4.3.5 NoSQL
NoSQL injection
NoSQL injection is a vulnerability where an attacker is able to interfere with the queries that an application makes to a NoSQL database. NoSQL injection may enable an attacker to:
Bypass authentication or protection mechanisms.
Extract or edit data.
Cause a denial of service.
Execute code on the server.
NoSQL databases store and retrieve data in a format other than traditional SQL relational tables. They use a wide range of query languages instead of a universal standard like SQL, and have fewer relational constraints.
MongoDB NoSQL Injection
Detecting operator injection in MongoDB
Consider a vulnerable application that accepts a username and password in the body of a POST
request:
{"username":"wiener","password":"peter"}
Test each input with a range of operators. For example, to test whether the username input processes the query operator, you could try the following injection:
{"username":{"$ne":"invalid"},"password":"peter"}
If the $ne
operator is applied, this queries all users where the username is not equal to invalid
.
If both the username and password inputs process the operator, it may be possible to bypass authentication using the following payload:
{"username":{"$ne":"invalid"},"password":{"$ne":"invalid"}}
This query returns all login credentials where both the username and password are not equal to invalid
. As a result, you're logged into the application as the first user in the collection.
To target an account, you can construct a payload that includes a known username, or a username that you've guessed. For example:
{"username":{"$in":["admin","administrator","superadmin"]},"password":{"$ne":""}}
Exploiting syntax injection to extract data
In many NoSQL databases, some query operators or functions can run limited JavaScript code, such as MongoDB's $where
operator and mapReduce()
function. This means that, if a vulnerable application uses these operators or functions, the database may evaluate the JavaScript as part of the query. You may therefore be able to use JavaScript functions to extract data from the database.
Exfiltrating data in MongoDB
Consider a vulnerable application that allows users to look up other registered usernames and displays their role. This triggers a request to the URL:
https://insecure-website.com/user/lookup?username=admin
This results in the following NoSQL query of the users
collection:
{"$where":"this.username == 'admin'"}
As the query uses the $where
operator, you can attempt to inject JavaScript functions into this query so that it returns sensitive data. For example, you could send the following payload:
admin' && this.password[0] == 'a' || 'a'=='b
This returns the first character of the user's password string, enabling you to extract the password character by character.
You could also use the JavaScript match()
function to extract information. For example, the following payload enables you to identify whether the password contains digits:
admin' && this.password.match(/\d/) || 'a'=='b
Injecting operators in MongoDB
Consider a vulnerable application that accepts username and password in the body of a POST
request:
{"username":"wiener","password":"peter"}
To test whether you can inject operators, you could try adding the $where
operator as an additional parameter, then send one request where the condition evaluates to false, and another that evaluates to true. For example:
{"username":"wiener","password":"peter", "$where":"0"}{"username":"wiener","password":"peter", "$where":"1"}
Preventing NoSQL injection
The appropriate way to prevent NoSQL injection attacks depends on the specific NoSQL technology in use. As such, we recommend reading the security documentation for your NoSQL database of choice. That said, the following broad guidelines will also help:
Sanitize and validate user input, using an allowlist of accepted characters.
Insert user input using parameterized queries instead of concatenating user input directly into the query.
To prevent operator injection, apply an allowlist of accepted keys.