Exploit Syntax Injection to Extract Data

Exploit 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

Identifying field names

Because MongoDB handles semi-structured data that doesn't require a fixed schema, you may need to identify valid fields in the collection before you can extract data using JavaScript injection.

For example, to identify whether the MongoDB database contains a password field, you could submit the following payload:

https://insecure-website.com/user/lookup?username=admin'+%26%26+this.password!%3d'

Send the payload again for an existing field and for a field that doesn't exist. In this example, you know that the username field exists, so you could send the following payloads:

admin' && this.username!=' 
admin' && this.foo!='

If the password field exists, you'd expect the response to be identical to the response for the existing field (username), but different to the response for the field that doesn't exist (foo).

If you want to test different field names, you could perform a dictionary attack, by using a wordlist to cycle through different potential field names.

Lab

The user lookup functionality for this lab is powered by a MongoDB NoSQL database. It is vulnerable to NoSQL injection.

To solve the lab, extract the password for the administrator user, then log in to their account.

You can log in to your own account using the following credentials: wiener:peter.

The password only uses lowercase letters.

Steps

  • Open Burp suite

  • Login to the account as wiener:peter

  • Send the post request to repeater

  • In the repeater tab change the username to administrator

  • Add the following payload after the username

administrator'+%26%26+this.password[2].match(/[k]/)||+'a'%3d%3d'b
  • Now send the request to intruder

  • In the intruder positions tab select the .match value [k], and add $$ to brute force the value

  • In the payload tab select simple list and paste the alphabet in small letters in the Pyload Settings section

  • Now Start the attack

  • Repeat the steps for each password[] value. Change the password index manually and review the response to get the password

  • After the completion the password should be look like this "hvmxmcxj"

  • $$$

Last updated