深度剖析cURL配置文件解析中的任意释放漏洞

本文详细分析了一个cURL在解析配置文件时出现的任意内存释放漏洞。攻击者可通过精心构造的配置文件控制传递给free()函数的指针,可能导致双重释放、释放后使用或内存损坏,文章包含完整的漏洞复现步骤、调试过程及修复方案。

curl配置文件解析中的任意释放漏洞分析报告

报告编号: #3434543 报告平台: HackerOne 提交时间: 2025年11月20日 报告者: letshack9707 项目: curl 状态: 已公开(被评估为信息性,非安全问题)

漏洞概要

在cURL解析配置文件的过程中,存在一个任意释放(arbitrary free)漏洞。攻击者可以通过特制的配置文件,控制传递给free()函数的指针值。根据程序的具体情况和攻击者在释放指针后所能进行的操作,这可能引发双重释放(double-free)释放后使用(use-after-free)内存损坏(memory corruption)

声明:报告中使用了AI来帮助整理与此错误相关的一些资源。

受影响版本

  • curl 8.17.0 (x86_64-pc-linux-gnu)
    • libcurl/8.17.0 OpenSSL/3.4.1 zlib/1.3.1 brotli/1.1.0 zstd/1.5.7 libidn2/2.3.8 libpsl/0.21.2 nghttp2/1.64.0 librtmp/2.3 OpenLDAP/2.6.9
    • 发布日期: 2025-11-05
  • curl 8.16.0 同样受影响(配置文件中可控参数和样本不同)。

操作系统/内核:

  • Linux kali 6.3.0-kali1-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.3.7-1kali1

复现步骤

  1. 创建并编辑配置文件 host0.bin
    1
    2
    
    touch host0.bin
    vim host0.bin
    
  2. 将以下内容粘贴到 host0.bin 中:
    1
    2
    3
    4
    
    --url "http://google.com/iernay{1-2}kFORFNUUklOR1JBTkRTVFJJTkdSQU5EU1RSSU5HUkFORFNUUklOR1JBTkRTVFJJTkdSQU5EU1RSSU5HUkFORFNUUklOR1JBTkRTVFJJT"
    --url "http://[::%2-socks5]:8080/"
    --url google.com-Z[.-p].example.com"
    --doh-url=127.0.0.1
    
  3. 使用GDB运行cURL并加载该配置文件:
    1
    
    gdb -ex "r" --args curl --config host0.bin
    
    程序将在 __GI___libc_free 函数中因段错误(SIGSEGV)而停止。寄存器$rdifree函数的参数)的值为0x2e302e302e373231,经反转后对应字符串 127.0.0.。这表明我们能够控制(针对此配置文件)传递给free()的数据。

漏洞利用与控制验证

为了进一步证明对free()参数的控制能力,报告者编写了一个Python脚本 mutate.py。该脚本可以将堆中的可控数据(127.0.0.)替换为我们希望传递给__GI___libc_free的任意地址,并生成新的配置文件 vuln.conf

1
python mutate.py 0x4242424242424242 && gdb -ex "r" --args curl --config vuln.conf

执行后,程序同样在free()中崩溃,但此时寄存器$rdi的值变为0x4242424242424242BBBBBBBB),证实了攻击者可以完全控制释放的指针。

堆栈跟踪分析: 崩溃发生在tool_urlglob.c文件的glob_cleanup函数中(第499行):

1
tool_safefree(glob->pattern[i].c.set.elem[elem]);

tool_safefree最终调用了标准库的free()。回溯显示,调用链为:main -> operate -> run_all_transfers -> … -> glob_url -> glob_cleanup -> free

双重释放(Double-Free)演示

通过ltrace工具跟踪free调用,可以更清晰地观察内存操作。首先关闭地址空间布局随机化(ASLR)以便观察:

1
2
echo 0 > /proc/sys/kernel/randomize_va_space
ltrace -e free -o free.txt curl --config vuln.conf

如果我们将一个已经被释放的地址写入配置文件(通过mutate.py设置),则会触发tcache的双重释放检测机制:

1
python mutate.py 0x555555602dd0 && ltrace curl --config vuln.conf

输出结果显示:

1
2
free(0x555555602dd0) # 释放一个先前已释放的地址
free(0x555555602dd0free(): double free detected in tcache 2

程序因SIGABRT(中止信号)而终止,这正是glibctcache机制检测到双重释放时的行为。

漏洞影响与评估

潜在影响: 控制传递给free()的指针,可能导致双重释放/释放后使用,进而可能引发远程代码执行(RCE)权限提升。具体影响取决于运行cURL的环境。

利用前提:

  • 需要诱使用户执行恶意的配置文件(例如通过~/.curlrc)。
  • 需要额外的漏洞(如任意读取、内存泄漏)来绕过ASLR和Tcache缓解机制,或者利用同一漏洞构建读/写原语来实现绕过。

严重性评级: 低 (Low) 报告者将严重性设置为“低”,原因如下:

  1. 利用需要诱骗用户运行特制的配置文件。
  2. cURL本身已经具备执行命令的能力(此漏洞源于cURL处理配置文件的方式,而非其固有的命令执行能力)。
  3. 需要额外的漏洞来绕过ASLR/Tcache缓解机制。

维护者响应与修复

cURL安全团队(bagder, dgustafsson)在收到报告后迅速做出了回应。

初步评估: 维护者起初认为这是一个无害的bug。bagder指出:这是cURL工具中一次realloc后对(未初始化的)堆内存的释放。它不与其他线程共享内存空间,攻击者无法控制或滥用这次释放——即使用户提供了特制的配置文件。结果很可能是无害的或导致崩溃。在这种上下文中,cURL工具崩溃是无害的,因为cURL无论如何都会退出,并且给定一个任意的配置文件,无法期望有特定的定义行为,因为输入是未知的。因此,他们认为这不是一个安全漏洞。

修复尝试: 尽管不认为是安全漏洞,维护者仍然提供了修复代码。最初的补丁被认为“过于天真和不完整”,随后他们提交了一个更完善的修复尝试,并成功通过了glob相关测试用例: GitHub Pull Request #19614

报告者反驳: 报告者letshack9707重申,他已经证明了可以通过配置文件控制传递给free()的指针,并导致了tcache中的双重释放检测。他询问这与经典的已知双重释放漏洞有何不同,并提出了理论上的利用思路:首先需要绕过tcache双重释放检测,然后触发cURL中分配与之前释放块大小相同的内存分配。如果分配器随后在malloc()调用中返回该地址,返回的指针将指向攻击者控制的区域(我们释放的地址),允许我们在选定的地址获得一个伪造的块(fake chunk)。

最终结论与报告处理: 经过多轮讨论,cURL安全团队坚持认为,鉴于cURL工具本身的性质(单进程、以用户权限运行、可接受外部配置文件并已有执行命令的能力),即使能够控制free()的地址,也无法构成比现有能力更严重的威胁。他们无法找到将此bug转化为实际漏洞的方法。

因此,报告状态被更改为 Informative(信息性),并于2025年11月23日公开披露。未分配CVE ID,也未发放赏金。

报告者总结

报告者letshack9707在报告关闭后表示,鉴于cURL配置文件解析漏洞在此项目中被视为普通bug或cURL的正常能力范围,未来类似的问题将直接提交到GitHub,而非HackerOne平台。他同时感谢cURL团队为改进工具安全性所付出的努力和时间。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计