
CVE-2026-23918 Apache http2 RCE 탐지 규칙 - 크레딧: stringa.ai, isec.pl
게시일: 2026-05-04
CVSSv3: 8.8 (높음)
유형: 원격 코드 실행 / 서비스 거부 (Double-Free 메모리 손상)
구성 요소: Apache HTTP Server mod_http2 (h2_mplx.c 스트림 정리 경로)
영향: HTTP/2가 활성화되고 멀티스레드 MPM을 사용하는 Apache HTTP Server 2.4.66
참고:
CVE-2026-23918은 Apache HTTP Server 2.4.66의 HTTP/2 프로토콜 구현에서 발생하는 double-free 메모리 손상 취약점으로, mod_http2 모듈의 h2_mplx.c에 있는 스트림 정리 경로에만 영향을 미칩니다. 인증되지 않은 원격 공격자가 단일 TCP 연결과 두 개의 HTTP/2 프레임만으로 Apache 작업자 프로세스를 충돌(서비스 거부)시킬 수 있습니다. Debian 계열 시스템 및 공식 Apache Docker 이미지에 존재하는 조건에서는 double-free가 완전한 원격 코드 실행(RCE)으로 이어질 수 있습니다.
DoS 악용은 실제 환경에서 확인되었습니다. HTTP/2 엔드포인트를 대상으로 하는 대규모 인터넷 스캔이 관찰되었습니다. RCE 악용은 통제된 환경에서 가능한 것으로 입증되었지만, 현재 시점에서 RCE를 위한 광범위한 공개 악용 증거는 없습니다.
MPM prefork는 영향을 받지 않습니다. 취약점이 발생하려면 멀티스레드 MPM 구성(worker, event 또는 유사)이 필요합니다. CVE-2026-23918은 Apache HTTP Server 버전 2.4.66에만 영향을 미칩니다.
Attacker opens HTTP/2 connection to Apache 2.4.66 (mod_http2 loaded, multi-threaded MPM) └─ Sends HTTP/2 HEADERS frame on stream N (opens the stream) └─ Immediately sends RST_STREAM on stream N (non-zero error code) └─ Sent BEFORE the multiplexer has registered the stream
Two nghttp2 callbacks fire in sequence: ├─ on_frame_recv_cb (RST received) → calls h2_mplx_c1_client_rst → m_stream_cleanup └─ on_stream_close_cb (stream closed) → calls h2_mplx_c1_client_rst → m_stream_cleanup
Result: same h2_stream pointer pushed onto spurge[] cleanup array TWICE
c1_purge_streams() iterates spurge[] and calls h2_stream_destroy() on each entry: ├─ First call: valid — frees the stream └─ Second call: DOUBLE-FREE — operates on already-freed memory → heap corruption
DoS path (trivial, in the wild): └─ Heap corruption → SIGABRT in worker process → worker dies → service disruption
RCE path (requires mmap allocator — default on Debian/Ubuntu and official Docker): └─ Attacker places fake h2_stream struct at freed virtual address via mmap reuse └─ Points pool cleanup function pointer to system() └─ Uses Apache scoreboard shared memory (fixed address, ASLR-resistant) as payload container └─ c1_purge_streams() executes system() with attacker-controlled argument → RCE
> **핵심 비대칭성:** DoS 경로는 힙 조작 기술이 필요하지 않으며 실제로 적극적으로 악용되고 있습니다. RCE 경로는 기술적으로 까다롭지만 실험실 조건에서 입증되었으며, 점수판이 ASLR에 저항하는 고정 주소를 가지고 있기 때문에 가까운 미래에 거의 확실히 무기화될 것입니다.
---
## 탐지 아키텍처
> 이 섹션은 여기의 탐지 도구가 일반적인 로컬 권한 상승 패키지와 크게 다른 이유를 설명합니다.
Copy Fail (CVE-2026-31431)은 **호스트 측, 접근 후** 취약점이었습니다. 공격자는 시스템에 기존에 존재해야 했습니다. 탐지는 주로 syscall 계층(auditd, Wazuh)에서 이루어졌으며, YARA를 사용하여 디스크에 있는 PoC 스크립트를 스캔했습니다.
CVE-2026-23918은 **네트워크 측, 접근 전** 취약점입니다. 익스플로잇은 애플리케이션 코드가 실행되기 전에 HTTP/2 프로토콜 프레임 형태로 네트워크를 통해 전달됩니다. 이로 인해 탐지 스택이 크게 변경됩니다:
| 계층 | Copy Fail (LPE) | CVE-2026-23918 (RCE) |
|---|---|---|
| **기본 탐지** | auditd syscall 규칙 | Suricata 네트워크 규칙 |
| **WAF (ModSecurity)** | 제한적 — 익스플로잇을 볼 수 없음 | 관련 있음 — 이상 징후 + 사후 익스플로잇 |
| **Auditd** | 핵심 탐지 | 결과 탐지(충돌, 사후 익스플로잇) |
| **YARA** | PoC 스크립트 스캔 | 웹 셸 스캔(사후 익스플로잇 아티팩트) |
| **네트워크 IDS** | 해당 없음 | 일급 탐지 계층 |
| **TLS 검사** | 해당 없음 | 전체 Suricata 커버리지에 필요 |
경험상: 네트워크 수준 RCE의 경우 외부에서 내부로(네트워크 → WAF → 호스트) 작업합니다. 로컬 권한 상승의 경우 호스트에서 외부로 작업합니다.
---
## 탐지 한계
> **규칙을 배포하기 전에 이 내용을 읽으십시오.**
**1. TLS는 HTTP/2 가시성을 종료합니다.**
대부분의 프로덕션 Apache 배포는 HTTPS를 제공합니다. Suricata는 TLS 복호화가 구성되지 않은 경우 암호화된 HTTP/2 프레임의 내용을 검사할 수 없습니다. Suricata 배포에 TLS 세션 키나 복호화 미러에 접근할 수 없는 경우, 아래 네트워크 수준 규칙은 다음만 감지합니다:
- 일반 텍스트 HTTP/2 (h2c) — 프로덕션에서는 드물지만 내부 환경에 존재
- TCP 연결 동작의 네트워크 시그니처(연결 수, TCP 계층의 RST 패턴)
HTTPS 배포의 경우, Suricata의 TLS 복호화를 `tls-decrypt` 설정 및 세션 키 로깅을 통해 활성화하거나, 대신 WAF(ModSecurity/Coraza) 및 호스트 기반(auditd/Wazuh) 계층에 의존하십시오.
**2. ModSecurity는 익스플로잇 트리거를 차단할 수 없습니다.**
이중 해제(double-free)는 완전한 HTTP 요청이 조립되어 ModSecurity에 전달되기 전에 HTTP/2 프레임 파서 내부에서 발생합니다. WAF는 프레임 구문 분석이 완료된 후에만 요청을 확인합니다. 이때 이미 피해가 발생했을 수 있습니다. 이 패키지의 ModSecurity는 이상 징후 탐지, 속도 제한 및 사후 익스플로잇 탐지에 사용되며, 트리거 차단용이 아닙니다.
**3. MPM prefork는 영향을 받지 않습니다.**
Apache 배포가 `mpm_prefork_module`(단일 스레드)을 사용하는 경우 이 취약점은 적용되지 않습니다. 버그는 다중 스레드 MPM(`mpm_event_module` 또는 `mpm_worker_module`)에서만 나타납니다. 규칙을 배포하기 전에 `apachectl -V | grep MPM`으로 확인하여 prefork 서버에서 오탐을 방지하십시오.
**4. RCE는 mmap 할당자가 필요합니다.**
RCE 경로(DoS 경로가 아님)는 APR의 mmap 할당자가 필요하며, 이는 Debian 계열 배포판 및 공식 Apache Docker 이미지의 기본값입니다. jemalloc 또는 system malloc을 사용하는 RHEL/CentOS 기반 배포판은 RCE 위험이 감소하지만, DoS에는 여전히 완전히 취약합니다.
**5. 안정적인 사후 익스플로잇 IoC는 아직 없습니다.**
현재까지 사후 익스플로잇 활동에 대해 공급업체가 발표한 IoC는 없습니다. 사후 익스플로잇 동작을 대상으로 하는 YARA 규칙과 auditd 규칙은 일반적인 웹 셸 및 권한 상승 패턴을 기반으로 합니다. 이는 일반적인 결과는 잡아내지만 정교한 맞춤형 페이로드는 잡아내지 못합니다.
---
## 즉시 완화
선호도 순서대로 적용하십시오. 각각은 이전보다 더 파괴적이지만, 더 완전합니다.```bash
# Option 1 (Preferred): Upgrade to 2.4.67
# See Patching & Remediation section below
# Option 2: Disable HTTP/2 in Apache config (no reboot required, restart required)
# In httpd.conf or relevant VirtualHost / site config:
# Remove or comment out: Protocols h2 h2c http/1.1
# Replace with: Protocols http/1.1
# Then:
apachectl configtest && sudo systemctl restart apache2
# Option 3: Switch to MPM prefork (eliminates vulnerability entirely — more disruptive)
sudo a2dismod mpm_event mpm_worker
sudo a2enmod mpm_prefork
apachectl configtest && sudo systemctl restart apache2
# Option 4: Reverse proxy HTTP/2 termination
# If nginx, HAProxy, or a CDN is in front of Apache and terminates HTTP/2,
# Apache only receives HTTP/1.1 — confirm your proxy config explicitly:
# nginx: proxy_http_version 1.1; (already the default for upstream connections)
# HAProxy: use-server-close + http/1.1 on backend bind
# Verify with: curl -v --http2 https://your-origin-directly
완화 조치를 확인하세요: HTTP/2를 비활성화한 후 다음으로 확인합니다:
curl -s -o /dev/null -w "%{http_version}" --http2 http://localhost/ # Should return "1.1", not "2" apachectl -M | grep http2 # Should produce no output
cve-2026-23918.rules로 저장하고 suricata.yaml에서 참조하십시오.