环境

分析

adobe reader中的CoolType.dll在解析字体文件SING表中的uniqueName项时存在栈溢出漏洞。

ida打开CoolType.dll,搜索"SING"找到漏洞位置,漏洞发生的原因是没有对strcat的参数做长度校验导致发生溢出。

image-20200105223250277

到调试器里面看看发生了什么:

打开adobe reader,用od attach之后在0803ddab(call strcat)处下断点,之后打开样本文件msf.pdf(样本文件可用msf生成),成功断下。

查看堆栈得知arg0=0012e4D8, arg1=047c5c68

esp

由于call strcat前已经把arg0的第一位置0了,所以相当于直接把047c5c68指向的内容(一直到\x00)复制到0012e4D8处,在hexdump中可以看到这段数据的长度是573(0x47c5ea8-0x47c5c68-3=0x23d),后面会提到这段数据的来源。

payload-dump

call strcat所在的函数开头只扩展了104h的栈空间,所以溢出是肯定的了。

image-20200105225417351

通过溢出之前和之后arg0(0012e4D8)附近的内存对比,可以发现栈上的很多数据被覆盖了。

溢出之前的0012e4D8

溢出之后的0012e4D8

接下来看样本是如何获得eip的,调试发现在call strcat所在函数还未返回之前就已经弹出计算器了,在call strcat之后一路f8,发现执行过0803deaf就会弹计算器,说明问题出在call 08016bde里面。

image-20200105230312895

重新来一次,在0803deaf断下,f7进去后和刚才一样连续f8找目标,发现在0801656处(call 08016bde)弹了。

image-20200105230730587

同样的方法继续往里面跟:

0801BB41处(call [eax])弹计算器

image-20200105231038670

继续,在0808B308弹计算器,此时call [eax]跳到4a304B38处

image-20200105231047759

f7跟进去,发现4A80CB38是一个rop gadget

image-20200105231454453

return前栈上的状况,

image-20200105232008791

4a82a714又是一个rop gadget,

image-20200105232045662

之后程序跳转到0c0c0c0c执行,这是经典的堆喷射地址,之后就跳转到实现布置好的区域开始执行shellcode了。

image-20200105232529770

至此把从溢出到跳转shellcode的过程走了一遍。

文件提取

用pdfstreamdumper打开msf.pdf,使用search_for选择ttf fonts定位到左边的object,右击object选择save decompressed stream提取字体文件。

image-20200105233105118

用010editor打开,选中的部分就是SING表中uniqueName的值,这段数据就是之前做strcat参数的那一段。

image-20200105234257621

可以看到我们前面用到的两个rop gadget(4A80CB38和4a82a714)就来源于其中。

追踪

有个问题,程序是怎么运行到第一个gadget(4A80CB38)处的?

通过前面的调用链往回查找数据来源,发现在0808B308处call dword ptr [eax]中eax来源于[edi+3ch],

而edi的值是0012e718,所以实际上call的是存放在0012e754处(0x0012e718+0x3c)的一个函数指针。

回到一开始溢出的地方,长度为0x23d的数据被复制到0012e4D8处,而0x012e754-0x012e4D8=0x27c,所以0012e754的值并没有被覆盖,这个值在strcat之前一直到最后调用rop都是0012e6d0,但是0x0012e6d0-0x012e4D8=0x1f8,所以0012e6d0指向的数据被覆盖了,覆盖成了4A80CB38,也就是第一个rop gadget。

所以溢出做的事情就是覆盖了一个后面会被调用的函数指针,以此劫持程序流程开展后续的利用。

思考

分析起来好费劲,不过也学到了一些技巧,回头想想作者写exp的时候可能是搞一段cyclic找到异常访问的地址之后找no aslr的rop什么的。