0day CVE-2023-4863 WebP图片格式缓冲区溢出漏洞 POC

admin 2023年9月24日23:30:46评论527 views字数 9272阅读30分54秒阅读模式

CVE-2023-4863 WebP图片格式缓冲区溢出漏洞POC公开,除苹果、安卓、Windows等操作系统外,使用webp组件的软件均受影响。


0day CVE-2023-4863 WebP图片格式缓冲区溢出漏洞 POC

解开时间线

Chrome 安全更新发布后,专家立即开始猜测CVE-2023-4863 与 Apple 的早期 CVE CVE-2023-41064 之间存在联系。这个理论是这样的。

9 月初(具体日期未知),Citizen Lab 在 iPhone 上检测到“华盛顿特区民间社会组织雇用的个人”的可疑行为:

BLASTPASS:NSO Group iPhone 零点击、零日漏洞在野外捕获

他们将此行为归因于 iMessage 的“零点击”漏洞,该漏洞被用来部署 NSO 组织的 Pegasus 间谍软件,并将他们的技术发现发送给了 Apple。Apple 迅速做出了反应,并于 9 月 7 日发布了一份安全公告,其中包含来自 Citizen Lab 发现的攻击的两个新 CVE。他们在每个 CVE 上都指出:“ Apple 已获知一份报告称此问题可能已被积极利用。 ”

公民实验室将这次攻击称为“BLASTPASS”,因为攻击者找到了绕过“ BlastDoor ”iMessage 沙箱的巧妙方法。我们没有完整的技术细节,但看起来通过将图像漏洞捆绑在PassKit附件中,恶意图像将在不同的非沙盒进程中进行处理。这对应于 Apple 发布的第一个 CVE CVE-2023-41061。

但您仍然需要图像漏洞来利用这种情况,事实上,Apple 发布的第二个 CVE 是 CVE-2023-41064,这是 ImageIO 中的缓冲区溢出漏洞。ImageIO是Apple的图像解析框架。它将采用字节序列并尝试将字节与合适的图像解码器进行匹配。支持多种不同的格式,ImageIO 一直是安全研究的活跃 领域。我们尚无有关 CVE-2023-41064 的任何技术细节,因此我们不知道它会影响哪种图像格式。

但我们确实知道 ImageIO 最近开始支持 WebP 文件,并且我们知道在 9 月 6 日(iOS/macOS 安全公告的前一天),苹果安全团队向 Chrome 报告了一个 WebP 漏洞,并紧急修补了该漏洞(就在 5 天后)最初的报告)并被谷歌标记为“在野外利用”。基于此,BLASTPASS 漏洞和 CVE-2023-4863(“WebP 0day”)很可能是同一个错误。

WebP 0day——技术分析

通过交叉引用 Chrome 安全公告中的 bug ID 与最近对 libwebp 库代码的开源提交,可以找到以下补丁:

修复 BuildHuffmanTable 中的 OOB 写入

该补丁创建于 9 月 7 日(Apple 报告后一天),对应 CVE-2023-4863。根据对该补丁的初步审查,我们了解到以下内容:

  • 该漏洞存在于对 WebP(有时称为 VP8L)的“无损压缩”支持中。无损图像格式可以以 100% 的精度存储和恢复像素,这意味着图像将以完美的精度显示。为了实现这一点,WebP 使用一种称为霍夫曼编码的算法。

  • 尽管霍夫曼编码在概念上基于树数据结构,但现代实现已优化为使用表。该补丁表明,在解码不受信任的图像时,霍夫曼表可能会溢出。

  • 具体来说,易受攻击的版本使用基于固定表中预先计算的缓冲区大小的内存分配,然后将霍夫曼表直接构造到该分配中。新版本执行“第一遍”构造,计算输出表所需的总大小,但实际上并不将表写入缓冲区。如果总大小大于预先计算的缓冲区大小,则进行更大的分配。

这是一个很好的开始,但它没有建设性。我们希望能够构建一个实际上可以触发溢出的示例文件,为此我们必须了解这段代码实际上是如何工作的以及为什么预先计算的缓冲区大小不够。

退一步来说,易受攻击的代码实际上在做什么?当以无损方式压缩 WebP 图像时,将对输入像素执行频率分析。基本思想是,出现频率较高的输入值可以分配给较短的输出位序列,出现频率较低的输入值可以分配给较长的输出位序列。真正的技巧是巧妙地选择输出位,以便解码器始终可以计算出该特定序列的长度 - 即始终可以消除 2 位代码和 3 位代码之间的歧义,依此类推,因此解码器总是知道要消耗多少位。

为了实现这一点,压缩图像必须包括有关频率和代码分配的所有统计信息,以便解码器可以再现代码和值之间的相同映射。如前所述,webp 内部为此使用一个表(他们称之为“huffman_table”)...但表本身可能非常大,将它们与压缩图像一起包含会使文件大小增加。解决方案是使用霍夫曼编码来压缩表。一路下来都是乌龟。

这意味着分析/触发错误需要大量的心理练习。根据对补丁的审查,我们可以隔离最有可能溢出的内存分配并制定计划。

我们试图溢出 ReadHuffmanCodes (src/dec/vp8l_dec.c) 中的 huffman_tables 分配,其想法是使用 ReadHuffmanCode 中的 VP8LBuildHuffmanTable/BuildHuffmanTable 调用(而不是 ReadHuffmanCodeLengths 中的调用)来将 huffman_table 指针移过 pre-计算的缓冲区大小。为了增加复杂性,霍夫曼表实际上有 5 个不同的部分,每个部分都有不同的字母大小(例如表的该特定部分的可能输出符号的数量)——我们可能必须精心设计所有 5 个部分这些足够接近缓冲区末尾以导致溢出。

此时,我已经提出了如何继续的基本理论,并开始手动制作一个可以深入到代码的文件事实证明,他们也一直在尝试重现这个问题,并且他们构建了工具代码来创建具有任意霍夫曼编码数据(“代码长度”)的格式良好的 WebP。我尝试了一下,效果非常好,我们可以将任意 code_lengths 数组传递到我们目标的 BuildHuffmanTable 调用中。杰出的。

现在的挑战是找到一组 code_lengths 使 BuildHuffmanTable 超过预先计算的缓冲区大小。我开始进行一些手动实验 - 更改 code_lengths 数组以影响内部直方图(本质上是 BuildHuffmanTable 中的计数数组),然后观察 16 个直方图条目中的每一个对总大小(我们需要增加到的关键变量)的影响大于预期值。

很快我们就发现,直方图的起始状态、树统计信息(num_open 和 num_nodes)以及跟踪“ReplicateValue”操作起始位置的“key”变量之间存在着复杂的交互作用,该操作将条目写入到输出表中我们正试图溢出。它让我想起了观察加密哈希函数的内部状态,并且在不了解更多关于霍夫曼树和 WebP 的具体实现选择的情况下,我没有信心能够手动制作一个输入,甚至可以是BuildHuffmanTable 认为是正确的,更不用说使 BuildHuffmanTable 返回意外大的值了。

我的下一个想法是暴力解决方案。我注意到直方图中的前 9 个条目(例如 count[0] .. count[8],称为“根表”)不会对总大小产生太大影响,但可能会影响内部状态后续计算(例如将节点数量推得太高)。直方图中的最终条目(例如count[9] .. count[15],称为“第二级表”)对最终total_size 值有直接影响。考虑到这一点,我创建了一些不同的统计分布,这些分布通常使根表的值保持较低(通常总和小于 8),而二级表的值较高。这种方法设法找到正确的输入,其中一些导致输出表非常大,

我决定需要了解预先计算的尺寸是如何得出的。实际上有几个不同的预先计算的大小桶,具体取决于指定的颜色缓存位数。这些存储桶在 kTableSize 中定义,其中包括对值的有用描述和宝贵的提示:“使用 Mark Adler 的工具计算 8 位第一级查找的所有值:   https ://github.com/madler/zlib/blob/ v1.2.5/examples/enough.c "

对于任何给定的字母大小、根表大小和最大代码长度,“足够”工具会生成最大可能的霍夫曼树查找表的直方图。使用 Mark Adler 的工具,我可以复制预先计算的缓冲区大小,并使用@mistymntncop的工具,我可以验证“足够”发出的特定 code_lengths 是否会 100% 填充 huffman_tables 分配。这很好,但是堆溢出的整个想法是将分配填充到 101%...

我在这里遇到了一个死胡同,即“足够”的工具仅适用于最大 8 位的 color_cache 大小。他们如何得出 9 位、10 位或 11 位缓存的值(所有这些都被认为是有效的)?也许他们只是猜测而这些值是错误的?我认为 Google 必须修改了“足够”才能处理更大的字母大小,因为我通过对“足够”进行一些微小的更改(例如使用 128 位整数标量类型编译器扩展来能够计数)来复制他们的数字没有溢出的树的数量)。

此时,有一个漫长的焦虑过程。“足够”工具在其文档中明确指出,它计算有效且完整的代码的最大值此输入直方图必须进行某种配置,以生成 WebP 认为有效且完整的树,但实际上不完整/无效,从而产生比预期更大的扩展。该补丁甚至暗示了这个方向,说:“确保有效(但由于不平衡代码而未优化)流仍然是可解码的”

最后,我设法说服自己,通过枚举最小表(符号大小为 40)中所有可能的有效树,这是不可能的,这也恰好是我们需要的 5 个表中的最后一个。充满。符号大小为 40、根表为 8 位且最大代码长度为 15 的符号的最大大小是 410。如果您可以生成大于 410 的任何值,那么您就赢了。但是 BuildHuffmanTable 认为有效的代码没有一个大小大于 410(而且大多数都小得多)。看起来 BuildHuffmanTable 末尾的一致性检查(例如检查输出节点的数量是否为预期值)是确保它接受的代码符合“足够”以及它给出的预先计算的缓冲区大小。

但是 BuildHuffmanTable 函数正在使用前面提到的“ReplicateValue”操作将值写入输出表。如果我们构建 4 个有效的霍夫曼树,产生 4 个最大大小的输出表,然后为最后一个表提供一个无效的霍夫曼树,会怎么样?在对节点计数进行最终一致性检查之前,我们能否让 ReplicateValue 从无效的起始键写入越界内容?答案是:是的,我们可以。

以下是复制该错误的方法:

  # checkout webp
$ git clone https://chromium.googlesource.com/webm/libwebp/ webp_test
$ cd webp_test/
# checkout vulnerable version
$ git checkout 7ba44f80f3b94fc0138db159afea770ef06532a0
# enable AddressSanitizer
$ sed -i 's/^EXTRA_FLAGS=.*/& -fsanitize=address/' makefile.unix
# build webp
$ make -f makefile.unix
$ cd examples/
# fetch mistymntncop's proof-of-concept code
$ wget https://raw.githubusercontent.com/mistymntncop/CVE-2023-4863/main/craft.c
# build and run proof-of-concept
$ gcc -o craft craft.c
$ ./craft bad.webp
# test trigger file
$ ./dwebp bad.webp -o test.png
=================================================================
==207551==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x626000002f28 at pc 0x56196a11635a bp 0x7ffd3e5cce90 sp 0x7ffd3e5cce80
WRITE of size 1 at 0x626000002f28 thread T0
#0 0x56196a116359 in BuildHuffmanTable (/home/isosceles/source/webp/webp_test/examples/dwebp+0xb6359)
#1 0x56196a1166e7 in VP8LBuildHuffmanTable (/home/isosceles/source/webp/webp_test/examples/dwebp+0xb66e7)
#2 0x56196a0956ff in ReadHuffmanCode (/home/isosceles/source/webp/webp_test/examples/dwebp+0x356ff)
#3 0x56196a09a2b5 in DecodeImageStream (/home/isosceles/source/webp/webp_test/examples/dwebp+0x3a2b5)
#4 0x56196a09e216 in VP8LDecodeHeader (/home/isosceles/source/webp/webp_test/examples/dwebp+0x3e216)
#5 0x56196a0a011b in DecodeInto (/home/isosceles/source/webp/webp_test/examples/dwebp+0x4011b)
#6 0x56196a0a2f06 in WebPDecode (/home/isosceles/source/webp/webp_test/examples/dwebp+0x42f06)
#7 0x56196a06c026 in main (/home/isosceles/source/webp/webp_test/examples/dwebp+0xc026)
#8 0x7f7ea8a8c082 in __libc_start_main ../csu/libc-start.c:308
#9 0x56196a06e09d in _start (/home/isosceles/source/webp/webp_test/examples/dwebp+0xe09d)
0x626000002f28 is located 0 bytes to the right of 11816-byte region [0x626000000100,0x626000002f28)
allocated by thread T0 here:
#0 0x7f7ea8f2d808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x56196a09a0eb in DecodeImageStream (/home/isosceles/source/webp/webp_test/examples/dwebp+0x3a0eb)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/isosceles/source/webp/webp_test/examples/dwebp+0xb6359) in BuildHuffmanTable
...

实际上,有很多这样的输入会溢出 huffman_tables。我发现代码长度导致写入超过 huffman_tables 分配末尾 400 个字节。即使仅部分控制所写入的值,它看起来也绝对是可利用的。要利用此问题,您可能需要使用颜色缓存位(或 num_htree_groups)来获取大致页面对齐的 huffman_tables 分配,但这应该不是问题。可能还有其他方法可以导致 huffman_tables 分配上的 OOB 写入,但此方法看起来是可接受的方法。

无效输入本身是很不寻常的——mistymntncop 提供了它使用他们编写的帮助分析的工具创建的霍夫曼树的以下可视化:

0day CVE-2023-4863 WebP图片格式缓冲区溢出漏洞 POC

如果放大,您可以看到树是部分不平衡的,并且不平衡分支的一部分有大量内部节点,其中根本没有子节点。这种结构会产生有效树永远无法到达的“键”索引。有效的树如下所示:

0day CVE-2023-4863 WebP图片格式缓冲区溢出漏洞 POC

至于补丁,它似乎几乎是偶然起作用的。如前所述,修补版本首先使用 BuildHuffmanTable 来计算所需的总大小。实际上,此问题已得到修补,因为对于所有无效输入,BuildHuffmanTable 都会失败(返回 0),否则会导致越界写入,并且由于第一遍明确不写入表,因此不会无效树被部分处理并不重要。换句话说,我认为补丁会根据需要动态增加缓冲区的大小以防止堆溢出,但实际上它只是拒绝会导致堆溢出的输入。这绝对很难推理,但我搜索了仍然会触发此溢出的“有效且完整”的代码,但我找不到任何代码。

早期发现?

Chrome 安全更新后,立即出现了一些关于模糊测试的讨论。由 C 代码库实现的二进制文件格式是模糊测试的理想目标——那么为什么没有更早地发现这个错误呢?图书馆的模糊程度还不够吗?或者它没有被模糊化吗?

Google 的 OSS-Fuzz 项目多年来已经对数百个开源库进行了模糊测试,其中包括 libwebp 和许多其他图像解码库。可以详细查看 OSS-Fuzz 项目的代码覆盖率,并且很明显,对 WebP 的无损支持正在被广泛模糊:

0day CVE-2023-4863 WebP图片格式缓冲区溢出漏洞 POC

我们现在知道,问题在于这种格式极其复杂和脆弱,而且触发这个问题的先决条件是巨大的。在数十亿种可能性中,我们必须构建一个由 4 个有效霍夫曼表组成的序列,这些表的最大大小适合两种不同的字母大小(280 和 256),然后再为第三种字母大小(40)构建非常特定类型的无效霍夫曼表。如果在任何阶段有一位出现错误,图像解码器就会抛出错误,并且不会发生任何不良情况。

事实上,在修复 WebP 0day 后,Google 做的第一件事就是专门针对 WebP 中的霍夫曼例程发布了一个新的模糊器。我尝试运行这个模糊器一段时间(由于 API 更改,需要进行一些反向移植),可以预见的是,它没有找到 CVE-2023-4863。

也许我错了,一些涉及符号执行的新技术(如 Quarkslab 的TritonDSE)能够解决这个问题——但是基于位翻转突变和代码覆盖反馈循环的标准方法,甚至是稍微复杂一点的方法,如CmpLog(输入到状态),将无法通过所有这些中间步骤来达到这种极其悲观的状态。

将此错误与早期的漏洞(FreeType 中的Load_SBit_Png错误)进行对比是很有趣的,该漏洞也是在高级 0day 漏洞中“野外”发现的。它类似于用 C 编写的二进制文件格式(在本例中为字体)的公共库中的堆溢出,它类似于它影响 Chrome,并且它类似于 FreeType 在这次袭击发生前的几个月和几年。不同之处在于,在模糊测试期间没有发现 Load_SBit_Png 错误是由于缺乏足够的利用,而不是由于漏洞的某些特定限制而导致模糊测试变得困难。如果模糊测试工具已提前更新以更好地反映 API 的使用情况,

WebP 0day (CVE-2023-4863) 的情况并非如此——除非您非常幸运,您的模糊测试语料库中有一个文件已经非常接近该错误,并且您的模糊测试器在以下方面进行了很好的校准其突变率。

在实践中,我怀疑这个错误是通过手动代码审查发现的。在查看代码时,您会看到在 VP8L 文件的标头解析期间进行 huffman_tables 分配,因此您自然会查看它是如何使用的。然后,您将尝试合理化 huffman_tables 分配缺乏边界检查的情况,如果您足够坚持,您将逐渐深入问题,然后意识到代码被巧妙地破坏了。我怀疑大多数代码审计员并不是那么执着——霍夫曼代码的东西令人费解——所以我印象深刻。

有什么大不了的

有一些好消息,也有一些坏消息。

✓ 好消息是,公民实验室的团队再次出色地捕捉到了在野外使用的顶级漏洞。他们与最有可能受到漏洞利用的组织和个人建立了很大的信任。这是非常令人印象深刻的。

✗ 坏消息是,此类漏洞继续产生社会影响,我们只能猜测情况到底有多糟糕。事实是,没有人确切知道,即使是那些有功绩的人。

✓ 好消息是,Apple 和 Chrome 在以应有的紧迫性回应这一问题方面做得非常出色。看起来这两个组织在短短几天内就向其数十亿用户推出了更新。这是一项令人印象深刻的壮举,需要跨威胁分析、安全工程、软件工程、产品管理和测试团队付出令人难以置信的努力和协调,才能使这一切成为可能。

✗ 坏消息是 Android 仍然可能受到影响。与Apple的ImageIO类似,Android有一个名为BitmapFactory的工具来处理图像解码,当然也支持libwebp。截至今天,Android 尚未发布包含 CVE-2023-4863 修复程序的安全公告 - 尽管该修复程序已合并到 AOSP 中。综上所述:如果这个错误确实影响 Android,那么它可能会变成 Signal 和 WhatsApp 等应用程序的远程攻击。我预计它会在 10 月份的公告中得到修复。

✓ 好消息是,该错误似乎已在上游 libwebp 中得到正确修补,并且该修补程序正在传播到它应该到达的任何地方。

✗ 坏消息是 libwebp 在很多地方都被使用,补丁可能需要一段时间才能达到饱和。此外,代码仍然很难推理,我们不能依靠模糊器来找到潜伏在这里的任何其他错误。

最后的想法

WebP 0day (CVE-2023-4863) 是广泛使用的开源库中的一个微妙但强大的漏洞,高度暴露于攻击者的输入。它既很难模糊测试,也很难手动触发——但其好处是可在多个浏览器、操作系统和应用程序上运行的可利用堆溢出。CVE-2023-4863 很可能与BLASTPASS攻击中使用的漏洞相同

我在上周发布关于 Phineas Fisher 的博客文章后不久就开始了这项技术分析,这意味着我迟到了几天。实际上,花了大约 3 个完整工作日的时间(在@mistymntncop的大量额外帮助下)来找出错误并构建重现测试用例。

由于供应商缺乏可用的技术信息,验证变得非常困难,而且谁真正受益还值得怀疑。攻击者显然非常积极地跟踪和利用 Nday 漏洞,并且缺乏发布的技术细节不会显着减缓他们的速度。另一方面,很少有防守者有能力执行我今天分享的技术分析类型。这是违反直觉的,但隐瞒了这些攻击如何以不对称方式进行的基本技术细节,这对攻击者最有利——你很快就会陷入这样一种情况:攻击者可以获得有关防御者所没有的漏洞/利用的见解。

这个错误还表明我们过度依赖模糊测试来保证复杂解析器代码的安全性。模糊测试很棒,但我们知道有许多严重的安全问题不容易模糊测试。对于像图像解码(零点击远程利用攻击面)这样的敏感攻击面,需要 1) 在主动源代码审查方面进行更大的投资,2) 重新关注确保这些解析器被充分沙箱化。


https://github.com/mistymntncop/CVE-2023-4863

https://blog.isosceles.com/the-webp-0day/

原文始发于微信公众号(TtTeam):0day CVE-2023-4863 WebP图片格式缓冲区溢出漏洞 POC

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年9月24日23:30:46
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   0day CVE-2023-4863 WebP图片格式缓冲区溢出漏洞 POChttps://cn-sec.com/archives/2064492.html

发表评论

匿名网友 填写信息