如何检测WebP文件中的BLASTPASS漏洞

本文分析了WebP图像格式中的安全漏洞,尤其是CVE-2023-4863,影响了浏览器和消息应用。作者探讨了RIFF结构、VP8L压缩及哈夫曼编码在WebP中的作用,同时强调了内存安全和锁定模式在防范此类漏洞中的重要性。
摘要由CSDN通过智能技术生成

作者:Matt Suiche 翻译:Doris Liu 转载请注明

介绍

压缩算法再一次向我们展示了它们正在统治互联网。我最初接触压缩算法是在2007年,当时我正在逆向Windows休眠文件,以重新实现现在众所周知的微软LZXpress算法。后来我发现直到今天微软的大多数产品都在使用这种压缩算法。今天,我们将继续研究开源 Libwebp库中的 CVE-2023-4863漏洞,该漏洞不仅会影响Mozilla、Chrome和Edge 等基于Chromium的浏览器,还会影响iMessage等消息应用程序。另外,苹果和谷歌最近也解决了libvpx中的堆缓冲区溢出CVE-2023-5217,这是WebM的VP8视频编码器,是我们今天讨论的WebP格式的姊妹项目。

在我们深入探讨时,有必要了解一下当前的形势,复杂的攻击已经超越了传统的模式。目前,向非北约成员销售的经纪商对iOS和Android上的全链RCE漏洞利用估价高达2,000万美元,这凸显了强大的防御机制(如移动设备检测工程)的极端重要性,以及推动行业超越典型日志解析和基于正则表达式搜索的必要性。

我们之前深入研究了通过iMessage传播的FORCEDENTRY漏洞之后,现在是时候关注一下 BLASTPASS了,这是CitizenLab在野外发现的另一个令人震惊的全链iOS漏洞,苹果公司在CVE-2023-41064下对其进行了处理,并推测它与CVE-2023-4863相关联。通过仔细研究发现,未经授权的数据现在可以写入超出内存分配限制的内容,为潜在的恶意活动创造了条件。

这与苹果公司早先的CVE-2023-41064漏洞有着明显的联系,需要对这些相互交织的漏洞进行彻底检查和了解。随着我们层层剥开,"WebP 0day "漏洞脱颖而出,它可能是与BLASTPASS漏洞相关联的同一漏洞,这为防御研究提供了一个途径,也为我们提供了一个机会来增强我之前发布的基于文件的检测ELEGANTBOUNCER的能力检测。

文件格式

RIFF

资源交换文件格式(Resource Interchange File Format,简称RIFF)是一种通用文件容器格式,用于以标记段或块的形式存储数据。虽然主要用于音频和视频文件,但其灵活的结构可容纳各种数据类型。

1991年,微软和IBM推出RIFF格式,标志着它成为Windows 3.1中多媒体文件的标准格式,这是受早期Electronic Arts于1985年为Amiga平台开发的交换文件格式的影响。随着时间的推移,RIFF格式已成为AVI、ANI和WAV等各种容器格式的基础,显示了其适应性和广泛的应用。

转眼到了2010年,谷歌发布了WebP图像格式,并将RIFF作为其首选容器。这一时刻至关重要,因为WebP成为JPEG、PNG 和GIF等成熟图像格式的有力的替代品,它支持有损和无损压缩,并具有动画和Alpha透明度等功能。

WebP

在这次探索中,我们将聚焦WebP格式。谷歌推出WebP的目的是取代现有的图像格式,承诺采用增强型压缩算法,确保在缩小文件大小的同时实现高质量的视觉效果。

RIFF在这种格式中的作用至关重要,它将WebP数据封装在不同的块中,并保持图像数据的完整性和质量。这一强大的框架为谷歌在2010年9月宣布WebP以及随后在2018年4月发布其支持程序库的稳定版本铺平了道路。

WebP Lossless是一种专为无损压缩ARGB图像而设计的图像格式。这种格式保证了像素值的准确存储和恢复,包括 Alpha 值为 0 的像素的颜色值。WebP Lossless采用子分辨率图像,递归地嵌入到格式中。这些图像保存了有关主图像的重要统计数据,包括熵编码、空间预测器以及色彩空间转换和色彩表等色彩相关信息。

WebP Lossless采用LZ77、前缀编码和颜色缓存来处理批量数据的压缩。这些技术提高了WebP Lossless的效率,解码速度比PNG更快,压缩密度比现代PNG格式提高了25%。

VP8L

本节概述了WebP无损图像中的压缩数据表示。它深入探讨了有助于有效压缩和准确重建 WebP无损格式图像的具体组件和方法。要全面了解WebP无损图像压缩的内部工作原理和优势,这一研究是必不可少的。

资源交换文件格式(RIFF)是一种通用文件容器格式,可将数据分块存储。在WebP图像格式领域,RIFF包含多个数据块,包括WebP数据块。不过,数据提取的重点在于压缩数据块下面的比特流,特别是VP8(有损压缩)和VP8L(无损压缩)数据块。这些数据块包含单帧的压缩比特流数据。

分类:比特流数据块可能有两种不同的形式

  1. VP8 数据块:以标签 "VP8"标识(第四字符有明显的空格)。
  2. VP8L数据块:以标签 "VP8L"标识。

在本文中,我们只关注VP8L数据块。

VP8L数据块中的大部分数据都使用规范前缀码编码,即通常所说的哈夫曼编码。这种编码策略涉及前缀码长度的传输,而不是实际的前缀码本身。这种格式的一个显著特点是利用空间变异前缀编码。这种方法允许不同的图像块使用不同的熵编码。

该格式概述了两种前缀编码长度的编码方法论,由单个比特值定义:

  • 如果该位为 1:则表示简单的代码长度码。
  • 如果该位为 0:则表示标准代码长度码。无论采用哪种方法,格式都允许码流中存在未使用的码长。

本讨论将围绕标准代码长度码展开。在这里,码长使用前缀码编码,因此必须先读取下级码长(code_length_code_lengths)

读取编码长度后会根据每种符号类型(A、R、G、B、distance)各自的字母大小,为其生成特定的前缀码:

  • G 通道:计算公式为 256 + 24 + color_cache_size
  • 其他字母(A、R、B):恒定为 256
  • 代码距离:恒定为40

每个元编码使用五个哈夫曼编码:

1.green + length prefix codes + color cache codes

2.alpha

3.red 

4.blue

5.distance prefix codes. 

这一计算有助于确定字母表大小(kAlphabetSize),以及哈夫曼树组的查找表大小(kTableSize)红色、蓝色、透明度和字母距离的常量值及其对应的查找表大小如下:

  • 红,蓝,透明度:256
  • 字母距离:40
  • 查找表大小:在最坏情况下,分别为 630 和 410

绿色字母表的大小取决于色彩缓存的大小,计算公式为 256(绿色成分值)+ 24(长度前缀值)+ 色彩缓存大小(范围在 0 到 2048 之间)。

如需了解更多技术知识,请参阅Mark Adler的工具,深入了解8位一级查找值:Mark Adler的工具。

#define FIXED_TABLE_SIZE (630 * 3 + 410)static const uint16_t kTableSize[12] = {
  FIXED_TABLE_SIZE + 654,
  FIXED_TABLE_SIZE + 656,
  FIXED_TABLE_SIZE + 658,
  FIXED_TABLE_SIZE + 662,
  FIXED_TABLE_SIZE + 670,
  FIXED_TABLE_SIZE + 686,
  FIXED_TABLE_SIZE + 718,
  FIXED_TABLE_SIZE + 782,
  FIXED_TABLE_SIZE + 912,
  FIXED_TABLE_SIZE + 1168,
  FIXED_TABLE_SIZE + 1680,
  FIXED_TABLE_SIZE + 2704};(...)
#define HUFFMAN_CODES_PER_META_CODE  5
#define NUM_LITERAL_CODES            256
#define NUM_LENGTH_CODES             24
#define NUM_DISTANCE_CODES           40
static const uint16_t kAlphabetSize[HUFFMAN_CODES_PER_META_CODE] = {
  NUM_LITERAL_CODES + NUM_LENGTH_CODES,
  NUM_LITERAL_CODES, NUM_LITERAL_CODES, NUM_LITERAL_CODES,
  NUM_DISTANCE_CODES};

错误

溢出的哈夫曼表 huffman_tables 是在 ReadHuffmanCodes() 中根据两个主要参数分配的:

  1. 哈夫曼树组的数量。
  2. 根据 color_cache_size(在我们的示例中等于零)的存在,如上所述确定一个固定的表大小。
huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
                                                sizeof(*huffman_tables));

稍后在偏移量offsethuffman_tables + (num_htree_groups * table_size)处读取哈夫曼编码比特流时,将出现越界写入。

Ben-Hawkes和 mistymntncop分享的长度代码引发的溢出是在解析距离通道第二级表时触发的,该表的最大大小为410。

当在 BuildHuffmanTable() 函数中调用 ReplicateValue() 时,表中使用的索引超出绑定范围,就会发生越界范围的写入。

 idx++;
    ReplicateValue(&table[key >> root_bits], step, table_size, code);
    key = GetNextKey(key, len);

测试

恶意的代码距离长度会产生不平衡的哈夫曼树;检测它的直接方法是通过模拟 BuildHuffmanTable() 的行为来确保写入是在huffman_tables的边界内进行的,就像我们通过 is_code_lengths_count_valid() 所做的那样。

在我们的代码中,我们会评估每个通道的长度(绿色、红色、蓝色、透明度和距离),并确保写入没有超出其边界。

 if table_off + (key >> root_bits) + (table_size - step) >= max_table_size {
        debug!("OVERFLOW!!!!!!! (offset = 0x{:x})", table_off + (key >> root_bits) + (table_size - step));
        has_overflow = true;
    }

给定查找表的最大尺寸(max_table_size)取决于两点:色彩通道比特数(color_channel_bits)和通道本身。就通道距离而言,该值为 410。

 let max_table_size = match j {
        0 => K_TABLE_SIZE[color_cache_bits as usize] - FIXED_TABLE_SIZE,
        1 | 2 | 3 => MAX_RBA_TABLE_SIZE,
        4 => MAX_DISTANCE_TABLE_SIZE,
        _ => panic!("Unhandled idx value: {}", j),
};

考虑到设计,这可能意味着其他通道的代码长度也可能被用来溢出哈夫曼查找表,而我们要确保每个通道查找表的边界。

建议

具有讽刺意味的是,WebP 规范确实(毫不奇怪)有如下警告:

这种格式的实现面临着整数溢出、越界读取以及向堆和栈写入等安全风险。

这加强了Rust等内存安全语言对文件解析库的长期价值。与此同时,尽管许多此类库仍使用 C/C++编写,但事实上它们肯定会导致错误。

如果你认为自己有受到此类攻击的风险,强烈建议你启用苹果的锁定模式。激活后,锁定模式会改变各种应用程序和功能的功能,包括:

  1. Messages: 锁定模式限制大多数信息附件,只允许特定的图像、视频和音频文件。此外,链接和链接预览等功能也会被禁用。
  2. Web浏览: 该模式会阻止某些高级的网络技术,可能导致某些网站加载时间变慢或无法运行。在该模式下,网页字体可能无法显示,图像可能会被丢失的图像图标替代。

这一点尤为重要,因为它可以阻止对图像等各种资源的处理和预处理,从一开始就防止触发此类错误。

作者:Matt Suiche 翻译:Doris Liu 转载请注明

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值