EaEa0001/servu-cve-2026-28318-poc
GitHub: EaEa0001/servu-cve-2026-28318-poc
针对 SolarWinds Serv-U 预认证堆损坏崩溃漏洞(CVE-2026-28318)的防御性安全研究项目,提供根因分析与仅限 DoS 的 PoC。
Stars: 1 | Forks: 0
# CVE-2026-28318 — SolarWinds Serv-U "Content-Encoding: deflate" 预认证崩溃
## ⚠️ 免责声明 / 范围
- 这是针对**已修补且已公开披露**漏洞的**防御性安全研究**
(修复程序已于 **2026-06-04** 在 Serv-U 15.5.4 Hotfix 1 中发布;并被列入 **CISA KEV**)。
- 此处的 PoC 仅会导致您**拥有或获得明确授权测试**的 Serv-U 实例**崩溃**。
它是**仅限 DoS** 的 — 不包含或演示任何远程代码执行(参见*严重性*)。
- 使用它来**验证您自己系统上的补丁状态和检测**。不要将其指向您无法控制的系统。
您需自行负责遵守适用的法律。
## 受影响 / 已修复
| | |
|---|---|
| 产品 | SolarWinds Serv-U (FTP / MFT / 文件服务器) |
| 受影响版本 | 该分支中的 15.5.4 及更早版本(**未包含** Hotfix 1,分析基于内部版本 **15.5.4.108**) |
| 已修复版本 | **Serv-U 15.5.4 Hotfix 1**(发布于 2026-06-04) |
| 向量 | 未认证、网络(HTTP/HTTPS 管理/Web 端口) |
| 公开类别 | CWE-400 不受控的资源消耗 · DoS · CVSS 7.5 · CISA KEV |
| 实际类别 | **CWE-763 释放无效指针 / CWE-590 释放非堆内存** → 堆损坏 |
## 摘要 (TL;DR)
任何携带 `Content-Encoding: deflate` **且具有有效 deflate 主体**的 HTTP 请求都会导致服务崩溃。
处理程序会解压缩该主体,然后**释放指向*已压缩*主体的指针**并替换为解压缩后的缓冲区 — 但该指针是一个**位于 HTTP 接收缓冲区内部的指针**(它指向紧随 `\r\n\r\n` 之后的主体),**而不是堆分配基址**。
在非基址且未对齐的指针上调用 `free()` 会损坏堆,导致进程终止。
由于该漏洞出在*主体指针如何被释放* — 而不在于*生成了多少*数据 — 因此即使是解压后仅有几 KB 的约 25 字节压缩主体也能稳定触发崩溃。内存使用量不会增加;这并不是一个“zip/deflate 炸弹”。
## 根本原因
deflate 解码例程位于 `RhinoNET.dll`(Serv-U 的网络库)中,并在 HTTP 接收路径 (`ProcessReceive`) 中,当头部解析器看到 `Content-Encoding: deflate` 并设置了“deflate”标志后被触发。
简而言之,该例程的调用方式为 `decode(this, &bodyPtr, &bodyLen)`,其执行过程如下:
```
1. inflate bodyPtr[0..bodyLen] -> grows an accumulator buffer `acc` (stock zlib, bounded, correct)
2. free(*bodyPtr) <-- *bodyPtr is an INTERIOR pointer into the receive buffer
3. *bodyPtr = acc // replace compressed body with decompressed buffer
4. *bodyLen = total
```
第 2 步是问题所在。`*bodyPtr` 并不是一个独立分配的内存块:它指向**单个 HTTP 接收缓冲区内部**的请求主体,即 `receive_buffer + header_length`。释放一个内部(且 16 字节未对齐的)指针会导致分配器将受攻击者影响的区域解析为堆块头部 → 堆元数据损坏 → `0xC0000374`。
### 排除了哪些情况(以免您走弯路)
以下两个“显而易见”的假设都是**错误**的,并已在运行时验证:
- **不是 inflate/解压溢出。** 解压器是标准的 `zlib1.dll!inflate`,并在每次调用时严格遵守 `avail_out`(在 100 多个数据块中观察到;零越界写入)。
- **不是累加器溢出。** 不断增长的输出缓冲区每轮分配的大小为 `prev_total + produced + 1` 并准确地写入相同大小 —— 非常紧凑,没有溢出。
损坏完全是由于第 2 步中无效的 `free()` 造成的。
## 证据
在发送解压后为 `"A" * 8192` 的 `Content-Encoding: deflate` 请求时,针对 Serv-U 15.5.4.108 在运行时(通过 Frida)捕获:
- **被释放的指针是 `…ce` — `mod 16 == 14`。** 堆分配基址是 16 字节对齐的,因此这不是分配基址;它是一个内部指针。
- **被释放指针*之前*的 48 字节是 HTTP 头部尾部**,以 `\r\n\r\n` 结尾:
…tream\r\nContent-Length: 26\r\nConnection: close\r\n\r\n
- **被释放指针*处*的字节是原始 deflate 流**(`ed c1 01 0d 00 …`)。
- **崩溃签名:** 错误模块为 `ntdll.dll`,异常 `0xC0000374`
(`STATUS_HEAP_CORRUPTION`),调用源自 `RhinoNET.dll` deflate 处理程序中的 `free`。崩溃前最后一次堆操作正是此 `free(bodyPtr)`。
- **与大小无关:** 解压后仅约 4 KB(压缩后约几十字节)的主体同样会崩溃;工作集内存不会增加。
## 严重性
- **已确认:** 导致 Serv-U 服务(DoS)的**未认证远程崩溃**。服务可能会自动重启,但持续的请求会使其保持宕机状态,并可能耗尽 Windows 服务恢复机制。
- **超出 DoS — 未经证实。** 被释放的“块头部”与**受攻击者控制的 HTTP 头部字节**重叠,原则上这比单纯的 DoS 是更强的利用原语。然而,在现代 Windows(Segment Heap)上,无效的 `free` 在我们的测试中会**快速失败**(`0xC0000374`),并且**我们未能实现代码执行。** 请将其视为*具有内存安全根本原因的预认证堆损坏 DoS*;不要假设会发生 RCE。
## 复现
需要 Python 3(仅限标准库)。将其指向您已获授权测试的 Serv-U HTTP 监听器。在 Windows 上,它使用一次 `Get-NetTCPConnection` 调用来读取监听器 PID,并使用应用程序事件日志来确认堆损坏崩溃。
```
python poc_verify.py # default 127.0.0.1:80, tiny packet, 1 shot
python poc_verify.py --host --port 80
python poc_verify.py --big # body decompresses to 8192 bytes
python poc_verify.py --shots 3
python poc_verify.py --no-events # skip event-log check (no privileges needed)
```
该 PoC 构建了一个最小请求:
```
POST / HTTP/1.1
Host:
Content-Encoding: deflate
Content-Type: application/octet-stream
Content-Length:
Connection: close
```
如果服务崩溃(监听器 PID 发生变化 / 出现 `0xC0000374` 事件),它会报告 **PASS**;如果服务存活(已修补、未受影响或主体未被作为 deflate 处理),则报告 **FAIL**。
## 缓解措施
1. **应用 Serv-U 15.5.4 Hotfix 1**(或更高版本)。
2. **临时方案:** 在 Serv-U 前端,剥离或拒绝 HTTP/HTTPS 监听器上的入站 `Content-Encoding`,例如在反向代理上:
if ($http_content_encoding) { return 400; }
3. 限制 Serv-U Web/管理端口的网络暴露。
## 方法论(分析方式)
- 静态分析:对 `RhinoNET.dll` / `Serv-U.exe` 进行参数化 PE 反汇编(镜像基址 `0x180000000`),以映射 接收 → 头部解析 → deflate 解码 的路径,并定位错误的 `free`。
- 动态分析:对实时服务进行 Frida 插桩 — 挂钩解压器以证明 `zlib` 遵守 `avail_out`,将解码调用的每个 `alloc`/`free`/`memcpy` 追踪到磁盘,并使用进程异常处理程序在损坏发生的瞬间捕获错误指令和 `0xC0000374` 堆栈。随后通过转储被释放指针周围的字节(HTTP 头部尾部 + 原始 deflate 主体,16 字节未对齐)确认了内部指针的释放。
分析中引用的偏移量特定于内部版本 15.5.4.108,且在不同版本中会有所不同。
## 参考资料
- SolarWinds — Serv-U 15.5.4 Hotfix 1 发行说明
- NVD — CVE-2026-28318
- CISA KEV 目录 — CVE-2026-28318
*作为防御性研究,在供应商补丁可用后发布。PoC 仅限 DoS 用途,旨在用于授权测试。*
标签:Maven, PoC, 拒绝服务攻击, 暴力破解, 漏洞分析, 漏洞验证, 路径探测, 逆向工具, 配置错误