libcurl MQTT协议违规与整数溢出漏洞解析

本文详细分析了在libcurl的MQTT实现中发现的一个协议解析漏洞。该漏洞违反了MQTT v3.1.1规范中“剩余长度”字段不得超过四字节的限制,导致协议流不同步,并在32位系统上引发确定性的整数溢出问题。修复建议也已包含在内。

报告 #3484319 - libcurl 中的 MQTT 协议违规与整数溢出

执行摘要

  • 漏洞类型: CWE-190
  • 组件: lib/mqtt.c
  • 函数: mqtt_decode_len
  • 受影响架构:
    • 所有架构: 协议不合规导致流不同步
    • 32位架构: 长度解码中的确定性整数溢出

libcurl 在处理传入数据包时,未能正确强制实施 MQTT v3.1.1 规范对“剩余长度”字段的限制。这使得格式错误的 MQTT 数据包可能被错误解析,导致协议不同步和潜在的拒绝服务。在 32 位系统上,解码逻辑额外允许一个确定性的整数溢出。

根本原因:长度处理不一致

该问题由 lib/mqtt.c 中的不一致性导致。编码器正确强制实施了 MQTT 规范限制,而解码器没有。

正确行为(编码)mqtt_encode_len 中,实现明确将“剩余长度”字段限制为四个字节,符合规范要求:

1
2
3
4
5
for(i = 0; (len > 0) && (i < 4); i++) {
  unsigned char encoded;
  encoded = len % 0x80;
  /* ... */
}

这确保了协议合规性。

错误行为(解码) 相比之下,mqtt_decode_len 没有强制执行相同的限制:

1
2
3
4
5
for(i = 0; (i < buflen) && (encoded & 128); i++) {
  encoded = buf[i];
  len += (encoded & 127) * mult;
  mult *= 128;
}

只要 continuation bit 被设置且输入可用,循环就会继续,允许超过四个字节被作为“剩余长度”字段的一部分消耗。

规范违反

根据 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 规范定义的四字节限制。 示例修复:

1
2
3
4
5
6
7
8
9
for(i = 0; (i < buflen) && (encoded & 128); i++) {
  if(i >= 4) {
    /* Malformed Remaining Length */
    return 0; /* or propagate an error to the caller */
  }
  encoded = buf[i];
  len += (encoded & 127) * mult;
  mult *= 128;
}

可选地,解码后的长度也可以对照实现限制进行检查:

1
2
if(len > MAX_MQTT_MESSAGE_SIZE)
  return 0;

验证说明

通过代码审查和逻辑模拟验证了该问题,确认 mqtt_decode_len 接受超过四个字节的“剩余长度”字段,并允许在 32 位系统上进行算术溢出。无需运行时利用来证明协议违规。

结论

这是一个由于未强制实施 MQTT 规范强制限制而导致的协议解析错误。虽然它不会直接导致内存损坏,但它允许格式错误的 MQTT 数据包使客户端的协议状态不同步并导致拒绝服务。将解码器与现有的编码器逻辑对齐可以干净地解决问题。


互动记录

bagder (curl 工作人员) 发表于 9 天前

While it does not directly result in memory corruption, it allows malformed MQTT packets to desynchronize the client’s protocol state and cause denial of service 这不是“拒绝服务”。这是一个错误。

bagder (curl 工作人员) 9 天前关闭了报告并将状态改为信息性。

感谢您的报告。被认为不是安全问题。因其确实识别了一个真正的错误,故作为信息性问题关闭。

bagder (curl 工作人员) 9 天前请求披露此报告。

根据项目透明度政策,我们希望所有报告都能被披露并公开。

ssyyaa (报告者) 发表于 9 天前

明白。虽然我基于严格的协议合规性将协议不同步视为一个可用性问题,但我尊重项目关于客户端影响的区分。我很高兴解析逻辑将被修复以与编码器保持一致。我已批准披露请求。

ssyyaa (报告者) 发表于 9 天前

感谢回复

bagder (curl 工作人员) 9 天前披露了此报告。

项目 详情
报告日期 2026年1月1日,UTC 21:51
报告者 ssyyaa
报告给 curl
报告 ID #3484319
状态 信息性
严重性 高 (7 ~ 8.9)
披露日期 2026年1月1日,UTC 22:50
弱点 整数溢出
CVE ID
赏金
账户详情
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计