以福昕阅读器为例实现高性能Fuzz

原文首发看雪论坛

1前 言

Fuzzing

现在已经很普遍了,特别是在 AFL 发布之后。因为性能是关键,为了在给定时间内尽可能多的发现 bug,我们需要优化我们的 Fuzzing

方法。本文以 Foxit Reader 的一个图片转pdf的插件为例来描述一通用方法。确切地说,我们用的 Foxit 版本是

7.3.6.321,有漏洞的插件(ConvertToPDF_x86)版本是 7.3.4.308. 该版本的插件有几个有意思的

crash,是由另一位研究人员独立发现的,并且已经提交给 Foxit 团队(已修复并发布新版本),因为我们决定公开这些问题。

2FuzzingMethod

当通过Foxit Reader打开一个图片时,插件 ConvertToPDF_x86 就会被加载来转换图片为pdf并显示出来。该插件可以转换大部分常用的图片格式(JPEG, GIF,PNG...)。

ModLoad: 6cf90000 6cf96000   C:\Windows\SysWOW64\IconCodecService.dll

ModLoad: 50230000 50f61000   C:\Windows\SysWOW64\ieframe.dll

ModLoad: 53820000 53d45000   C:\Program Files (x86)\Foxit Software\Foxit Reader\Plugins\Creator\x86\ConvertToPDF_x86.dll

在我 Fuzzing 测试中,我专注于JPEG 文件格式,然后定位到 Foxit 调用插件的函数:

003b96f0 533c932e kernel32!CreateFileW

003b9720 533cb136 ConvertToPDF_x86!DestorFXPDFConvertor+0x4fe

003b975c 02598c3f ConvertToPDF_x86!CreateFXPDFConvertor+0x646

003bb644 0128e6fd FoxitReader_Lib_Full!CryptUIWizExport+0x8856ff

003beac8 0128637a FoxitReader_Lib_Full+0x18e6fd

003beb18 0128691c FoxitReader_Lib_Full+0x18637a

003beed0 013aefa8 FoxitReader_Lib_Full+0x18691c

通过检查栈上的参数,我们可以看出第一个是图片文件的路径,第二个是要写入的临时 PDF 文件。注意由于 ASLR,下面显示的地址可以与上面列出的模块不同。

0032e6f0 6a01            push    1

0032e6f2 6a00            push    0

0032e6f4 51              push    ecx                    ; path to temp PDF file

0032e6f5 8bc8            mov     ecx,eax

0032e6f7 8b4604          mov     eax,dword ptr [esi+4]

0032e6fa 52              push    edx                    ; path to JPEG image

0032e6fb ffd0            call    eax

当 Foxit 调用该方法时通过动态地修改参数,我们可以打开其他任意地图片。因此在调用期间通过恢复上下文(尤其是x86寄存器),快速重复地调用该转换函数也就成为可能。幸运地是,每次调用不需要恢复堆。

该方法有几种实现自动化的方式。我们可以使用 Pintool,但是为了优化我决定写一个特定的工具。

最后,我写了一个小调试器,可以通过传一个图片参数来启动 Foxit Reader,并且断点在 ConvertToPDF_x86.dll 的图片转换函数的对应调用处,可以获取下一步进行回放的上下文。

CONTEXT ctx;

...

case EXCEPTION_DEBUG_EVENT:

{

EXCEPTION_DEBUG_INFO& exception = debug_event.u.Exception;

switch (exception.ExceptionRecord.ExceptionCode)

{

case STATUS_BREAKPOINT:

...

if (IsMyBp())

{

SaveContext(&ctx);

...

RunFuzzing(&ctx);

...

}

}

}

然后调试器注入一 DLL 到 Foxit 内存中(通过 RunFuzzing() 实现),并设置好要传给被调用函数的参数。

while(TRUE)

{

corrupt(image);

// call the fonction

_asm

{

push 1

push 0

lea  edi, pdf_path

push edi;

lea  edi, image_path

push edi;

mov  edi, val_edi

mov  esi, val_esi

mov  ecx, val_ecx

mov  ebx, val_ebx

mov  eax, val_eax

mov  edx, val_edx

call eax

}

}

Intel Xeon E3-1230v3 (3.3 GHz)机器上,基于该 Fuzzing 方法,我们达到了150~300tests/sec

的效果。很重要的一点是该 Fuzzing 必须在 Foxit 的进程中执行,手动调用该 DLL 插件不会直接生效。

3Fuzzing 结果

即使是简单的位翻转,就会产生很多的 crash,其中一些可利用。在进行了3天的Fuzzing 后,对这些 crash 有了如下发现。

以福昕阅读器为例实现高性能Fuzz_第1张图片

请点击此处输入图片描述

4结 论

该方法可用于任意软件,只要在目标函数(或一组函数)被调用前能够轻松地再现软件的状态。在我看来这也是要克服的最大障碍。

ConvertToPDF_x86

的例子还是简单的,但是在其他大量的例子中,需要注意内存分配、回收和全局变量修改(或初始化程序)。针对这个目的 Pintool

就很有用了,并且可能是一个有趣的可进一步研究的方向。当然,我们可以通过 hook 插件的读/写访问来优化该 Fuzzing

方法,从而避免执行过程中写文件到硬盘。

本文由 看雪 iOS 安全小组 Arming  编译,小布校对,来源 hdwsec@Vitaly Nikolenko

请点击此处输入图片描述

往期热门内容推荐

等你来挑战!| 看雪 CTF 2017 攻击篇

【终于等到你!】看雪 CTF 2017

春风十里,我在等你

Windows 平台下的最优化 Shellcode 代码编写指引

使用最新的代码重用攻击绕过执行流保护(一)

新手逆向学习--Win7 下 64 位扫雷逆向以及辅助制作

......

你可能感兴趣的:(以福昕阅读器为例实现高性能Fuzz)