no sql
https://portswigger.net/bappstore/db57ecbe2cb7446292a94aa6181c9278
NoSQL injection detection
Application Context
Shopping application displays products by category.
Example URL:
https://insecure-website.com/product/lookup?category=fizzy
Backend MongoDB query:
this.category == 'fizzy'
Testing for Vulnerability
Fuzz Testing
Submit a fuzz string in the
category
parameter to test input handling.Example MongoDB fuzz string:
'"
{ ;$Foo} $Foo \xYZ`
Constructing the Attack URL
URL-encoded fuzz string:
Detection Indicator: Change in response suggests improper input filtering or sanitization.
Important Considerations
Context Adaptation
NoSQL injection vulnerabilities vary by context; adjust fuzz strings accordingly.
Example: Injection may need to be via URL or JSON property.
JSON payload example:
'\"
{\r;$Foo}\n$Foo \xYZ\u0000`
Determining Processed Characters
Character Injection
Inject individual characters (e.g.,
'
) to identify syntax handling.Example Injection:
'
resulting inthis.category == '''
Syntax Error Confirmation
Submit a valid escaped string:
this.category == '\''
Detection Indicator: Absence of syntax error may indicate vulnerability.
Confirming Conditional Behavior
Boolean Condition Manipulation
Send requests with false and true conditions:
False condition:
fizzy'&&0&&'x
True condition:
fizzy'&&1&&'x
Detection Indicator: Different application behaviors suggest query logic can be influenced.
Overriding Existing Conditions
Injecting Always-True Conditions
Example payload:
'||1||'
Attack URL:
Modified MongoDB query:
Outcome: Returns all items, including hidden or unknown categories.
Operators injection
NoSQL databases often use query operators, which provide ways to specify conditions that data must meet to be included in the query result. Examples of MongoDB query operators include:
$where
- Matches documents that satisfy a JavaScript expression.$ne
- Matches all values that are not equal to a specified value.{"username":{"$ne":"invalid"},"password":{"$ne":"invalid"}}
$in
- Matches all of the values specified in an array.$regex
- Selects documents where values match a specified regular expression.{"$regex":"admin.*"}
You may be able to inject query operators to manipulate NoSQL queries. To do this, systematically submit different operators into a range of user inputs, then review the responses for error messages or other changes.
Submitting query operators
In JSON messages, you can insert query operators as nested objects. For example, {"username":"wiener"}
becomes {"username":{"$ne":"invalid"}}
.
For URL-based inputs, you can insert query operators via URL parameters. For example, username=wiener
becomes username[$ne]=invalid
. If this doesn't work, you can try the following:
Convert the request method from
GET
toPOST
.Change the
Content-Type
header toapplication/json
.Add JSON to the message body.
Inject query operators in the JSON.
Exfiltrating data in Mongo
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
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"}
If there is a difference between the responses, this may indicate that the JavaScript expression in the $where
clause is being evaluated.
Exfiltrating field names
If you have injected an operator that enables you to run JavaScript, you may be able to use the keys()
method to extract the name of data fields. For example, you could submit the following payload:
Checking if object starts with 'a'
"$where":"Object.keys(this)[0].match('^.{0}a.*')"
This inspects the first data field in the user object and returns the first character of the field name. This enables you to extract the field name character by character.
Exfiltrating unknown data
Alternatively, you may be able to extract data using operators that don't enable you to run JavaScript. For example, you may be able to use the $regex
operator to extract data character by character.
Consider a vulnerable application that accepts a username and password in the body of a POST
request. For example:
{"username":"myuser","password":"mypass"}
You could start by testing whether the $regex
operator is processed as follows:
{"username":"admin","password":{"$regex":"^.*"}}
If the response to this request is different to the one you receive when you submit an incorrect password, this indicates that the application may be vulnerable. You can use the $regex
operator to extract data character by character. For example, the following payload checks whether the password begins with an a
:
{"username":"admin","password":{"$regex":"^a*"}}
Time based injection
Sometimes triggering a database error doesn't cause a difference in the application's response. In this situation, you may still be able to detect and exploit the vulnerability by using JavaScript injection to trigger a conditional time delay.
To conduct timing-based NoSQL injection:
Load the page several times to determine a baseline loading time.
Insert a timing based payload into the input. A timing based payload causes an intentional delay in the response when executed. For example,
{"$where": "sleep(5000)"}
causes an intentional delay of 5000 ms on successful injection.Identify whether the response loads more slowly. This indicates a successful injection.
The following timing based payloads will trigger a time delay if the password beings with the letter a
:
admin'+function(x){var waitTill = new Date(new Date().getTime() + 5000);while((x.password[0]==="a") && waitTill > new Date()){};}(this)+'
admin'+function(x){if(x.password[0]==="a"){sleep(5000)};}(this)+'
Last updated