摘要

本文主要讲述如何利用winafl对***pdf阅读器程序进行漏洞挖掘的过程。

准备

  • winafl、DynamoRIO
  • ***pdf(11.6.0.8537)32位
  • 测试环境:win7 32位、4G内存、4核cpu

漏洞挖掘步骤

1. 寻找合适的函数偏移

大致看了下***pdf的程序目录,找到和pdf相关的dll仅有pdfmain.dll,大概分析了下,应该是将开源的pdf库pdfium打包了进去,但无法确定库的版本,同时也无法确定是否经过***官方修改,因此无法找到独立的库文件进行fuzz了。就只好对***pdf.exe主程序进行fuzz了。

利用winafl对windows程序进行漏洞挖掘,关键是找到合适的函数位置进行插桩,便于winafl进行可重复的fuzz测试。根据winafl的官方说明,函数偏移需要满足以下条件:

  • 打开输入文件。打开文件操作必须在选定的函数内部执行,这样当winafl迭代测试时可以重写输入文件,程序每次读取的都是经过变异后的文件。
  • 解析输入文件。(这样便于衡量程序的覆盖率)
  • 关闭输入文件。这点非常重要,如果没有关闭文件,winafl将无法重写文件
  • 函数能够在无交互的情况下运行到返回处。

在没有源码的情况下,我们可以通过逆向分析的手段来找到一个恰当的函数位置进行插桩。

首先通过process monitor来大致确认***pdf打开、读取pdf文件时的大致函数位置,如下图:

查看调用栈如下:

查看模块基址如下:

因此可以确定调用CreateFileW时的函数调用地址为,关键位置处于pdfmain.dll中,利用ida打开,代码如下:

接着看下ReadFile的函数操作:

可以看出从偏移0x389130处下面的函数调用都相同,可以判断出在该函数内部进行了对文件的打开、读取操作,因此可以考虑在该函数以及后面的函数作为选取的函数偏移。

2. 进行debug模式测试

这里考虑将0x765F93处的函数头部0x765f00作为选定的函数偏移,利用以下命令进行测试:

drrun.exe -c winafl.dll -debug -call_convention cdecl -coverage_module pdfmain.dll -target_module pdfmain.dll -target_offset 0x765f00 -nargs 2 -fuzz_iterations 10 -- office6***pdf.exe BZ7.pdf 

效果如下:

看起来不错,没有什么问题,接下来利用winafl-cmin.py对样本进行精简。

3. 利用winafl-cmin 精简样本

命令如下:

afl-fuzz -i E:sampleout -o pdfout -m none -t 30000 -D E:fuzz_targetoolsfuzztoolsdynbuild32bin32 -S fu2 -- -call_convention stdcall -target_module pdfmain.dll -coverage_module pdfmain.dll -target_offset 0x765f00 -fuzz_iterations 15000 -nargs 2 -- office6_old***pdf.exe @@

结果如下,200多个文件最终保留了15个。

4. 利用winafl进行fuzz测试

命令如下:

afl-fuzz -i E:sampleout -o pdfout -m none -t 30000 -D E:fuzz_targetoolsfuzztoolsdynbuild32bin32 -S fu2 -- -call_convention stdcall -target_module pdfmain.dll -coverage_module pdfmain.dll -target_offset 0x765f00 -fuzz_iterations 15000 -nargs 2 -- office6_old***pdf.exe @@

但是出现了一些问题,如下图:

为什么程序被处理掉呢,通过深入分析发现是由于winafl无法重写测试文件即.cur_input,原因是在我们选择的函数内部并没有主动关闭文件导致没有释放句柄,所以winafl就无法重写文件,这导致winafl必须主动关闭掉程序来进行新样本的测试。

那么***pdf在什么时候会关闭文件呢,通过分析发现只有用户主动点击X图标时,***pdf才会关闭文件,因此在***pdf打开的文件中,是不允许对文件进行修改的。这给fuzz带来一些困扰,根据winafl的说明,如果发现fuzz效率低下,则可能需要修改winafl源码或者对程序进行patch来提高不关闭文件句柄时的fuzz效率。当然,目前还有其它的方法,比如发现有的人会通过一些autoit脚本来主动识别打开文件时的窗口,并立即关闭,这样似乎也可以,相当于通过脚本自动化的关闭窗口。但是在实际过程发现,在我们选择的函数中还并没有对窗口进行绘制,因此就无法获取窗口句柄,关闭窗口了。因此为了提高效率,我们可以从以下两方面入手:

  • patch系统调用,对CreateFile、ReadFile、WriteFile等和文件读写的系统调用进行patch,比如说,CreateFile判断读取的文件名称,是否是fuzz时的输入文件名称,如果是,则保留句柄,在ReadFile、WriteFile时判断传入的句柄是否为输入文件的句柄,如果是,则将特定数据内容返回,而不走系统自身调用。这样避免了已经打开的文件无法重写的问题。
  • patch目标程序,在选择的函数偏移内部找一块可读、可执行的区域添加保存句柄、释放句柄的代码。这样实现了在函数内部自动关闭文件的操作。

这里仅仅修改winafl源码是无法解决问题的,不过可以修改代码来进行配合以提高fuzz效率,比如每次生成变异的文件无需写入磁盘,而是直接向特定的区域写入,这样少了系统api的调用,应该可以快上不少。

为了防止修改的调用系统影响过大进而造成其他问题,我选择patch ***pdf目标程序。在调试时找到一块可利用的地址,但是发现是系统出于内存对齐而申请的,文件中并不存在,因此只能通过添加区段的方式来添加新的利用代码了。

我通过studype这个软件来添加区段,并且设置区段属性为可读、可写、可执行,如下:

一般来说,在CreateFile函数后添加代码将输入文件的句柄进行保存,那么就需要解决另外一个问题:在哪里关闭句柄是恰当的。我通过不断的测试发现在特定的函数后关闭句柄,并不会影响整个pdf文件的读取和解析,pdf文件内容可以正常输出到显示器上。添加的代码如下:

由于执行CreateFile的操作不只一次,因此需要提前进行判断,只保留输入文件的句柄。对patch后的程序进行fuzz,效率果然提升了不少,测试效果如下图:

但是在fuzz过程中,由于winafl变异样本导致pdf格式不正确,因此***pdf会弹窗说明,如下:

此时winafl会卡住,这会极大地降低fuzz的速率,一般来说通过post library的方式修改pdf文件头部为%PDF-1.4,可以解决一部分的文件格式问题,还有一部分是不符合整个pdf的文件结构导致的,这时只修改头部是没什么用的。不过要解决这个问题,其实只要让它不弹窗就好了。

我们可以利用调试器调试***pdf打开文件的过程,当弹窗messagebox后,中断程序,切换到0号线程,即可观察到弹框时的函数调用栈,如下:

查看函数rva如下:

因此将该处的代码patch即可,尽量不要修改程序的逻辑,如下:

这样的话程序哪怕检测到文件格式不正确也不会弹窗,进而影响fuzz速度了。但是这里遇到另外一个问题涉及到了数据重定位,由于patch的地方保存着重定位的数据,因此必须手动修复。首先通过studype查看程序的重定位表,定位到具体的代码段的rva处,查看对应重定位数据的索引,如下:

接着通过010editor打开pdfmain.dll,利用pe的模板对文件进行解析,如下:

将对应块的内容改为其它地址或者0,就不会对原有的数据进行重定位了,不然nop后的汇编代码会被修改为重定位后的值,导致程序执行异常。但是这里有一个隐患,为了提高漏洞的检测能力,通过gflags开启page heap,这样就能够检测堆的漏洞了。

后面确实触发了一个uaf漏洞,经过深入调试分析发现,是因为程序在检测到文件格式错误后,会主动关闭文件句柄,而我们自身又关闭了一次,这就导致程序的逻辑出现了一些问题,最终触发了uaf。因此为了修复这个问题,定位到了程序在检测到文件格式不正确后,我们可以关闭句柄的函数地址,再次patch,添加代码,让程序能够正常运行。

经过一段时间的fuzz后,出现了一些crash,我们接下来针对crash进行分析。

5. crash分析

经过粗略的分析发现这次的漏洞是一个uaf漏洞,崩溃现场如下:

可以看到ecx指向的内存地址是不可访问的,由于开启了page heap,可以查看该内存块的释放位置,利用命令!heap -p -a ecx,显示如下:

虽然知道了释放堆的地址,但我们无法获取堆块的内容,同样也不清楚申请该堆的作用是什么,在什么地方申请的。虽然可以通过调试时在free的地方下断点进行分析,但实际分析时发现该处释放堆块的次数非常多,难以确认具体的释放触发uaf漏洞的堆块的时机,因此我们可以通过简单的windbg脚本来获取释放堆块时的具体数据,以方便进行对照。脚本命令如下:

bp pdfmain+43c7f2 "r esi;dd esi l10;db esi l20;!heap -p -a esi;g"

搜索找到了free前的堆块数据,如下所示:

跟踪下malloc后的程序行为,发现是将pdf obj中的数据保存在该堆块中,如上图中的数据0x2068,其实是pdf obj的length数据,如下图:

将8296字符串转换为16进制数据保存到该堆中,申请以及数据存储函数如下:

随后,又将该指针保存在多处,函数如下:

整个程序的执行流如下,首先在函数0x10479DF0中处理对pdf内容的解析,申请堆内存保存相关数据,

接着在函数0x1043a7b0中释放资源:

而保存length内容的指针在多个地方均有引用,首次释放在这里:

接下来释放保存有uaf指针的多个指针,结构如下:

随后会对释放后指针的首4字节内容进行判断,就触发了uaf漏洞。

6. 修复建议

该漏洞产生的原因是将多个指针指向同一块内存区域,但是在释放内存后,并没将所有指向该内存的指针指向null,产生了野指针,在后面对野指针的访问造成程序异常。因此建议在开发阶段排查野指针问题,或者使用更加安全的智能指针进行代替。

7. 改进

后续在fuzz过程中,我发现新的路径非常难以产生,虽然说整个程序的运行速度很快,但是每次都是在一次完整的迭代测试后,kill掉进程重新测试时才会产生新的路径。这种情况的产生似乎有可能是由于patch程序造成的,为了了解产生这种情况的原因,必须对程序进行再次的分析。

通过drrun.exe监控下patch后程序的运行状况,结果如下:

可以看出,除了第一次外,***pdf会读取输入文件,后面的迭代测试中并没有对输入进行读取和解析,因此此时的fuzz效率本质上还是非常低的,虽然它的速度非常快,但是***pdf并没有对后续的输入进行解析,这就导致发现新路径的速度非常的慢。在解决这个问题之前,我们必须了解清楚***pdf对后续的输入没有读取的原因。

通过几次测试发现,***pdf程序无法打开同一个位置的同名文件,由于patch了pdfmain.dll,这让我们可以在***pdf加载输入文件后随意修改输入文件名称和内容,在将文件名称修改后,***pdf就可以继续打开输入文件了,本质上它们是同一个文件。我们可以确定两点,第一点是确***pdf内部有判断机制,即不会重复打开相同的文件路径;第二点是该判断机制的代码的大概区间,就在我们patch代码的函数地址到读文件的函数地址之间。

通过动态调试,找到该判断处位于函数0x107b0e90,如下:

当该函数返回值非0时,说明此时的文件已经在***pdf中被打开,***pdf就不会第二次打开该pdf,因此让该函数直接返回0后退出即可。patch过后再次利用drrun.exe查看程序的执行效果,如下:

可以看出,在每次迭代测试中均会对输入文件进行打开和解析,这样就可以进一步的fuzz了。

​ 如上所示,虽然程序fuzz速度变慢,但是发现新路径的速度反而快了很多。后续我将继续思考如何提高fuzz效率的相关问题,详细内容敬请期待。

ie 打开后端发过来的pdf_某办公软件PDF阅读器漏洞挖掘及Crash分析相关推荐

  1. Win10用Windows照片查看程序打开图片+更改注册表后导致Win10任务栏Adobe PDF阅读器图标显示异常

    Win10用Windows照片查看程序打开图片 解决办法: 参考:https://jingyan.baidu.com/article/455a9950bb20bda166277824.html 上述操 ...

  2. edge打开pdf不显示印章_SumatraPDF - 免费轻量的 PDF 阅读器

    SumatraPDF 是 Windows 平台上的一款 免费轻量 的 PDF 阅读器,除了支持 .pdf 以外,还支持 .epub..mobi..chm 等格式的文件.该软件体积小巧,但功能十分强大, ...

  3. opencv4快速入门pdf_云复工提升工作效率之九 福昕PDF阅读器

    福昕PDF阅读器核心采用福昕风腾PDF电子文档处理技术,比肩Adobe Acrobat Reader PDF处理技术,性能稳定.运行速度快,可以对PDF进行新建.压缩.加密.合并.注释.编辑.签名.翻 ...

  4. android 手机 用短信发pdf文件,安卓手机什么pdf阅读器最好用?如何编辑pdf文件

    原标题:安卓手机什么pdf阅读器最好用?如何编辑pdf文件 现在手机上都会安装各种功能的应用app,以便应对工作或休闲娱乐的需求.那么你知道安卓手机上扫描pdf阅读器最好用吗?我认为一款好用的pdf阅 ...

  5. python 打开pdf文件_用Python开发的简易PDF阅读器

    主要的库 PyQt5:UI的开发 fitz:与pdf文件相关的操作几乎都用的是它 这是一个用Python开发的pdf阅读器,是软A项目的附加软件(虽然现在主程序几乎可以说还没有开始:joy:,只完成了 ...

  6. ShellExecuteEx如何关闭打开的pdf阅读器

    要关闭使用ShellExecuteEx打开的PDF阅读器,需要使用Windows API函数来结束进程.可以使用以下步骤来实现: 使用函数FindWindow找到PDF阅读器的窗口句柄. 使用函数Ge ...

  7. 【福昕PDF阅读器】当前文件兼容于PDFA且以不接受修改的只读模式打开

    前言 写这篇文章不是因为网上没有解决办法,只是大部分都是adobe的,不同软件的界面总是不一样的,像我这么懒的人当然希望搜到的答案跟自己的情况完全一样,所以写一篇给跟我一样懒的人. 问题 当下载一个p ...

  8. ie 打开后端发过来的pdf_JS如何下载资源文件,并且兼容IE、Edge

    前言:这边需要做一个功能: 点击按钮,下载所有的资源文件. 这不挺简单,心想,直接通过 a.download 直接解决不就 ok 了.谁知... 我尿了... 对不起,是我年轻了. 与后台确定了一下返 ...

  9. 打开acrobat pdf阅读器提示“内容准备进度”解决方法

    点击菜单栏中的"编辑"-"首选项"-"辅助工具",取消勾选"启用辅助性技术支持"选项,如下图

最新文章

  1. c的开始,求最大数。
  2. 多媒体文件格式之RMVB
  3. TCP的TIME_WAIT状态
  4. jQuery插件编写基础之“又见弹窗”
  5. java获取本机ip地址_代码片段:获取系统所有IP
  6. 【概率论】对弈输光模型,ruin model
  7. 百度地图上的标注物太多导致界面卡顿的解决办法
  8. windows10完全删除mysql_Windows 10系统下彻底删除卸载MySQL的方法教程
  9. DOM701:禁用了反向和正向缓存(开发者)
  10. python 通用数据库类型_Python开发基础之Python常用的数据类型
  11. Red Hat Cormier发布OpenShift.io和容器状态指数
  12. 果园机器人作文开头_果园机器人作文
  13. 关于SiamRPN代码的一些要点
  14. Windows域内密码凭证获取 (゚益゚メ) 渗透测试
  15. IPC TCP/IP协议
  16. 2021级程序设计ICODING答案分享
  17. 【我的架构之路】什么是代理服务器以及什么是负载均衡?
  18. 英汉互译教程---生词
  19. 手机和电脑的文件传输利器(FE文件管理器)
  20. wincc版本升级_西门子触摸屏OS更新方法

热门文章

  1. 如何使用Arthas定位线上 Dubbo 线程池满异常
  2. Spring Cloud构建微服务架构:分布式配置中心(加密解密)
  3. binlog工具_基于Binlog实时同步数仓,有哪些不为人知的坑?
  4. python傅里叶变换例子
  5. kl散度学习笔记python实现
  6. Py_Initialize fails - unable to load the file system codec
  7. RuntimeError: cudnn64_7.dll not found.
  8. speedtorch 加速神经网络
  9. ffmpeg4编解码例子
  10. python自带 python2转python3 代码工具