29.7 Lab: Detecting server-side prototype pollution without polluted property reflection

This lab is built on Node.js and the Express framework. It is vulnerable to server-side prototype pollution because it unsafely merges user-controllable input into a server-side JavaScript object. To solve the lab, confirm the vulnerability by polluting Object.prototype in a way that triggers a noticeable but non-destructive change in the server’s behavior | Karthikeyan Nagaraj

Karthikeyan Nagaraj
3 min readJun 17, 2024

Description

This lab is built on Node.js and the Express framework. It is vulnerable to server-side prototype pollution because it unsafely merges user-controllable input into a server-side JavaScript object.

To solve the lab, confirm the vulnerability by polluting Object.prototype in a way that triggers a noticeable but non-destructive change in the server's behavior. As this lab is designed to help you practice non-destructive detection techniques, you don't need to progress to exploitation.

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

Solution

Study the address change feature

  1. Log in and visit your account page. Submit the form for updating your billing and delivery address.
  2. In Burp, go to the Proxy > HTTP history tab and find the POST /my-account/change-address request.
  3. Observe that when you submit the form, the data from the fields is sent to the server as JSON. Notice that the server responds with a JSON object that appears to represent your user. This has been updated to reflect your new address information.
  4. Send the request to Burp Repeater.
  5. In Repeater, add a new property to the JSON with the name __proto__, containing an object with an arbitrary property:
"__proto__": {
"foo":"bar"
}

6. Send the request. Observe that the object in the response does not reflect the injected property. However, this doesn’t necessarily mean that the application isn’t vulnerable to prototype pollution.

Identify a prototype pollution source

  1. Delete a comma from the end of one of the lines.
  2. Send the request. Observe that you receive an error response in which the body contains a JSON error object.
  3. Notice that although you received a 500 error response, the error object contains a status property with a value.
  4. In the request, make the following changes:
  • Fix the JSON syntax by reversing the changes that triggered the error.
  • Modify your injected property to try polluting the prototype with your own distinct status property. Remember that this must be between 400 and 599.
"__proto__": {
"status":400
}

5. Send the request and confirm that you receive the normal response containing your user object.

6. Intentionally break the JSON syntax again and reissue the request.

7. Notice that this time, although you triggered the same error, the status and statusCode properties in the JSON response match the arbitrary error code that you injected into Object.prototype. This strongly suggests that you have successfully polluted the prototype and the lab is solved.

--

--

Karthikeyan Nagaraj

Security Researcher | Bug Hunter | Web Pentester | CTF Player | TryHackme Top 1% | AI Researcher | Blockchain Developer