### MongoDB 注入方式

MongoDB 注入的原理

MongoDB 注入的核心原理是利用MongoDB 查询中的特殊操作符或特性，来绕过应用程序的认证或执行未授权的数据库操作。当应用程序将用户输入直接拼接或用于构建查询对象时，攻击者可以通过构造恶意的输入来改变查询的逻辑

例如，一个典型的登录查询可能看起来像这样：

    db.collection.findOne({
        username: request.body.username,
        password: request.body.password
    });

如果攻击者在`username`字段输入`{"$ne": null}`，在`password`字段输入`{"$ne": null}`，那么查询就会变成：

    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` 操作符可以用来查询某个字段是否在给定的数组中。攻击者可以利用这个特性进行注入

例如，一个查询可能用来检查用户的角色：

    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 支持正则表达式查询，这使得攻击者可以利用它来进行更复杂的攻击，比如盲注

假设存在一个查询，用来查找匹配用户名的文档：

    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 代码。这在功能上非常强大，但同时也是一个巨大的安全隐患，因为攻击者可以直接执行任意代码，包括操作系统命令