CVE-2024-6197 Curl 和 Libcurl 的漏洞:堆栈上的释放后使用
作者: Ben Gross,JFrog 安全研究员;Yair Mizrahi,JFrog 安全研究团队负责人
一、背景
2024年7月24日,Curl 维护人员宣布了一个新的堆栈缓冲区释放后使用(UAF)漏洞 —— CVE-2024-6197。这种类型的漏洞非常罕见,因为 UAF 问题通常发生在堆(heap)上而不是堆栈(stack)上。
虽然此漏洞很容易被利用来导致拒绝服务,但在本文中我们将说明为什么我们认为在任何实际设置中利用此漏洞实现远程代码执行几乎是不可能的。
二、哪些版本的 Curl 受到影响?
CVE-2024-6197 同时影响 Curl 命令行工具和 Libcurl 库。
受影响的版本包括 Curl 和 Libcurl 从8.6.0 至 8.8.0(含)的所有版本。
三、CVE-2024-6197 攻击的前提条件
当以下所有条件均满足时,此漏洞可被利用:
- 受害者使用curl(curl 库或 curl CLI 工具)连接到恶意 TLS 服务器。恶意服务器提供特别设计的 TLS 证书,从而触发漏洞。此漏洞也可在中间人攻击 (MitM) 场景中利用,但在此场景中,无需利用任何软件漏洞即可实现 DoS,因此此 CVE 在中间人攻击 (MitM) 场景中不会带来额外的安全影响。
如下图所示,不知情的用户连接到恶意服务器,该服务器返回虚假证书:
- 构建 curl 二进制文件时选择支持GnuTLS、wolfSSL、Schannel、Secure Transport或 mbedTLS。要检查 curl 实例是否存在漏洞,请运行“curl -version”并检查是否列出了上述任何 TLS 后端。使用其他 TLS 后端或常用 Linux 发行版(如 Debian、Ubuntu 和 Alpine)的构建默认不存在漏洞,因为它们中的大多数默认都是使用 OpenSSL 构建的。
如下图所示,“curl -version”命令可以帮助确定特定版本是否存在漏洞:
- 必须设置curl 的证书信息标志 CURLINFO_CERTINFO。此标志允许 libcurl 收集有关连接中使用的 SSL 证书链的详细信息,传输后可使用带有 CURLINFO_CERTINFO 选项的 curl_easy_getinfo 检索这些信息。
从我们的研究中,我们观察到,只有明确使用 CURLINFO_CERTINFO 时,curl 才容易受到攻击(尽管其他更罕见的利用场景也可能存在)。例如:
当使用特定的 CLI 标志调用 curl CLI 工具时,该工具很容易受到攻击,这会导致启用 CURLINFO_CERTINFO 标志:
四、攻击概述
Libcurl 的 ASN.1 解析器包含函数 utf8asn1str(),该函数用于解析证书中存在的 ASN.1 UTF-8 字符串。在某些情况下,该函数可能会调用 4 字节本地堆栈缓冲区,从而触发堆栈释放后使用漏洞。
大多数 malloc 实现(包括 glibc)都会识别此错误并立即终止进程。但是,某些实现可能会接受输入指针并将该内存添加到其可用块列表中。这可能会导致堆栈内存被覆盖。覆盖此内存的内容由 free() 实现确定,通常由内存指针和一组标志组成。
要利用 CVE-2024-6197 进行远程代码执行,必须采取以下步骤:
- 攻击者需要设置一个具有509 证书的恶意TLS 服务器,以触发无效的 free()。
- 使用Libcurl 或 curl CLI 的应用程序需要连接到恶意 TLS 服务器。这会导致恶意证书被解析,并且堆栈地址被放入分配器的空闲列表(freelist)中。
- 攻击者以某种方式与客户端交互,导致堆栈地址由malloc() 调用返回并用于存储来自攻击者的数据。
- 根据堆栈布局,攻击者可能能够覆盖局部变量、指针等。
五、深入细节
5.1 设计恶意证书
HTTPS (X.509) 证书格式由 RFC5280(https://datatracker.ietf.org/doc/html/rfc5280)定义。该定义以 ASN.1 表示,这是一种用于定义格式和数据结构的语言。ASN.1 与许多编码相关联,例如 BER 和 DER(可区分编码规则),它是 X.509 证书和私钥的二进制编码。
大多数 HTTPS 证书通常采用 DER 编码,这是一种 TLV 编码(类型-长度-值 或标签-长度-值)。
使用 DER 编码生成的字符串(标签、长度和值)如下图所示:
当您读取使用 DER 编码的字节时,首先会遇到一种类型,在 ASN.1 中称为“标签”(Tag)。这是一个字节或一系列字节,它告诉您正在编码什么:这可能是 INTEGER、UTF8String 或其他预定义值。接下来您会遇到“长度”(Length)值,这是一个数字,它告诉您需要读取多少字节的数据才能获得“值”(Value)。然后,当然是包含“值”本身的字节。
在 Libcurl 的 utf8asn1str; 函数中,该函数用于解析和处理证书中的 ASN.1 UTF-8 字符串,其中有一个本地堆栈缓冲区初始化。当 wc 变量大于 0x00200000 时,该缓冲区将被释放,如 [1] 所示。
只有当size变量正好为4时,wc变量才可以被设置为大于0xff00的值,如 [2] 所示。
根据证书中的字符串类型初始化size变量,如果类型等于 UniversalString(https://www.oss.com/asn1/resources/asn1-made-simple/asn1-quick-reference/universalstring.html),一种几乎从未在证书中使用过的旧编码方法,则返回值为 4。
当size = 4 时,必须满足以下条件:
- 字符串 type必须是 UniversalString (0x1c)
- 字符串应包含超过0x00200000 限制的值。
需要注意的是,使用 UniversalString 创建证书并非易事,因为大多数证书创建工具(如 OpenSSL)都不支持将字符串编码为 UniversalString。
5.2滥用释放后使用(Use-after-Free, UAF)
通过写入最近“释放”的堆栈位置,可以发起成功的 RCE 攻击。如下图所示:
在大多数 Linux 发行版中,调用 free(buf) 会导致程序崩溃。在堆实现不会崩溃的 Linux 发行版中,调用 malloc 或任何其他堆分配函数,在缓冲区释放后不久,会错误地返回堆栈指针作为 malloc 的返回值。这可能允许攻击者写入先前“释放”的堆栈位置。要成功进行 RCE,攻击者必须在 curl 中找到合适的 malloc 调用,该调用可以通过来自恶意 TLS 服务器的通信触发,然后确保他们可以控制将写入“分配”空间的内容。
5.3综述
要成功利用 CVE-2024-6197,需要执行以下步骤:
- 找到一个在free(buf) 之后不会崩溃的 Linux 发行版可能非常具有挑战性,因为我们检查的大多数 Linux 发行版在对堆栈变量调用 free() 时都会使程序崩溃。例如,Ubuntu 22.04 和 Ubuntu 24.04 会崩溃,而 Alpine 3.10 不会崩溃,因为它们的 C 实现不同。
- 使用精心制作的证书设置TLS 服务器,该证书需要使用至少一个 UniversalString 进行编码,其中 UniversalString 中至少有 2 个字符需要通过 wc >= 0x00200000 条件。
在 curl 中查找可以通过攻击者控制的 TLS 服务器的 TLS 响应触发的代码流,该代码流可以在调用错误的 free() 后很快到达 malloc()。
六、CVE-2024-6197 在现实世界中的可利用程度如何?
通过 CVE-2024-6197 触发的DoS 攻击,示例如下:
在我们的研究过程中,我们尝试寻找在释放堆栈缓冲区后不会崩溃的 Linux 发行版(例如 Debian、Ubuntu 和 Red-Hat)。最终,我们确定 Alpine 3.10 是在这些条件下不会崩溃的发行版,因为 Alpine 使用了 musl (https://www.musl-libc.org/) libc 实现。直到 musl 版本 1.2.1 为止,musl 都没有对其释放的地址进行任何检查。
我们必须使用易受攻击的 TLS 后端来构建 Curl,因为它在 Alpine 3.10 上默认安装了无漏洞的后端(OpenSSL)。我们的研究证明,即使这些版本不会导致崩溃(DoS),使用 free(buf) 也会导致未捕获的错误,并且堆栈地址不会像我们预期的那样添加到 freelist bin 中。因此,在这种情况下无法实现基于 RCE 的攻击。
munmap 中未捕获的 ENOMEM 错误 (RAX)如下图所示:
由于 curl 是一个无处不在的项目,随着更复杂的攻击不断涌现,未来可能会利用此漏洞。然而,在大多数 Linux 发行版中,调用堆栈缓冲区上的 free() 不会造成崩溃,这意味着远程代码执行的可能性极小。
还应考虑到,此漏洞是在 2024 年 1 月 31 日发布的 Curl 版本 8.6.0 中最近引入的。因此,此版本不太可能出现在没有针对释放堆栈地址的缓解措施的任何 Linux 发行版或嵌入式系统中。因此,进一步降低了远程代码执行的可能性。
基于上述所有原因,我们相信绝大多数 curl 用户不会受到此漏洞的影响。
七、CVE-2024-6197 真正的严重性是怎样的?
如前几节所示,只有满足几个特定条件时才会触发此问题。此外,由于代码流以及大多数 Linux 发行版中的 glibc 和 musl 缓解措施,利用此 CVE 时无法实现 RCE。
我们预计最严重的损害是 Curl 客户端中的 DoS,这不是一个真正的问题,因为分叉的客户端进程崩溃对安全的影响可以忽略不计。
八、如何解决CVE-2024-6197
升级到新发布的 Curl 8.9.0 (https://curl.se/changes.html#8_9_0)是解决此漏洞的最直接方法。请确保识别可能存在风险的任何版本(从 8.6.0 到 8.8.0 不等),并将其更新到此新修复的版本。
除了上游修补版本之外,多个 Linux 发行版已经发布了 curl 的修复版本,最著名的是 Ubuntu(https://ubuntu.com/security/CVE-2024-6197)、Debian(https://security-tracker.debian.org/tracker/CVE-2024-6197)、Alpine(https://security.alpinelinux.org/vuln/CVE-2024-6197)、SUSE(https://www.suse.com/security/cve/CVE-2024-6197.html) 和 Red Hat JBoss Services(https://access.redhat.com/security/cve/CVE-2024-6197)(Red Hat Enterprise Linux 不受影响)。
针对基于堆栈的 UAF 漏洞的缓解措施
2004 年发布的 Glibc 2.3.4 版本引入了一种缓解措施,可将此问题作为远程代码执行 (RCE) 漏洞消除。相关代码片段(https://elixir.bootlin.com/glibc/glibc-2.3.4/source/malloc/malloc.c#L4290)如下:
此代码检查下一个要释放的堆块,并验证它是否位于堆区域之一内。如果它在这些区域之外,则应用程序中止。当触发漏洞并释放堆栈指针时,此检查失败,导致程序崩溃。
另一个可以发现问题的检查是块对齐检查,如下面的代码片段(https://elixir.bootlin.com/glibc/glibc-2.3.4/source/malloc/malloc.c#L4224)所示:
这段代码验证了块地址是否与内存页面对齐,如果失败,程序也会崩溃。
九、JFrog 平台是否容易受到 CVE-2024-6197 的攻击?
经过内部研究,我们可以确认 JFrog DevOps 平台(https://jfrog.com/platform/)不会受到 Curl CVE-2024-6197 的攻击。
使用 JFrog Xray 和 JFrog Advanced Security (JAS)解决 CVE-2024-6197
与往常一样,JFrog Security Essentials(Xray,https://jfrog.com/xray/)和 JFrog Advanced Security (JAS,https://jfrog.com/devops-native-security/)可用于识别整个代码库和编译成的制品(包括 Docker 容器、存储库里的包甚至独立二进制文件)中出现的每次 Curl。
JFrog 平台对 Curl 的 CVE-2024-6197 进行的上下文分析如下图所示:
通过在微信公众号上关注我们(JFrog捷蛙)并访问官方网站(https://www.jfrogchina.com/)来了解有关漏洞的最新消息。如需了解有关我们的安全解决方案的更多信息,请随时进行在线参观(https://www.jfrogchina.com/security-and-compliance/)或预订一对一演示(https://www.jfrogchina.com/platform/schedule-a-demo/)。
成功
感谢您提交申请,我们稍后会与您取得联系!
哎哟... 出了点问题
请稍后再试
Information
Modal Message