Lab: Exploiting NoSQL operator injection to extract unknown fields

PRACTITIONER

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

To solve the lab, log in as carlos.

Tip

To solve the lab, you'll first need to exfiltrate the value of the password reset token for the user carlos.

Solution

  1. In Burp's browser, attempt to log in to the application with username carlos and password invalid. Notice that you receive an Invalid username or password error message.

  2. In Burp, go to Proxy > HTTP history. Right-click the POST /login request and select Send to Repeater.

  3. In Repeater, change the value of the password parameter from "invalid" to {"$ne":"invalid"}, then send the request. Notice that you now receive an Account locked error message. You can't access Carlos's account, but this response indicates that the $ne operator has been accepted and the application is vulnerable.

  4. In Burp's browser, attempt to reset the password for the carlos account. When you submit the carlos username, observe that the reset mechanism involves email verification, so you can't reset the account yourself.

  5. In Repeater, use the POST /login request to test whether the application is vulnerable to JavaScript injection:

    1. Add "$where": "0" as an additional parameter in the JSON data as follows: {"username":"carlos","password":{"$ne":"invalid"}, "$where": "0"}
    2. Send the request. Notice that you receive an Invalid username or password error message.
    3. Change "$where": "0" to "$where": "1", then resend the request. Notice that you receive an Account locked error message. This indicates that the JavaScript in the $where clause is being evaluated.
  6. Right-click the request and select Send to Intruder.

  7. In Intruder, construct an attack to identify all the fields on the user object:

    1. Update the $where parameter as follows: "$where":"Object.keys(this)[1].match('^.{}.*')"
    2. Add two payload positions. The first identifies the character position number, and the second identifies the character itself: "$where":"Object.keys(this)[1].match('^.{§§}§§.*')"
    3. Select Cluster bomb attack from the attack type drop-down menu.
    4. In the Payloads side panel, select position 1 from the Payload position drop-down list, then set the Payload type to Numbers. Set the number range, for example from 0 to 20.
    5. Select position 2 from the Payload position drop-down list and make sure the Payload type is set to Simple list. Add all numbers, lower-case letters and upper-case letters as payloads. If you're using Burp Suite Professional, you can use the built-in word lists a-z, A-Z, and 0-9.
    6. Click Start attack.
    7. Sort the attack results by Payload 1, then Length, to identify responses with an Account locked message instead of the Invalid username or password message. Notice that the characters in the Payload 2 column spell out the name of the parameter: username.
    8. Repeat the above steps to identify further JSON parameters. You can do this by incrementing the index of the keys array with each attempt, for example: "$where":"Object.keys(this)[2].match('^.{}.*')"

      Notice that one of the JSON parameters is for a password reset token.

  8. Test the identified password reset field name as a query parameter on different endpoints:

    1. In Proxy > HTTP history, identify the GET /forgot-password request as a potentially interesting endpoint, as it relates to the password reset functionality. Right-click the request and select Send to Repeater.
    2. In Repeater, submit an invalid field in the URL: GET /forgot-password?foo=invalid. Notice that the response is identical to the original response.
    3. Submit the exfiltrated name of the password reset token field in the URL: GET /forgot-password?YOURTOKENNAME=invalid. Notice that you receive an Invalid token error message. This confirms that you have the correct token name and endpoint.
  9. In Intruder, use the POST /login request to construct an attack that extracts the value of Carlos's password reset token:

    1. Keep the settings from your previous attack, but update the $where parameter as follows: "$where":"this.YOURTOKENNAME.match('^.{§§}§§.*')"

      Make sure that you replace YOURTOKENNAME with the password reset token name that you exfiltrated in the previous step.

    2. Click Start attack.
    3. Sort the attack results by Payload 1, then Length, to identify responses with an Account locked message instead of the Invalid username or password message. Note the letters from the Payload 2 column down.
  10. In Repeater, submit the value of the password reset token in the URL of the GET / forgot-password request: GET /forgot-password?YOURTOKENNAME=TOKENVALUE.
  11. Right-click the response and select Request in browser > Original session. Paste this into Burp's browser.
  12. Change Carlos's password, then log in as carlos to solve the lab.

Community solutions

Popo Hack