天天看点

Chrome PDFium 整数截断漏洞分析

作者:刘科

chromium:697847 是 PDFium 里面由于 整数截断 引起的一个堆溢出漏洞(将 <code>unsigned long</code> 赋值给<code>uint32</code>),简单记录一下。

漏洞原理:

PDFium 使用 zlib 的 <code>inflate</code> 接口解压数据;

在 zlib 中,解压后的数据的大小使用 <code>unsigned long</code>类型的变量 <code>total_out</code>来存储;

PDFium 使用 <code>uint32</code> 类型的变量来接收 <code>total_out</code> 的值;

在 64 位环境中,当解压后的数据大小超过 4GB 时(即超过<code>uint32</code>的范围)会产生截断;

后续 PDFium 使用截断后的值分配堆块并拷贝解压后的数据,导致了堆溢出;0x02. 漏洞分析

在 64 位 Ubuntu 上开启 <code>AddressSanitizer</code> 编译 PDFium,使用编译出来的 <code>pdfium_test</code>测试原贴提供的 PoC 文件,可以看到如下崩溃信息(已简化):

可以看出这里出发了堆溢出行为,目标堆块的大小只有 1 字节(<code>[0x60200000ecd0,0x60200000ecd1)</code>),而程序尝试通过 <code>memcpy</code>往堆块上写入大量数据。总结如下:

<code>memcpy</code>调用位于 <code>FlateUncompress</code> 函数 (<code>core/fxcodec/codec/fx_codec_flate.cpp</code>的第 <code>603</code> 行);

堆块的分配操作同样位于 <code>FlateUncompress</code>函数(<code>fx_codec_flate.cpp</code> 的第 <code>595</code> 行);2.2 POC 分析

原贴提供的 PoC 文件十分简单:4 号 <code>obj</code> 包含 <code>0x3FB2B2</code> 字节数据,<code>/Filter</code>的值为 <code>/FlateDecode</code>,即数据使用了 <code>zlib/deflate</code> 算法进行压缩,需要使用 <code>zlib/inflate</code>算法进行解压缩。

先来看一下 zlib 在解压数据时需要用到的关键结构<code>z_stream</code>(注意这里 <code>total_out</code> 的类型为<code>unsigned long</code>):

在调用 zlib 的<code>inflate</code> 解压数据时,<code>z_stream</code> 的成员都会进行相应的更新,这里着重观察 <code>total_out</code> 成员。

为了提高代码的可读性,这里删除了 <code>FlateUncompress</code>中无关紧要的一些代码。

下面的代码展示了数据的解压过程,可以看出数据是分块进行解压的,且解压的结果存储在 <code>result_tmp_bufs</code> 中。

因为数据是分块进行解压的,所以解压完之后需要进行拼接操作。然而 <code>FPDFAPI_FlateGetTotalOut</code>返回类型为<code>int</code>,且<code>dest_size</code> 的类型为<code>uint32</code>,所以会发生截断,后面 <code>FX_Alloc(uint8_t, dest_size)</code>分配的堆块也无法存储全部解压数据。

对<code>FlateUncompress</code>下断点,可以看到待解压的数据以及大小(前面提到过大小为 <code>0x3FB2B2</code>):

在调用<code>FPDFAPI_FlateGetTotalOut</code> 函数所在的行(第 <code>590</code> 行)下断点,可以看到 <code>total_out</code> 的值为 <code>0x100000000</code>,当赋值给 uint32 时会截断为 <code>0</code>。

f6d0146 对相关的代码进行了 Patch 以防止出现 Heap Overflow ,但是新的代码仍然无法处理 4GB 以上的数据,如下所示:

后续相关的 commit 对这一段代码进行了清理,如 7b8e8c 和 1e8c39 。