Exploiting server side parameter pollution in a REST URL

Description

To solve the lab, log in as the administrator and delete carlos.

Approach

After accessing the lab, I enabled the FoxyProxy extension to proxy all my requests through Burp Suite. Two requests got my attention: one fetching a JavaScript file and the other a POST request to /forgot-password.

Starting with the GET /static/js/forgotPassword.js, there is an interesting part in the JavaScript script:

forgotPwdReady(() => {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString);
    const resetToken = urlParams.get('reset-token');
    if (resetToken)
    {
        window.location.href = `/forgot-password?passwordResetToken=${resetToken}`;
    }

This part is responsible for getting the value of passwordResetToken and verifying it. If it exists, it redirects with a GET request to /forgot-password with that passwordResetToken.

From this information, I can build an attack path to get the administrator's passwordResetToken, reset their password, log in as them, and delete the user Carlos.

I started working on how to get the passwordResetToken of the administrator. I went to the POST /forgot-password request and sent it to the repeater in Burp Suite to start working on it. I started by truncating the query string with the # character:

POST /forgot-password HTTP/2
Host: 0ada009f03b2058781472faf00550026.web-security-academy.net
Cookie: session=bb7bjqWIY6WBTvIkezybzDfZtiBq6cJP
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0
...

csrf=vBr4ih5Bd22dgiBe4Pkw1y2jCUgSgVDX&username=administrator%23

I got this error:

From this, I understood that the truncation worked, but it destroyed the query string, making it unable to reach the intended route. To clarify, imagine this is the normal route:

And I sent this:

The query string would become:

That's not a valid route, so the API triggers an error indicating an invalid route.

Going back to the analysis, I tried using path traversal with common API definition file names, starting with the one mentioned in the course: openapi.json. After some attempts, I got a response after passing this payload URL-encoded: administrator../../../../../../openapi.json#.

The response was:

From this, I could see the /api/internal/v1/users/{username}/field/{field} route, which helped me understand the invalid route error I was getting.

I decided to go for the reset token of the administrator:

I got this error:

I couldn't get it this way, but looking at the documentation, I saw it was using version 2 of the API. I confirmed this by reaching the token again from a full path where the version is equal to 2:

When sending this request:

I got the same error, confirming my theory:

Now, I tried using an older version, version 1, to see if it worked:

I got the reset token in the response:

Now, by sending this request:

In the response, I could see the password reset page for the administrator user. By simply right-clicking the response and clicking Show response in browser, I could copy and paste the URL into the browser and reset the administrator's password. Finally, I logged in as the administrator and deleted the user Carlos, which resulted in solving the lab.