> For the complete documentation index, see [llms.txt](https://simon-6.gitbook.io/simoncyber/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://simon-6.gitbook.io/simoncyber/portswigger-web-academy/api-testing/lab-4.md).

# Lab 4

### Server-Side Parameter Pollution (SSPP)

#### Simple example

Website takes your search input and forwards it like:

```
GET /internal/api/users?name=wiener
```

You type `wiener&isAdmin=true` as your input. Now the internal request becomes:

```
GET /internal/api/users?name=wiener&isAdmin=true
```

You just injected a parameter into a request you were never supposed to control.

Basically, this type of exploit attacks a internal API lives on a private network/server. If you tried to visit that URL in your browser — **nothing**. It's not on the internet, so for this attack it acts as a proxy.&#x20;

<figure><img src="/files/tkwUynlAHzu0s0YERBac" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

It's essential that you URL-encode the `#` character. Otherwise the front-end application will interpret it as a fragment identifier and it won't be passed to the internal API.
{% endhint %}

To confirm whether the application is vulnerable to server-side parameter pollution, you could try to override the original parameter. Do this by injecting a second parameter with the same name.

For example, you could modify the query string to the following:

`GET /userSearch?name=peter%26name=carlos&back=/home`

This results in the following server-side request to the internal API:

`GET /users/search?name=peter&name=carlos&publicProfile=true`

* PHP parses the last parameter only. This would result in a user search for `carlos`.
* ASP.NET combines both parameters. This would result in a user search for `peter,carlos`, which might result in an `Invalid username` error message.
* Node.js / express parses the first parameter only. This would result in a user search for `peter`, giving an unchanged result.

### Solving It

<figure><img src="/files/48PTbVrpRO5R9CZSqXtk" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/gyRv8hBgRWIQf6s0OcmA" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/M9neQBvmJlAfsFelmtJz" alt=""><figcaption></figcaption></figure>

```js
HTTP/2 200 OK
Content-Type: application/javascript; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 2552

let forgotPwdReady = (callback) => {
    if (document.readyState !== "loading") callback();
    else document.addEventListener("DOMContentLoaded", callback);
}

function urlencodeFormData(fd){
    let s = '';
    function encode(s){ return encodeURIComponent(s).replace(/%20/g,'+'); }
    for(let pair of fd.entries()){
        if(typeof pair[1]=='string'){
            s += (s?'&':'') + encode(pair[0])+'='+encode(pair[1]);
        }
    }
    return s;
}

const validateInputsAndCreateMsg = () => {
    try {
        const forgotPasswordError = document.getElementById("forgot-password-error");
        forgotPasswordError.textContent = "";
        const forgotPasswordForm = document.getElementById("forgot-password-form");
        const usernameInput = document.getElementsByName("username").item(0);
        if (usernameInput && !usernameInput.checkValidity()) {
            usernameInput.reportValidity();
            return;
        }
        const formData = new FormData(forgotPasswordForm);
        const config = {
            method: "POST",
            headers: {
                "Content-Type": "x-www-form-urlencoded",
            },
            body: urlencodeFormData(formData)
        };
        fetch(window.location.pathname, config)
            .then(response => response.json())
            .then(jsonResponse => {
                if (!jsonResponse.hasOwnProperty("result"))
                {
                    forgotPasswordError.textContent = "Invalid username";
                }
                else
                {
                    forgotPasswordError.textContent = `Please check your email: "${jsonResponse.result}"`;
                    forgotPasswordForm.className = "";
                    forgotPasswordForm.style.display = "none";
                }
            })
            .catch(err => {
                forgotPasswordError.textContent = "Invalid username";
            });
    } catch (error) {
        console.error("Unexpected Error:", error);
    }
}

const displayMsg = (e) => {
    e.preventDefault();
    validateInputsAndCreateMsg(e);
};

forgotPwdReady(() => {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString);
    const resetToken = urlParams.get('reset-token');
    if (resetToken)
    {
        window.location.href = `/forgot-password?reset_token=${resetToken}`;
    }
    else
    {
        const forgotPasswordBtn = document.getElementById("forgot-password-btn");
        forgotPasswordBtn.addEventListener("click", displayMsg);
    }
});

```

Field is not specified here

<figure><img src="/files/qdKF270QOlq1nNOrO8tp" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/qgZVsnAcyqpIDkgSglof" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/M7WdKoCgp3jC2fMEQyow" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/K2ffXuM3bLaxpBHrAyId" alt=""><figcaption></figcaption></figure>

Ok so using Burpsuite Community will take a lot of time to really process all of those words - so the most common would be username and email&#x20;

<figure><img src="/files/x4TlSVdXRhQor1IJD2KQ" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/y8augre8NzUTlZzDI4Sz" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/7EiYLze1f5JLwn49bGCH" alt=""><figcaption></figcaption></figure>

What is the ? in the URL?

```
https://website.com/forgot-password?reset_token=123456789
        \_________/ \______________/ \___________/ \_____/
           domain        path          param name    value
                                  ^
                                  ? starts here
                                  
```

<figure><img src="/files/HDTuJOG6MNdc2UMbb1yf" alt=""><figcaption></figcaption></figure>

What is the field&#x20;

It's telling the internal API **which piece of data to return about the user.** Like:
