Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
poc-h2-CVE-2026-71554 — CVE-2026-71554용 PoC - h2 중복 Host 헤더 요청 스머글링 프리미티브 (4.4.1에서 수정됨) | Kitploit
도구/GitHubGitHub/sunandm/poc-h2-cve-2026-71554
Vulnerability AnalysisExploitationWeb Application ExploitationAPI Security TestingWeb SecurityAPI SecurityAdversarial Attack
GitHubsunandm/poc-h2-cve-2026-71554

poc-h2-CVE-2026-71554

CVE-2026-71554용 PoC - h2 중복 Host 헤더 요청 스머글링 프리미티브 (4.4.1에서 수정됨)

저장소 보기
1282개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-71554 - h2 중복 Host 헤더 요청 스머글링 프리미티브

이것은 제 첫 번째 CVE이며, 이 발견을 문서화하고 다른 사람들이 이를 이해하고 재현할 수 있도록 돕기 위해 이 PoC를 공개했습니다.

CVE: CVE-2026-71554 GHSA: GHSA-6hr6-w5qg-qmwg 영향받는 버전: h2 <= 4.4.0 수정된 버전: h2 4.4.1 심각도: 중간 (CWE-444, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L = 5.3) NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-71554


발견한 내용

h2의 헤더 검증 로직을 검토하던 중, src/h2/utilities.py의 _validate_host_authority_header()가 Host와 :authority가 일치하는지 확인하지만, 확인하는 것은 마지막 Host 헤더뿐이라는 점을 발견했습니다. Host 헤더를 두 개 보내면 h2는 일치 검사에 두 번째 것을 사용하고, 두 헤더 모두 애플리케이션으로 아무 문제 없이 전달합니다.

흥미롭게도 h2 4.4.0은 이미 중복된 Content-Length 헤더를 ProtocolError로 거부합니다. 동일한 수정이 Host에는 적용되지 않았습니다. 소스에는 이 정확한 공백을 인정하는 TODO 주석까지 있었습니다:

# TODO: We should also guard against receiving duplicate Host headers,
#       and against sending duplicate headers.

근본 원인

src/h2/utilities.py의 _validate_host_authority_header()는 마지막 값이 이기는(last-wins) 루프를 사용하여 마지막으로 확인된 Host 값을 기록하고 다음만 검사합니다:

  1. :authority 또는 Host 중 적어도 하나가 존재하는지
  2. 둘 다 존재할 때, 서로 일치하는지

Host 헤더의 개수에 대한 검사는 없습니다. 각 Host 헤더는 몇 개가 존재하든 관계없이 다운스트림 애플리케이션으로 전달됩니다.


공격 시나리오

사례 1 - 두 개의 Host 헤더, :authority 없음

클라이언트가 전송:

:method: GET
:path: /
:scheme: https
host: good.internal
host: evil.attacker

h2는 둘 다 수락합니다. 애플리케이션은 두 Host 헤더를 모두 수신합니다.

HTTP/1.1 다운그레이드 시 생성되는 요청:

GET / HTTP/1.1
host: good.internal
host: evil.attacker

RFC 9112 s3.2는 서버가 Host 헤더를 두 개 이상 포함한 모든 HTTP/1.1 요청에 400으로 응답하도록 요구합니다. 백엔드마다 동작이 다릅니다:

nginx          — 400으로 거부
Python stdlib  — 수락, 조회 시 첫 번째 Host 반환
Werkzeug       — 수락, 조회 시 첫 번째 Host 반환

사례 2 - 은밀한 스머글링 (:authority 우회)

클라이언트가 전송:

:method: GET
:path: /
:scheme: https
:authority: good.internal
host: evil.attacker     <- 인덱스 0, 첫 번째 Host (오리진이 보는 값)
host: good.internal     <- 인덱스 1, 마지막 Host (h2 검증기가 사용하는 값)

h2 검증: 마지막 Host (good.internal) == :authority (good.internal) - 통과.

애플리케이션은 두 Host 헤더를 모두 수신합니다. HTTP/1.1 다운그레이드 시 생성되는 요청:

GET / HTTP/1.1
host: evil.attacker
host: good.internal

단일 키 조회 시 첫 번째 Host를 반환하는 백엔드는 요청을 evil.attacker로 라우팅하는 반면, h2는 good.internal을 검증했다고 믿습니다. h2가 검증한 것과 오리진이 처리하는 것 사이에 완전한 라우팅 디싱크가 발생합니다.


대조군 - 단일 불일치 Host는 올바르게 거부됨

:method: GET
:path: /
:scheme: https
:authority: good.internal
host: evil.attacker

h2는 ProtocolError를 발생시킵니다. 이는 공백이 중복 Host 헤더에 특정된 것임을 확인해 줍니다.


영향을 받을 수 있는 대상

영향은 배포 아키텍처에 따라 조건부입니다:

  • 영향받음: 클라이언트로부터 HTTP/2를 수락하고 백엔드로 전달할 때 HTTP/1.1로 다운그레이드하는 리버스 프록시 또는 API 게이트웨이 중, 백엔드가 라우팅 결정에 첫 번째 Host 헤더를 사용하는 경우
  • 영향받는 백엔드 (실증 테스트됨): Python stdlib http.client, Werkzeug Headers - 둘 다 중복 Host를 수락하고 첫 번째 값을 반환
  • 영향받지 않는 백엔드: nginx - 중복 Host에 대해 400으로 거부
  • 영향받지 않는 배포: HTTP/1.1 다운그레이드가 없는 종단 간 HTTP/2

재현 단계

요구 사항

pip install h2==4.4.0

실행

python3 poc_h2_duplicate_host.py

취약한 4.4.0에서의 예상 출력

CASE 1 - 두 개의 Host 헤더, :authority 없음 (둘 다 전달됨)
h2가 전달한 Host 헤더: ['good.internal', 'evil.attacker']
결과 HTTP/1.1 요청:
GET / HTTP/1.1
host: good.internal
host: evil.attacker

CASE 2 - STEALTH: :authority가 마지막 Host와 일치, 첫 번째 Host가 밀반입됨
:authority=['good.internal']  Host(s)=['evil.attacker', 'good.internal']
h2 불일치 검사 통과 (:authority == 마지막 Host).
결과 HTTP/1.1 요청:
GET / HTTP/1.1
host: evil.attacker
host: good.internal

CONTROL - :authority와 불일치하는 단일 Host (올바르게 거부됨)
[control] SENDER rejected: ProtocolError(...)

4.4.1에서 수정 사항 검증

pip install h2==4.4.1
python3 poc_h2_duplicate_host.py

세 가지 경우 모두 ProtocolError를 발생시킵니다. 헤더가 전달되지 않습니다.


수정 사항

_validate_host_authority_header()의 기존 루프에 카운터 하나를 추가했습니다:

host_header_count = 0
for header in headers:
    if header[0] == b"host":
        host_header_count += 1
    yield header

if host_header_count > 1:
    raise ProtocolError("Request header block has multiple Host headers.")

커밋: https://github.com/python-hyper/h2/commit/292a40829feefda98c8509dcdbbb4a57af9bd6a6


크레딧

Sunand Mohan (https://github.com/SunandM)이 발견하고 보고했습니다.

도구 다운로드