首页
社区
课程
招聘
[原创]Adobe Reader栈溢出漏洞分析(CVE-2010-2883)
发表于: 2019-6-8 17:09 9212

[原创]Adobe Reader栈溢出漏洞分析(CVE-2010-2883)

2019-6-8 17:09
9212

这个漏洞是《漏洞战争》里面的第一个漏洞,也是我分析的第一个漏洞。水平有限,如有错误还望各位大佬指正。

CVE-2010-2883是Adobe Reader和Acrobat中的CoolType.dll库在解析字体文件SING表中的uniqueName项时存在的栈溢出漏洞,用户受骗打开了特制的PDF就有可能导致执行任意恶意代码

用IDA反汇编CoolType.dll库,查看字符串可发现SING字体

直接定位进去即可查看该库对sing表格的解析方式,主要是strcat造成的溢出漏洞

可以注意到在地址0x0803DDAB处调用了strcat函数,先来看下strcat函数原型

strcat会将参数src字符串复制到参数dest所指的字符串尾部,dest最后的结束字符NULL会被覆盖掉,并在连接后的字符串尾部再增加一个NULL

漏洞成因就是没有去验证src的长度是否可能会超出dest数组定义的长度。如果我们有可能超出dest数组定义的长度的数据放入src中有可能在后方调用strcat函数时覆盖栈区从而实现代码执行

在复现环境中把Adobe Reader 9.3.4启动程序载入OD,加载之后按F9运行。此时OD显示当前调试程序是运行状态,实际上这个时候Adobe Reader就已经加载了CoolType.dll文件了。

通过刚刚的静态分析我们了解到SING在地址0x0803DD74处被引用,因此我们可以在OD中在这个地址处下一个断点

Ctrl+G输入0x0803DD74回车跳转到该地址F2下断点

将样本(名企面试自助手册.pdf)拖入Adobe Reader中,程序就会停在刚才下的断点上面

F7单步到下面的地址

此时ecx指向0x12E404,《漏洞战争》对这条指令的解释是这里是SING表的表的入口,我们来验证一下,数据窗口跟随看看这个指针里面存放的是什么

在分析这段数据之前我们先来看看TrueType字体格式标准文档里

在TrueType字体文件中,从0字节偏移的位置开始有一个表目录。且这个表目录的第一个字段是名为sfnt version是用来表明所用ttf格式版本的字段。在文档中清楚的说明了,对于1.0版本的TTF字体文件开头要用0x00010000来表示版本。

现在回到0x2AEB710位置处的数据,

会发现开头正好是0x00010000,这就证明了ecx保存的确实是SING表的指针

继续动态调试,接下来遇到一个call指令,不妨来看看这个函数传入了哪些参数

很明显它将SING字符串当作参数了,这个call实际上是在处理SING表,这里我们直接F8步过,继续单步

此时eax为0x46949,要想知道这块数据是什么,首先用pdfStreamDumper取出PDF样本中的TTF文件。TTF中关于SING表的TableEntry结构数据,如图所示

下面是官方文档中对TableEntry结构的定义

通过观察SING表中的结构我们可以知道在文件偏移0x11C处即是SING表的真实数据,Ctrl+G去到0x11C处,发现和eax所指向的0x46949是一致的,如图:

通过确认这个eax所指向的内容我们可以推测出上面那个call的作用是取出SING表的入口地址

接着比较eax和esi的值,检测SING表是否为空

下面的je因为SING表不为空,所以不会跳转

然后这里取出eax的内容赋给ecx,通过刚才的分析我们知道此时的ecx保存的是ttf的版本号,继续往下

然后清掉低4位,结果为零,je跳转,继续往下

接着将eax加上0x10,eax原来指向SING表,SING表加上0x10处指向的是unique域,在010Editor处如图:

继续单步就能发现溢出点

这里将uniqueName域和当前的ebp入栈,然后调用strcat进行字符串拼接,但是没有进行安全检查,导致溢出,我们单步步过strcat后查看一下ebp开始的栈区数据

此时栈溢出已经发生,函数的返回地址已经被覆盖为SING表中的恶意数据,在010Editor中如图

这个地址位于icucnv32.dll中,让我们来看看这个地址有和特别之处,为什么会选择这样一个地址,用010打开icucnv32.dll

我们发现IMAGE_OPTIONAL_HEADER中的IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 的值为0,也就是说这个模块没有开启ASLR,这就保证了exploit的稳定性

继续往下分析,执行到0x0808B308时,eax的值指向0x4A80CB38,这个地址也是在icucnv32.dll中,我们F7跟进去,

这个地址是精心挑选的ROP指令,首先调整了ebp,调整之后ebp为0012E4DC

也就是将ebp调整到strcat函数调用后的栈区数据范围内,接下来执行leave,修改了esp

最后retn会跳转到0x4A82A714地址处,继续F7单步

pop esp之后,esp将被修改为0x0C0C0C0C,然后返回,此时栈的情况如图:

上面的0x0C0C0C0C是样本特意构造的,自然是为了实现 HeapSpary堆喷射技术,借助PDF本身支持执行JS的特性,将ShellCode借助JS写入内存中。栈中的数据即是JS代码中的ShellCode,作者利用它来实现ROP以绕过DEP保护。

这里借助PDFStreamDumper工具提取样本中这段实现堆喷射的JS代码

所有的ShellCode都被转化为了十六进制的转义序列,经过unescape解码之后存储在var_shellcode之中,var_c变量存储了%u0c0c%u0c0c,接下来用了一个while循环叠加var_c,用来覆盖内存的数据。

采用0x0c0c0c0c作为滑板指令的原因是因为它对应的指令是or al,0x0C,这样的指令执行的效果对al寄存器不会产生任何影响

接下来的var_b保存了前面是所有滑板指令以及ShellCode,最关键的实现堆喷射的语句是new Array(),利用数据来开辟内存区域,然后通过填充数据的方式来喷射ShellCode

继续调试

这里ecx =0x4A8A0000 [ecx] = “UTF-32”,然后返回

这里借原本存“UTF-32”字符串的地方保存eax的值,然后再次返回

这里eax指向了CreateFileA

然后返回去跳转执行CreateFileA,我们直接查看CreateFileA在栈区的参数

这里以隐藏的方式创建了一个临时文件,文件名为iso88591,可以在当前样本的同路径下找到,我们直接按Ctrl+F9返回

这里会跳转到0x4A8063A5

然后将ecx赋值为4A801064,接着跳转到0x4A842DB2

这里交换eax和edi寄存器的值,接着跳转到0x4A802AB1,继续单步

此时ebx为0x8,跳转到0x4A80A8A6

这里指向了一个函数的实现模块

接着用相同的方法调用CreateFileMappingA,创建文件映射对象,再来查看一下堆栈中的参数

直接Ctrl+F9返回,然后去执行MapViewOfFile,将一个文件映射对象映射到当前程序的地址空间

参数如下

然后用类似的方法去调用memcpy

参数如下

这里将要执行的ShellCode写入到MapViewOfFile返回的地址,因为这段内存是可读可写的,所以就绕过了DEP的保护由于构造的ROP链指令均位于不受ASLR保护的icucnv32.dll模块,因此也绕过了ASLR。

接着去执行ShellCode

至于ShellCode本身干了什么,这个不是我们关心的重点

漏洞流程总结如图所示

下载AdobeReader 9.4.0提取CoolType.dll,定位到相同的位置

这里不再是调用strcat,而是 sub_813391E,跟进去看看sub_813391E

该函数获取了字段的长度,判断是否超出限制。如果超出限制就用strncat限制了拷贝的字节数从而修复了该漏洞

《漏洞战争》

细说CVE-2010-2883从原理分析到样本构造

 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 28
活跃值: (125)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2


赞 大佬好,有个问题,如果滑板指令能够执行的话,为啥不直接把shellcode写到滑板指令后,而是再利用rop申请新的可读可写可执行的内存放入shellcode呢,谢谢

最后于 2020-9-8 16:45 被kanxuexxx编辑 ,原因:
2020-9-8 16:23
0
游客
登录 | 注册 方可回帖
返回
//