bd23ad33accef14684d42c32769092a0
CVE-2018-4990是Adobe在2018年5月修复的一个Adobe DC系列PDF阅读器的0day,原样本配合另一个windows本地提权漏洞CVE-2018-8120一起使用,后者用来进行沙箱逃逸,关于CVE-2018-8120漏洞的分析可以参考小刀师傅写的《通过对比 5 月补丁分析 win32k 空指针解引用漏洞》一文。
官方公告说这是一个Double Free漏洞,但调试发现这是一个任意地址释放漏洞,原样本中,在32位环境下,攻击者可以通过这个漏洞实现对任意两个4字节地址的释放。原样本漏洞触发前用精准的堆喷射巧妙地布局内存,然后触发漏洞,释放可控的的两块大小为0xfff8的相邻堆块。随后,Windows堆分配算法自动将两块空闲的堆块合并成一个大堆块,接着立即重新使用这个大堆块,并利用这个该堆块的读写能力改写一个ArrayBuffer对象的长度为0x66666666,从而实现任意地址读写。
根据公告,这个漏洞并不影响Adobe Reader 11.x及之前的版本,根据ESET的给出的列表,影响的版本如下:
本次调试使用的是Adobe Acrobat Reader DC 18.11.20035,JP2Klib.lib版本为1.2.2.39492。操作系统为Windows 7 sp1 x86,调试器为Windbg。
拿到样本,我们要做的第一件事就是定位漏洞触发点,先开启全页堆,打开样本后发现crash,现场如下:
看过《Windows高级调试》第6章页堆部分的同学应该已经明白了,free地址为0xd0d0d0d0的原因是释放了全页堆的后置填充区域。
到这里,有经验的同学应该已经可以猜到是因为堆内存的越界访问导致释放了堆的后置填充数据,从上面的栈回溯我们可以看到这是JP2Klib动态库的一处调用导致的,如下:
我们在IDA里面看一下相应偏移处的代码逻辑:
将上述代码整理一下后可以更清楚地看到逻辑:
我们来监控一下max_count和while循环里的count变化过程
利用PdfStreamDumper.exe对pdf的修改能力,我们对内嵌的javascript代码稍作修改,放开原代码的一处注释,目的是在漏洞触发前弹个对话框,便于我们下断点:
可以看到mem_base为 073fa1a0, max_count = 0xff,当count变化到0xfd和0xfe时两个在原js中出现的堆地址 0x0d0e0048 和 0x0d0f0048 被释放。
此时我们对mem_base的分配大小很感兴趣,重启windbg,观察一下mem_base的大小,可以看到mem_base的大小为0x3f4
到这里漏洞的成因已经很清楚了,漏洞根源在于 max_count = 0xff,而ff*4 = 3fc,所以while循环可以访问到mem_base ~ mem_base+3fc 区间的内存。但是我们看到mem_base对应处的内存大小只有0x3f4,两者的差值为8个字节3fc - 3f4 = 8,于是可以借助上述while循环越界访问两个4字节地址并释放,来实现任意释放两个地址。
于是攻击者可以通过内存布局(例如堆喷射)提供的任意两个4字节地址,并实现任意释放,如下是样本中越界释放的两个堆地址,他们通过堆喷射被精确布控到相邻的内存。
所以这本质上不是一个double free漏洞,而是任意地址释放漏洞(原样本在32位下可以释放两个任意地址)。
攻击者在已经知道漏洞内存区域大小为0x3f4的前提下,在漏洞触发前利用精心控制大小(0x400)的堆喷射构造大量对象,然后释放其中的一半,借助堆分配算法,JP2Klib在申请漏洞对象时,会从释放的堆块里面直接复用一个。
上述复用造成了很有意思的现象,我们在windbg下来看一下
随后攻击者通过以下代码立即将上述合并的堆块重新使用。
由于漏洞触发前的如下堆喷射语句,0d0e0048和0d0f0048在释放前分别代表一个长度为0x10000 - 24的ArrayBuffer对象。在UAF之后,0d0e0048+0d0e0048的内存变成了一个长度为0x20000-24的ArrayBuffer对象。
接着攻击者利用长度为0x20000-24的ArrayBuffer的读写能力去改写释放前0d0f0048对应ArrayBuffer对象的长度,将其改写为0x66666666。然后利用之前构造的sprayarr数组找到长度为0x66666666的“ArrayBuffer”对象(这时候已经是伪造的了),紧接着将其赋值给一个DataView对象借助DataView来实现任意地址读写。
重启调试器,来看一下上述过程:
随后攻击者用其初始化一个DataView对象,并借助DataView对象实现了任意地址读写函数:
随后利用任意读写能力泄漏Escript.api基址,构造ROP:
随后构造ROP,填充PE数据:
构造完ROP后对escript的off_259BA4全局变量指向的指定偏移的数据进行修改:
ROP执行完毕后,样本进入shellcode,shellcode执行完后,在内存中直接执行PE,PE利用了CVE-2018-8120进行本地提权,提权成功后可以看到沙箱进程的权限已经由low变成了system。
随后样本会弹出对话框,并向启动项写入一个one.vbs,one.vbs的作用是从本地http服务器下载一个calc.exe,从这里可以看出这个组合漏洞样本还在测试阶段。
由于这个Adobe将这个漏洞归类为Double Free,所以一开始我一直在往Double Free的方面想,导致浪费了大量时间。在这个过程中我看到了一篇非常精彩的Double Free文章《Too Much Freedom is Dangerous: Understanding IE 11 CVE-2015-2419 Exploitation》,想入门Double Free漏洞分析的同学可以好好看一下这篇文章。同时,在本地复现时我发现win7下在打了2018年3月的内核补丁后Adobe在8120的提权过程中会导致虚拟机直接重启,不打该补丁则一切正常,目前还未完全清楚该问题的原因。
此外,实际执行时发现bkm.execute()这一步的前一步就可以导向ROP,我暂时没有调试清楚最后两步的含义,只知道是在切换执行流,也希望理解的同学可以告诉我一下。
这个漏洞我从上周开始一直在花时间调试,直到昨天下午国外 @steventseeley 发了一篇对这个漏洞的分析,当时感觉他并没有分析清楚漏洞原因,昨晚看了 @klotxl404 和 @binjo 两位大神在twitter上的互动后恍然大悟。今天下午看到 @steventseeley 的文章也更新了,他那篇还画了图,表述得非常清晰,可以先看他那篇。
这个漏洞中max_count值是否可控,以及其是否可以通过恶意的JPEG2000图像数据进行操纵,目前还暂不清楚,等待后面补充,或者等待有能力的同学进行补充。
第一次调试Adobe Reader漏洞,不足之处请多见谅。
《A tale of two zero-days》 https://www.welivesecurity.com/2018/05/15/tale-two-zero-days/
《通过对比 5 月补丁分析 win32k 空指针解引用漏洞》 https://xiaodaozhi.com/exploit/149.html
《Adobe, Me and an Arbitrary Free :: Analyzing the CVE-2018-4990 Zero-Day Exploit》https://srcincite.io/blog/2018/05/21/adobe-me-and-a-double-free.html
《Too Much Freedom is Dangerous: Understanding IE 11 CVE-2015-2419 Exploitation》https://blog.checkpoint.com/2016/02/10/too-much-freedom-is-dangerous-understanding-ie-11-cve-2015-2419-exploitation/
《Javascript DataView》http://pwdme.cc/2018/01/21/javascript-dataview/
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-3-26 13:06
被银雁冰编辑
,原因: