针对 Sliver C2 的 HTTP(S) 监听器的拒绝服务攻击利用工具。通过暴力破解每个会话的 PNG 编码随机数,并投递一个解压炸弹来耗尽服务器内存。
已发布为 GHSA-663m-7x7m-g4fw。
Sliver 的 HTTP(S) C2 通道将消息封装在 PNG 图像中。每个会话被分配一个范围在 [1, 65537) 内的随机随机数,服务器仅解码那些 ?n= 查询参数与会话随机数匹配的请求中的 PNG 数据。这是一种路由机制,而非身份验证检查——密钥空间仅为 16 位。
服务器使用 Go 的 image.Decode() 解码 PNG,该函数会在内存中分配 宽度 × 高度 × 每像素字节数 的空间。一个声明尺寸为 32767×32767 RGBA 的 PNG 文件在网络上压缩后仅约 3 KB,但解压后在内存中会超过 4 GB。服务器对解码后的尺寸没有任何限制。
该利用工具分三个阶段工作:
在 GHSA-663m-7x7m-g4fw 中引用的修复版本之前的 Sliver C2 版本。任何运行 HTTP 或 HTTPS 监听器的 Sliver 服务器均受影响。
go build -o pngboomer
无外部依赖。仅使用标准库。
./pngboomer -url http://target:8080/ [选项]
| 标志 | 默认值 | 描述 |
|---|---|---|
-url | http://127.0.0.1:8080/ | Sliver HTTP C2 基础 URL |
-workers | 8 | 扫描并发数 |
-probe-w | 2000 | 探测 PNG 宽度 |
-probe-h | 2000 | 探测 PNG 高度 |
-probe-color | 2 | 探测颜色类型(2=RGB,6=RGBA) |
-kill-w | 32767 | 击杀 PNG 宽度 |
-kill-h | 32767 | 击杀 PNG 高度 |
-kill-color | 6 | 击杀颜色类型(2=RGB,6=RGBA) |
-threshold-ms | 50 | 随机数检测的最小响应时间下限 |
-outlier-mult | 15.0 | 自适应阈值 = 基线 p99 × 此值 |
-calibrate | 16 | 校准样本数量 |
-verify | 3 | 每个候选随机数的重新探测次数 |
-max-nonce | 65537 | 随机数范围上限(Sliver 模数) |
-probe-timeout | 5s | 每次探测的 HTTP 超时 |
-kill-timeout | 180s | 击杀请求的 HTTP 超时 |
-target-cap-mb | 10240 | 声明的目标内存上限(安全检查) |
-nonce | 0 | 跳过扫描,直接使用此随机数 |
-scan-only | false | 仅查找随机数并打印,不发送击杀 |
-no-confirm | false | 击杀后跳过对目标死亡的 TCP 轮询 |
-no-color | false | 禁用 ANSI 彩色输出 |
-silent | false | 仅将发现的随机数打印到 stdout |
针对本地 Docker 目标的默认扫描和击杀:
./pngboomer -url http://127.0.0.1:8080/ -target-cap-mb 10240
仅扫描(查找随机数而不击杀):
./pngboomer -url https://c2.target.com/ -scan-only
已知随机数时跳过扫描:
./pngboomer -url http://target:8080/ -nonce 41337
击杀炸弹会在目标上触发多 GB 的 PNG 解码。测试时,请在 Docker 容器中使用 --memory=<N>g 运行 Sliver 服务器,并传入 -target-cap-mb N,以便该工具拒绝会超出目标内存的危险 worker/探测组合。
探测 PNG 足够大,其解码耗时明显长于服务器对错误随机数的快速路径拒绝。扫描会打乱随机数范围并将其分配到多个 worker goroutine 中。每个 worker 使用候选随机数发送探测 PNG 并测量响应时间。
当响应超过自适应阈值(-threshold-ms 与 baseline_p99 × outlier-mult 中的较大值)时,该候选值会被重新探测 -verify 次。如果大多数重新探测也超过阈值,则确认该随机数。如果未确认,该候选值会被加入黑名单,扫描继续。在扫描放弃之前,最多容忍 8 个误报"毛刺"。
通过 GitHub 的私有公告流程报告给 Bishop Fox。CalebKingan 编写了补丁。