深入剖析Curl TFTP实现中的堆缓冲区溢出漏洞

本文详细披露了一个在libcurl的TFTP实现中发现的堆缓冲区溢出漏洞。该漏洞源于恶意TFTP服务器发送超规格OACK数据包后,客户端缓冲区未重新分配,可能导致远程代码执行或拒绝服务攻击。

Heap Buffer Overflow in TFTP | Report #3444904

报告提交者:helspy 提交报告至 curl。 提交时间:5天前

摘要

libcurl的TFTP实现中存在一个堆缓冲区溢出漏洞。当恶意的TFTP服务器发送一个包含大于默认块大小(512字节)的blksize选项的OACK(选项确认)数据包时,会触发此漏洞。libcurl更新了其内部的块大小变量,但未能重新分配接收和发送缓冲区(rpacket和spacket)。当应用程序随后使用更大的块大小接收数据(在tftp_rx中)或发送数据(在tftp_tx中)时,会写入超出已分配缓冲区的末尾,导致堆缓冲区溢出。

受影响版本

  • curl 8.18.0-DEV(基于 include/curl/curlver.h 中的 LIBCURL_VERSION)
  • 平台:Windows(已复现)

重现步骤

  1. 将提供的重现脚本保存为 tftp_repro.py
  2. 运行脚本:python tftp_repro.py。这将启动一个在端口6969上运行的恶意TFTP服务器。
  3. 在另一个终端中,运行curl命令从该服务器获取文件:curl tftp://localhost:6969/test(注意:确保使用的curl构建版本包含此易受攻击的代码。如果使用系统curl进行测试,它可能不易受攻击或可能是不同版本)。
  4. 服务器将发送一个blksize=2048的OACK,然后是一个2048字节的DATA数据包。
  5. 由于堆溢出,curl客户端将崩溃或表现出未定义行为。

支持材料/参考

  • 易受攻击的代码位置lib/tftp.c,函数:tftp_parse_option_ack
    • 更新了 state->blksize 但没有重新分配 state->spacket.datastate->rpacket.data
  • 重现脚本tftp_repro.py

影响

摘要:此漏洞允许恶意的TFTP服务器在客户端上引发堆缓冲区溢出。

  • 远程代码执行(RCE):通过精心构造DATA数据包中的有效负载,攻击者可以覆盖关键的堆元数据或函数指针,可能在被攻击者的机器上以curl进程的权限执行任意代码。
  • 拒绝服务(DoS):溢出可能破坏内存结构,导致curl应用程序崩溃或行为不可预测,从而导致拒绝服务。

事件时间线

bagder (curl 工作人员) 发表了评论。 5天前

感谢您的报告! 我们将花一些时间调查您的报告,并尽快给您回复详细信息以及可能的后续问题!很可能在接下来的24小时内。 我们始终致力于尽快修复报告的问题。严重性为低或中等的问题,我们会将其合并到普通发布周期中的下一个版本。只有对于更严重的问题,我们可能会提前发布修复。

bagder (curl 工作人员) 发表了评论。 5天前

@helspy 没有附带 tftp_repro.py 脚本吗?

helspy 发表了评论。 5天前

抱歉!这是程序…

 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
import socket
import struct

PORT = 6969
blksz= 2048
def start_server():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind(('0.0.0.0', PORT))
    print(f" server started on port {PORT}")
    while True:
        data, addr = sock.recvfrom(1024)
        print(addr)
        opcode = struct.unpack('!H', data[:2])[0]

        if opcode == 1 or opcode == 2:
            print("Sending oack")
            oack = struct.pack('!H', 6) + b'blksize\0' + str(blksz).encode() + b'\0'
            sock.sendto(oack, addr)
            if opcode == 1:
                print("sending data packet")
                payload = b'A' * blksz
                data_pkt = struct.pack('!HH', 3, 1) + payload
                sock.sendto(data_pkt, addr)
if __name__ == "__main__":
    start_server()

helspy 发表了评论。 4天前

似乎在 tftp_parse_option_ack 中,当服务器发送新的块大小时,代码检查:

1
2
3
4
if(blksize > state->requested_blksize) {
    failf(data, "server requested blksize larger than allocated");
    return CURLE_TFTP_ILLEGAL;
}

此检查强制客户端使用大于最初分配的块大小,因此可能防止堆溢出。 我在编写报告(提交过早)的同时并行尝试重现,这是一个错误,因此这个问题。抱歉,您可以关闭这个问题。

bagder (curl 工作人员) 关闭了报告并将状态更改为“不适用”。 4天前

被认为不是一个安全问题。

bagder (curl 工作人员) 请求披露此报告。 4天前

根据项目的透明度政策,我们希望所有报告都被披露并公开。

bagder (curl 工作人员) 披露了此报告。 3天前

报告日期: 2025年11月29日,UTC时间下午5:06 报告者: helspy 报告对象: curl 报告ID: #3444904 严重程度: 严重(9 ~ 10) 披露日期: 2025年12月1日,UTC时间上午7:41 弱点: 堆溢出 CVE ID: 无 赏金: 无 账户详情: 无

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