Files
Sec-Interview/_book/Chapter17/17-1.md
T
2025-11-08 21:00:06 +08:00

101 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
### MongoDB 注入方式
**MongoDB 注入的原理**
MongoDB 注入的核心原理是**利用MongoDB 查询中的特殊操作符或特性,来绕过应用程序的认证或执行未授权的数据库操作**。当应用程序将用户输入直接拼接或用于构建查询对象时,攻击者可以通过构造恶意的输入来改变查询的逻辑
例如,一个典型的登录查询可能看起来像这样:
```js
db.collection.findOne({
username: request.body.username,
password: request.body.password
});
```
如果攻击者在`username`字段输入`{"$ne": null}`,在`password`字段输入`{"$ne": null}`,那么查询就会变成:
```js
db.collection.findOne({
username: {"$ne": null},
password: {"$ne": null}
});
```
这个查询的含义是“查找 `username``password` 都不为空的任何文档”。这就可以**绕过密码验证**,成功以第一个匹配的用户身份登录
**常见的 MongoDB 注入方式**
**1. 逻辑操作符注入**
这是最常见、最基础的注入方式。攻击者利用 MongoDB 的**逻辑操作符**,如`$ne`(不等于)、`$gt`(大于)、`$lt`(小于)等来改变查询的逻辑
**认证绕过**
利用 `$ne` 操作符,可以构造登录认证绕过
- **用户名**`'{"$ne": null}'`
- **密码**`'{"$ne": null}'`
在某些情况下,也可以使用**布尔类型**来绕过:
- **用户名**`'admin'
- **密码**`'{"$gt": ""}'` (即密码大于空字符串的任何值)
这种方法简单且有效,因为它利用了数据库自身的查询特性
**2. 数组操作符注入**
MongoDB 的 **`$in` 操作符**可以用来查询某个字段是否在给定的数组中。攻击者可以利用这个特性进行注入
例如,一个查询可能用来检查用户的角色:
```js
db.users.findOne({
username: request.body.username,
role: "admin"
});
```
攻击者可以尝试在 `username` 字段输入一个数组,来绕过这个检查:
- **用户名**`'{"$in": ["admin", "guest"]}'`
- **密码**`'password'`
如果应用程序没有正确处理,这个查询可能被解析为: `db.users.findOne({ username: { "$in": ["admin", "guest"] }, role: "admin" });`
这可以用来**枚举**用户或**绕过**某些基于角色的访问控制
**3. 正则表达式注入**
MongoDB 支持**正则表达式查询**,这使得攻击者可以利用它来进行更复杂的攻击,比如**盲注**
假设存在一个查询,用来查找匹配用户名的文档:
```js
db.users.find({ username: request.body.username });
```
攻击者可以构造一个正则表达式,通过**布尔盲注**的方式来猜测数据
- **`$regex`**:用于匹配正则表达式
- **`$where`**:这个操作符允许在查询中使用 JavaScript 代码,是**最高危**的注入点之一
**盲注步骤**
1. **测试是否存在注入点**
- 输入`{"$where": "this.username == 'admin'"}`,如果返回管理员信息,则说明存在注入
2. **布尔盲注猜解数据**
- 构造一个查询来猜解管理员的密码长度
- `{"$where": "this.username == 'admin' && this.password.length > 5"}`
- 如果响应正常(例如返回管理员信息),则说明密码长度大于 5
- 否则,说明小于等于 5
3. **逐位猜解密码**
- 构造一个正则表达式来猜解密码的每一个字符
- `{"$where": "this.username == 'admin' && this.password.match(/^a/)"}`
- 这个查询会检查管理员密码是否以 `a` 开头
- 通过**二分法**或**逐位**猜测,攻击者可以逐步猜解出完整的密码
**4. `eval`注入**
在早期版本中,MongoDB 的 `db.eval()` 命令允许在服务器端执行 JavaScript 代码。这在功能上非常强大,但同时也是一个巨大的安全隐患,因为攻击者可以直接执行任意代码,包括**操作系统命令**