文章总结: CVE-2026-77680是libsoup3中的一个算法复杂度缺陷,源于CVE-2025-32907修复不完善。攻击者通过发送含25000个重复Range字段的HTTP请求,触发O(N²)合并算法,导致单核CPU被占用约90毫秒,造成拒绝服务。修复方案MR!550引入了O(N)原地紧缩算法和200个Range数量上限。建议立即升级至包含该修复的版本,或临时在反向代理层拦截超长Range头。 综合评分: 90 文章分类: 漏洞分析,安全工具,安全建设,解决方案,安全运营
Libsoup3:libsoup:cve-2025-32907 修复后 http 范围合并中的二次 cpu 拒绝服务 (CVE-2026-77680)
撅人
2026年8月27日 00:00 广东
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
🟠 导语 · 紧急预警
用 libsoup 3 做 HTTP 服务的后端开发者、GNOME 生态运维请注意!⚠️
你以为 CVE-2025-32907 的修复已经堵住了 libsoup 的 Range 头攻击面?错了——上次修的是内存爆炸,这次发现 CPU 又爆了。
攻击者只需要发一个带有 25000 个重复 Range 字段 的 HTTP 请求(比如 bytes=0-0 重复 25000 次),你的 libsoup 服务器就会被单个请求卡住 90 毫秒纯 CPU——在事件循环模型下,这就是一个核弹级别的 DoS 攻击:90 毫秒内其他所有请求全部排队等待,服务器”看起来”就像瘫痪了。
这是一个 “打了补丁还不够” 的典型——CVE-2025-32907 修正了 Range 合并的正确性,但合并循环里用了 g_array_remove_index(),每次删除都做一次 O(N) memmove。25000 个重复范围 → O(N²) 工作量。修复 PR(!550)刚刚在 2026-08-20 合并,引入了 O(N) 原地紧缩 + 200 Range 上限限制。
没打最新补丁的 libsoup,今天起就是你的 CPU 消耗器。
🔍 漏洞速览
| | | | — | — | | 漏洞编号 | CVE-2026-77680 | | 漏洞类型 | 算法复杂度缺陷(CWE-400)→ 单请求 CPU 拒绝服务 | | CVSS 评分 | 5.3(Medium) ,Red Hat CVSS v3.1: 5.3 | | 影响产品 | libsoup(含 CVE-2025-32907 修复但无 MR !550 的版本) | | 攻击前提 | 攻击者能向 SoupServer 发 HTTP 请求,无需认证 | | 攻击方式 | 单请求 Range: bytes=0-0,…(25000 次)→ O(N²) 合并 → 单核 CPU 90ms → 事件循环阻塞 → DoS | | 受影响版本 | libsoup 包含 CVE-2025-32907 修复但 不含 MR !550 | | 修复版本 | MR !550(2026-08-20 合并) | | 影响面 | 仅可用性(CPU 耗尽),无内存损坏或信息泄露 | | 修复内容 | O(N) 原地紧缩 + Range 数量上限 200 |
💥 核心危害:一个请求卡 90 毫秒,你的服务器就死了?
CVSS 5.3 看着不高?但这个漏洞的攻击杠杆率极高——”小请求 × 高频率 × 单请求核弹”就是它的杀招。
🧵 单请求 90 毫秒 = 事件循环的 “核弹”
libsoup 基于 GLib 的事件循环(GMainLoop),是单线程事件驱动模型。这意味着 CPU 被某个请求占用时,其他所有请求全部排队等待,连 accept() 新连接都被延迟。90 毫秒听起来很短,但在高并发场景下:
• 10 并发请求被同一时间阻塞 → 平均延迟增加 90ms
• 100 个攻击者同时发构造请求 → 服务器 99.9% 的 CPU 被消耗在 Range 合并上,合法请求排队超时
• 每个请求只有 ~100 字节 payload,但触发 ~90ms CPU 处理——攻击成本远低于防御成本
🎯 攻击场景:谁能被击中?
当 SoupServer 的 handler 返回 HTTP 200 + 非空 body(即处理了 range GET 请求),且 Range 头包含超过 200 个重复范围时,攻击立刻触发。
这意味着以下场景全部中招:
• GNOME 桌面应用:使用 libsoup 做 HTTP 客户端+服务端的应用,如果同时接收来自不可信网络的请求
• Web 服务器:基于 SoupServer 的轻量级 HTTP 服务(比如开发/测试服务器、API 网关、内容分发节点)
• CDN / 代理层:如果 libsoup 作为反向代理接收客户端的 Range 请求,攻击者通过代理层放大攻击面
• 下载服务:支持断点续传的服务天然处理 Range 头——这是攻击最完美的伪装
💡 为什么不是高分漏洞?
CVSS 5.3 属于 Medium 的原因:这个漏洞 仅影响可用性(Availability),不会导致内存损坏或信息泄露。但它确实是一个典型的”算法复杂度攻击”(Algorithmic Complexity Attack / Algorithmic Complexity Vulnerability)——攻击者故意构造输入使算法退化到最差时间复杂度,从而用很小的输入达到很大的资源消耗效果。
💬 攻击者成本:一个 ~100 字节的 HTTP Range 头。防御方成本:事件循环阻塞 90ms/请求 → 高并发下服务器可用性下降 → 需要限流/拦截/升级。
🧠 漏洞原理(人话版)
理解这个漏洞,需要搞清三个层次:Range 头、合并算法、GArray 的数据结构代价
第 1 层:什么是 HTTP Range 头?
Range 是 HTTP/1.1 的断点续传标准头。比如下载一个大文件时网络断了,你可以请求服务器只发送你还没下载到的字节范围:
客户端请求:
GET /large-file.zip HTTP/1.1
Host: example.com
Range: bytes=1000-2000, 3000-4000, 5000-6000
服务器返回 206 Partial Content + 多段数据
一个合法的 Range 头最多可以包含 约 25000 个范围——受限于请求头最大 ~100 KiB。浏览器和下载工具在多线程下载时经常一次请求多个 range。
第 2 层:CVE-2025-32907 修了什么?还漏了什么?
CVE-2025-32907 针对的是 Range 头的内存放大问题——攻击者发大量重复 Range,服务器分配大量内存返回,导致内存耗尽。修复方式是 合并(coalesce)相同或重叠的 Range:bytes=0-0 重复 25000 次 → 合并成 bytes=0-0 一次。这样内存占用降下来。
但合并本身也有代价。修复补丁(commit 9bb92f7a)用 g_array_remove_index() 逐个删除已合并的元素。问题来了——
第 3 层:GArray 的 O(N) memmove 代价
GLib 的 GArray 是一个连续的动态数组(类似 C 的 malloc 分配 + realloc 扩容)。当你在数组中间删除一个元素时,后续所有元素必须整体向前移动一位——这就是 O(N) memmove。如果一个请求有 N 个重复 Range,合并循环要执行 N 次删除,每次删除 O(N) → 总复杂度 O(N²)。
25000 个重复 Range = 25000 次删除操作 × 平均 12500 次 memmove = ~3 亿次内存操作。这就是那 ~90 毫秒纯 CPU 的来历。
修复方案 MR !550 做了什么?
两个改动,一步到位:
1. O(N) 原地紧缩(in-place compaction):不再逐个删除元素,而是用双指针算法——一个读指针遍历原始数组,一个写指针只写有效元素。每个元素最多被读一次、写一次,总复杂度 O(N)。
2. Range 数量上限 200:请求头中的 Range 数量超过 200 个,直接拒绝(返回 400 Bad Request)。即使有人尝试攻击,也被挡在入口。
📊 O(N²) vs O(N) 复杂度对比
修复前(每请求最大 25000 Range)
删除 25000 次 × 平均 12500 次 memmove ≈ 3.125 亿次操作 ≈ 90ms 单核 CPU(实测)
修复后(O(N) 原地紧缩 + 200 Range 上限)
最多 200 个 Range × O(N) 紧缩 ≈ 200 次操作 ≈ 亚微秒级(可忽略)
⏱️ 3 秒自查
❌ 受影响状态
• libsoup 包含 CVE-2025-32907 修复但 不含 MR !550
• Debian 包:libsoup3 <= 3.6.6-1(sid/forky 仍受影响,trixie/bookworm 同样)
• Red Hat RHEL 10:libsoup3(Fix deferred)
✅ 安全状态
• 已应用 MR !550 修复的 libsoup 版本(O(N) 紧缩 + 200 Range 上限)
自查命令:
1. 检查已安装的 libsoup 版本
Debian/Ubuntu:
apt list –installed libsoup3
Red Hat/CentOS:
rpm -q libsoup3
2. 从源码编译的 libsoup,检查源码是否包含 MR !550
在 soup-message-headers.c 中搜索 compact 相关代码
grep -n “compact” soup-message-headers.c
修复版应包含 compact_ranges 相关函数
3. 快速验证:你的服务是否处理 Range 请求
构造一个 201 个 Range 的请求(超过上限即应被拒绝)
(修复版应该返回 400,未修复版应该响应 206 + 慢 ~90ms)
生成一个包含 250 个重复 range 的 HTTP 请求
RANGES=$(python3 -c “print(‘bytes=’ + ‘,’.join([‘0-0’]*250))”)
curl -s -H “Range: $RANGES” “http://
-o /dev/null -w “%{http_code} %{time_total}s”
输出 ~400 0.001 → 修复生效(200 Range 上限触发)
输出 ~206 0.090 → 仍有漏洞(250 range 触发 O(N²))
4. 检查你的应用是否使用了 SoupServer
grep -r “SoupServer|soup_server” –include=”*.c” –include=”*.vala” src/
如果有 SoupServer 的 handler 返回 HTTP 200 + 非空 body(range GET) → 中招
🛡️ 修复方案
✅ 方案一:升级到含 MR !550 的 libsoup(推荐,根治)
MR !550 已于 2026-08-20 在 GNOME libsoup 上游合并。等待各发行版打包发布后直接升级:
Debian/Ubuntu
apt update && apt upgrade libsoup3
Red Hat RHEL 10
dnf update libsoup3
源码编译:拉取最新 upstream,确认包含 MR !550
git clone https://gitlab.gnome.org/GNOME/libsoup.git
cd libsoup && meson build && ninja -C build
官方修复:MR !550
⚠️ 方案二:临时缓解——拦截超长 Range 头
如果暂时无法升级,可以在请求入口(负载均衡/反向代理)拦截超长 Range 头:
Nginx 反向代理配置示例
限制 Range 头大小不超过 2KB(约 200 个 range 条目)
或限制 Range 头中 range-spec 的数量
方案 A:直接拒绝过大的 Range 头
map $http_range $range_too_long {
default 0;
“~.{2048,}” 1;
}
if ($range_too_long) { return 400; }
HAProxy 配置示例
在 http-request 阶段拦截
http-request deny deny_status 400 if { req.hdr(Range) -m len gt 2048 }
⚠️ 这些措施 只能延缓无法根治——攻击者仍然可以尝试在 200 个 range 以内进行部分攻击。升级才是正道。
🛡️ 方案三:限制 SoupServer 的网络暴露面
如果 libsoup 服务运行在内网,确保它不对公网开放,可以从根本上降低被远程利用的风险:
• 监听 localhost(127.0.0.1)而非 0.0.0.0
• 使用 iptables/firewalld 限制访问源 IP
• 如需暴露,通过反向代理(Nginx/Caddy)做 Range 头和请求频率限制
💡 网络收口降低被远程利用风险,但内网横向移动仍可触达——根治还是要打补丁。
🕵️ 入侵排查清单
这类算法复杂度 DoS 通常不留持久化后门,但你需要确认:
☐ 检查服务器日志,搜索异常的 Range 头大小(> 1KB 的请求)
☐ 检查 CPU 使用率是否在特定 Range 请求后出现突增(~90ms 单核峰值)
☐ 确认 SoupServer 的 handler 是否正确处理了 Range 请求(返回 200 + body 时触发)
☐ 确认没有利用此漏洞进行的进一步横向移动
☐ 升级后验证:201 个 range 的请求返回 400,200 个 range 的请求正常响应
⚠️ 安全提醒
这个漏洞最讽刺的地方是——CVE-2025-32907 的修复反而制造了这个新漏洞。
CVE-2025-32907 修的是”Range 头内存放大”——客户端发大量重复 range,服务器分配大量内存。修复思路是对的:合并重复 range。但合并的实现方式用了 g_array_remove_index() 逐个删除,导致合并过程本身变成了 O(N²) 复杂度攻击面。
这是一个经典的 “修了一个洞,又开了一个口” 的案例。修复补丁解决了内存问题,但没考虑算法复杂度,结果攻击者的攻击载荷从”内存炸弹”变成了”CPU 炸弹”——伤害形式变了,但 DoS 的本质没变。
如果你的后端用了 libsoup 做 HTTP 服务,今天就去查版本、安排升级。 虽然 CVSS 只有 5.3(Medium),但这个攻击的杠杆率极高——一个 ~100 字节的 HTTP Range 头就能卡住整个事件循环。在 DDoS 攻击面前,攻击者不需要多高的技术门槛,一个 curl 脚本就能构造 25000 个重复 range。
转发给所有用 GNOME/libsoup 开发 HTTP 服务的技术团队——补丁已出 6 天了,还没升的真的在裸奔。
📎 官方参考
• 修复 MR !550:gitlab.gnome.org/GNOME/libsoup/-/merge_requests/550
• Issue #538:gitlab.gnome.org/GNOME/libsoup/-/issues/538
• CVE-2026-77680:access.redhat.com/security/cve/CVE-2026-77680
• CVE-2025-32907:access.redhat.com/security/cve/CVE-2025-32907
• Bugzilla:bugzilla.redhat.com/show_bug.cgi?id=2520892
本文仅供安全研究与防御参考,修复请以官方公告为准。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:撅人 《Libsoup3:libsoup:cve-2025-32907 修复后 http 范围合并中的二次 cpu 拒绝服务 (CVE-2026-77680)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。












评论