针对CVE-2026-23918 Apache http2 RCE的检测规则 - 致谢:stringa.ai, isec.pl
发布时间: 2026-05-04
CVSSv3: 8.8 (高危)
类型: 远程代码执行 / 拒绝服务(双重释放内存损坏)
组件: 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 协议实现的一个双重释放内存损坏漏洞,仅影响 mod_http2 模块中 h2_mplx.c 的流清理路径。攻击者无需认证即可通过一个 TCP 连接和两个 HTTP/2 帧远程导致 Apache 工作进程崩溃(拒绝服务)。在基于 Debian 的系统及官方 Apache Docker 镜像的特定条件下,该双重释放漏洞可被利用实现完全远程代码执行。
拒绝服务利用已在野外得到确认。大规模互联网扫描针对 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) 是一种 **主机侧、访问后** 漏洞。攻击者需要在系统上已有存在感。检测主要位于系统调用层(auditd、Wazuh),同时使用 YARA 扫描磁盘上的 PoC 脚本。
CVE-2026-23918 是一种 **网络侧、访问前** 漏洞。利用载荷以 HTTP/2 协议帧的形式在应用代码运行之前通过线路到达。这显著改变了检测栈:
| 层面 | Copy Fail (LPE) | CVE-2026-23918 (RCE) |
|---|---|---|
| **主要检测** | Auditd 系统调用规则 | Suricata 网络规则 |
| **WAF (ModSecurity)** | 受限 — 无法看到利用 | 相关 — 异常检测 + 利用后检测 |
| **Auditd** | 核心检测 | 结果检测(崩溃、利用后行为) |
| **YARA** | 扫描 PoC 脚本 | 扫描 Web Shell(利用后产物) |
| **网络 IDS** | 不适用 | 第一层检测层 |
| **TLS 检查** | 不适用 | Suricata 全面覆盖所必需 |
经验法则:对于网络级 RCE,由外向内(网络 → WAF → 主机)排查。对于本地权限提升,由主机向外排查。
---
## 检测限制
> **在部署任何规则前请阅读此部分。**
**1. TLS 会终止 HTTP/2 可见性。**
大多数生产环境的 Apache 部署使用 HTTPS。如果没有配置 TLS 解密,Suricata 无法检查加密的 HTTP/2 帧内容。如果你的 Suricata 部署无法获取 TLS 会话密钥或解密镜像,则以下网络级规则只能捕获:
- 明文 HTTP/2 (h2c) — 生产中不常见,但在内部环境中存在
- TCP 连接行为的网络特征(连接数、TCP 层的 RST 模式)
对于 HTTPS 部署,请通过 `tls-decrypt` 设置和会话密钥日志启用 Suricata 的 TLS 解密,或者依赖 WAF(ModSecurity/Coraza)和基于主机(auditd/Wazuh)的检测层。
**2. ModSecurity 无法阻止利用触发。**
双重释放发生在 HTTP/2 帧解析器内部,此时完整的 HTTP 请求尚未组装并传递给 ModSecurity。WAF 仅在帧解析完成后才能看到请求——此时可能已造成损害。本工具包中的 ModSecurity 用于异常检测、速率限制和利用后检测,而不是作为触发的阻断层。
**3. MPM prefork 不受影响。**
如果你的 Apache 部署使用 `mpm_prefork_module`(单线程),则此漏洞不适用。该错误仅出现在多线程 MPM(`mpm_event_module` 或 `mpm_worker_module`)中。在部署可能导致 prefork 服务器产生误报的规则前,请使用 `apachectl -V | grep MPM` 进行检查。
**4. RCE 需要 mmap 分配器。**
RCE 路径(而非 DoS 路径)需要 APR 的 mmap 分配器,这是 Debian 衍生发行版和官方 Apache Docker 镜像的默认配置。使用 jemalloc 或系统 malloc 的 RHEL/CentOS 部署降低了对 RCE 的风险,但仍完全容易受到 DoS 攻击。
**5. 尚无稳定的利用后 IoC。**
截至本文撰写时,尚无厂商发布针对利用后活动的 IoC。针对利用后行为的 YARA 规则和 auditd 规则基于通用的 Web Shell 和权限提升模式——它们能够捕获常见结果,但无法应对复杂、定制的载荷。
---
## 即时缓解措施
按优先级顺序应用。每项虽比前一项更具破坏性,但每项也更为完整。```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/ # 应返回 "1.1",而非 "2" apachectl -M | grep http2 # 应无输出
保存为 cve-2026-23918.rules,并在 suricata.yaml 中引用。
前提条件:
- Suricata 6.0 及以上版本,以支持
http2.frametype/http2.errorcode关键字(推荐 Suricata 7.x)- 在
suricata.yaml中启用app-layer.protocols.http2.enabled: yes- 配置了 TLS 解密以实现 HTTPS 覆盖(参见上文“检测局限性”)
$HTTP_SERVERS变量已设置,包含你的 Apache 主机- 以下 SID 为示例——请根据你本地的 SID 策略进行调整```
alert http2 $EXTERNAL_NET any -> $HTTP_SERVERS any
(msg:"CVE-2026-23918 Apache mod_http2 Double-Free - RST_STREAM with non-zero error code";
flow:established,to_server;
http2.frametype:3;
http2.errorcode:!0;
classtype:web-application-attack;
reference:cve,2026-23918;
sid:9926231801; rev:1;)