Lab: Bypassing flawed input filters for server-side prototype pollution

PRACTITIONER

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:

  1. Find a prototype pollution source that you can use to add arbitrary properties to the global Object.prototype.
  2. Identify a gadget property that you can use to escalate your privileges.
  3. Access the admin panel and delete the user carlos.

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

Note

When testing for server-side prototype pollution, it's possible to break application functionality or even bring down the server completely. If this happens to your lab, you can manually restart the server using the button provided in the lab banner. Remember that you're unlikely to have this option when testing real websites, so you should always use caution.

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.

Identify a prototype pollution source
  1. In Repeater, add a new property to the JSON with the name __proto__, containing an object with a json spaces property.

    "__proto__": { "json spaces":10 }
  2. Send the request.

  3. In the Response panel, switch to the Raw tab. Observe that the JSON indentation appears to be unaffected.

  4. Modify the request to try polluting the prototype via the constructor property instead:

    "constructor": { "prototype": { "json spaces":10 } }
  5. Resend the request.

  6. In the Response panel, go to the Raw tab. This time, notice that the JSON indentation has increased based on the value of your injected property. This strongly suggests that you have successfully polluted the prototype.

Identify a gadget
  1. Look at the additional properties in the response body.

  2. Notice the isAdmin property, which is currently set to false.

Craft an exploit
  1. Modify the request to try polluting the prototype with your own isAdmin property:

    "constructor": { "prototype": { "isAdmin":true } }
  2. Send the request. Notice that the isAdmin value in the response has been updated. This suggests that the object doesn't have its own isAdmin property, but has instead inherited it from the polluted prototype.

  3. In the browser, refresh the page and confirm that you now have a link to access the admin panel.

  4. Go to the admin panel and delete carlos to solve the lab.