MQTT协议违规与整数溢出在libcurl中的分析
报告提交时间: 10天前 提交者: ssyyaa 报告对象: curl项目 报告状态: 已公开(视为信息性报告)
执行摘要
漏洞类型: CWE-190(整数溢出或进制环绕)
影响组件: lib/mqtt.c
涉及函数: mqtt_decode_len
受影响架构:
- 所有架构: 协议违规导致流失步
- 32位架构: 长度解码中的确定性整数溢出
漏洞详情
libcurl 在解码传入数据包时,未能正确强制执行 MQTT v3.1.1 规范中对“剩余长度”字段的限制。这使得畸形的 MQTT 数据包可能被错误解析,导致协议失步和潜在的拒绝服务。在 32 位系统上,解码逻辑还会导致确定性的整数溢出。
根本原因:不一致的长度处理
问题源于 lib/mqtt.c 内部的不一致性:编码器正确执行了 MQTT 规范限制,而解码器却没有。
正确行为(编码)
在 mqtt_encode_len 中,实现明确将“剩余长度”字段限制为四个字节,符合规范要求:
|
|
错误行为(解码)
相比之下,mqtt_decode_len 没有强制执行相同的限制:
|
|
只要延续位被设置且有输入可用,循环就会继续,从而允许超过四个字节被作为“剩余长度”字段的一部分消耗。
规范违规
根据 MQTT v3.1.1 规范,第 2.2.3 节(剩余长度):
“剩余长度字段中的字节数不得超过四个字节。”
通过接受和处理超过四个字节的长度字段,libcurl 违反了 MQTT 规范并进入未定义的协议状态。
32位系统上的整数溢出
在 32 位架构上,size_t 是一个 32 位无符号整数。变量 mult 在解码过程中反复乘以 128。
32位系统示例进程:
| 迭代次数 | mult 值 | 操作 | 结果 |
|---|---|---|---|
| 0 | 1 | 1 × 128 | 128 |
| 1 | 128 | 128 × 128 | 16,384 |
| 2 | 16,384 | × 128 | 2,097,152 |
| 3 | 2,097,152 | × 128 | 268,435,456 |
| 4 | 268,435,456 | × 128 | 溢出 → 0 |
溢出后,mult 变为零,消耗的任何后续字节都不会对解码出的长度做出贡献。这使得一个巨大或畸形的“剩余长度”字段可以部分被“隐藏”,同时输入指针仍在前进。
影响
协议失步(所有架构) 通过为“剩余长度”字段消耗超过四个字节,libcurl 可能与 MQTT 流失去同步。原本属于有效载荷或后续数据包的字节可能被错误地解释为长度数据,导致后续数据包解析错误。
拒绝服务
这种失步可能导致畸形数据包处理、意外的连接终止或重复的协议错误(如 CURLE_WEIRD_SERVER_REPLY)。
报告者未声明存在内存损坏或代码执行。
建议修复方案
解码逻辑应明确强制执行 MQTT 规范定义的四字节限制。
示例修复:
|
|
可选的,解码出的长度也可以对照实现限制进行检查:
|
|
验证说明
该问题通过代码审查和逻辑模拟得到验证,确认了 mqtt_decode_len 接受超过四个字节的“剩余长度”字段,并在 32 位系统上允许算术溢出。演示协议违规无需运行时利用。
结论
这是一个协议解析错误,源于对强制性 MQTT 规范限制的缺失执行。虽然它不直接导致内存损坏,但允许畸形的 MQTT 数据包使客户端的协议状态失步并导致拒绝服务。使解码器与现有的编码器逻辑对齐可以干净地解决问题。
时间线与讨论
- 报告提交后:
bagder(curl 维护人员) 发表评论,指出这不是“拒绝服务”,而是一个 Bug。 - 报告状态变更:
bagder关闭了报告并将状态改为 信息性。评论:“感谢您的报告。我们认为这不是一个安全问题。因确实识别出了一个真正的 Bug 而关闭为信息性。” - 披露请求:
bagder请求公开此报告,以遵守项目的透明度政策。 - 报告者回应:
ssyyaa表示理解,尊重项目关于客户端影响的区分,并批准了披露请求。 - 报告披露:
bagder公开了此报告。
报告元数据
- 报告 ID: #3484319
- 状态: 信息性
- 严重性评分(原): 高 (7 ~ 8.9)
- 弱点: 整数溢出
- CVE ID: 无
- 赏金: 无
- 报告日期: January 1, 2026, 9:51pm UTC
- 公开日期: January 1, 2026, 10:50pm UTC
附件:
报告中包含一个名为 mqtt_malicious_server.py 的附件(附件ID: F5176784),用于演示漏洞。