CVE-2010-2883分析

1 漏洞背景

CVE-2010-2883是Adobe Reader和Acrobat中的CoolType.dll库在解析字体文件SING表中的uniqueName项时存在栈溢出漏洞。

1.1 Heap Spray(堆喷)

使用堆喷的时候,会将EIP指向堆区的0x0C0C0C0C位置,然后用JavaScript申请大量内存,用包含着0x90和shellcode的“内存片”覆盖这些内存。

CVE-2010-2883分析

JavaScript会从内存低址向高址分配内存,申请了超过200M的内存。

 CVE-2010-2883分析

var nop=unescape(“%u9090%u9090”);
//nop.length返回的是2
//产生一个大小为1MB且全部被0x90填满的内存块
while (nop.length<=0x100000/2)//0x100000是1MB,1MB=1024KB =1024*1024B=0x100000B
{
	nop+=nop;
}
//Java会为申请到的内存填上一些额外的信息,为了保证内存片恰好是1MB,需要将额外信息所占空间减去。
nop=nop.substring(0,0x100000/2-32/2-shellcode.length/2-2/2);
var slide=new Arrary();
//用200个nop+shellcode的内存片覆盖堆内存,只要任意一篇nop区能覆盖0x0C0C0C0C,攻击便可以成功。1MB的内存相对于200Bytes的shellcode,可以让exploit拥有足够的稳定性。
for (var i=0;i<200;i++)
{
	slide[i]=nop+shellcode;
}

 CVE-2010-2883分析

 

1.2 PDF中的JS

注:使用的pdf是用metasploit生成的cve-2010-2883漏洞利用文档test.pdf

使用PDFStreamDumper查看PDF文件结构。

CVE-2010-2883分析

 第11个obj是OpenAction,文件打开时会执行它里边的脚本。

CVE-2010-2883分析

 然而第11个obj没有JS脚本,个人推测JS后面跟了个“12 0 R”代表脚本在第12个obj里面。

CVE-2010-2883分析

 JS脚本用了很多字符串来混淆,用简单字符代替后得到如下代码:

var shellcode = unescape( '%u4141%u4141%u63a5%u4a80%u0000%u4a8a......' );
var str = unescape("%u0c0c%u0c0c");
while (str.length + 20 + 8 < 65536) //65536 Bytes=64MB
	str+=str;
//取从0-1524,1M多一点
str1 = str.substring(0, (0x0c0c-0x24)/2);
str1 += shellcode;
str1 += str;
str2 = str1.substring(0, 65536/2);
while(str2.length < 0x80000) 
	str2 += str2;
str3 = str2.substring(0, 0x80000 - (0x1020-0x08) / 2);
var str4 = new Array();
for (str5=0;str5<0x1f0;str5++) 
		str4[str5]=str3+"s";

 

1.3 TTF文件结构

使用PDFStreamDumper提取TTF文件。

CVE-2010-2883分析

 TTF文件在第10个obj里面。选中第10个obj,右键“save Decompressed Streams”。

CVE-2010-2883分析

 TrueType字体通常包含在单个TrueType字体文件中,其文件后缀为.TTF。(TrueType是微软和苹果公司共同研制的字型标准)。TrueType字体用machintosh的轮廓字体资源的格式编码,有一个唯一的标记名"sfnt"。windows没有macintosh的位图字体资源格式,字体目录包含了字体格式的版本号和几个表,每个表都有一个TableEntry结构项,TableEntry结构包含了资源标记、校验和、偏移量和每个表的大小。

typedef   sturct
{
char   tag[4];
ULONG   checkSum;
ULONG   offset;//相对文件的偏移
ULONG   length;//数据长度为0x1DDF
}TableEntry;

 在TTF文件中搜索“SING”,可以找到TTF中关于SING表的TableEntry结构所处的位置。

CVE-2010-2883分析

SING表数据结构如下图所示

 CVE-2010-2883分析

 

 文件偏移0x11C为SING表数据结构所处位置。SING表偏移0x10处为uniqueName域,uniqueName域大小为28字节。strcat会把从“58 E0 8D AD”(在test.pdf处是“4A E0 CE 68”,都是文件偏移0x0000012C处)开始的数据复制到指定位置,直到遇见NULL。此处的TTF文件已经是包含了触发栈溢出的数据。

CVE-2010-2883分析

1.4 漏洞成因

CoolType.dll中使用strcat函数时未对uniqueName字段的字符串长度进行检测,直接复制到固定大小的栈空间,最终导致栈溢出。攻击者篡改了TTF文件,在PDF文件中嵌入了JS脚本。

CVE-2010-2883分析

sub_8021B06(&TableEntry, a1, "SING");
v6 = TableEntry;
LOBYTE(v24) = 2;
if ( TableEntry )
{
  if ( !(*&TableEntry->tableVersionMajor & 0xFFFF) || (*&TableEntry->tableVersionMajor & 0xFFFF) == 256 )
  {
    uniqueName = 0;
    strcat(&uniqueName, TableEntry->uniqueName);
    sub_8001243(a2, &uniqueName);
    v6 = TableEntry;
  }
  v23 = 1;
}

 

 

2 漏洞调试

使用msf生成了漏洞利用文档,弹出计算机即利用成功。

2.1 使用msf生成样本

CVE-2010-2883分析

 CVE-2010-2883分析

2.2 调试环境

操作系统:xp sp3

调试工具:吾爱**OllyDbg

软件:AdbeRdr934_en_US.exe

2.3 调试

打开Adobe Reader,打开OD附加Adobe Reader,在strcat函数处下断点0x0803DDAB(CoolType.dll的基地址是0x8000000),运行,用Adobe Reader打开test.pdf(msf生成的漏洞利用文档)。过一会会报错,选择不发送错误即可,耐心等待,再过一会断在了strcat函数处。

CVE-2010-2883分析

 

strcat函数执行结束之后,复制的数据从0012E4D8一直到0012E714

构造的触发栈溢出数据有三处比较重要

CVE-2010-2883分析

 若未发生栈溢出,0x12E6D0处的内容是0x080833EF,CoolType.dll会在地址0x0808B308处调用该函数,但是栈溢出发生后,该处地址被覆盖成0x4A80CB38。

执行到sub_8001243函数结束,对复制的数据设置内存访问断点,直接断在了0x0808B308处。(为什么在sub_8001243函数执行结束后设置内存访问断点?因为sub_8001243函数会在调用ROP指令之前对复制的数据进行访问,影响调试,so,还是略过吧,sub_8001243跟了一遍,就是把地址0x12E608和0x12E60C处的数据修改了)。

CVE-2010-2883分析

 CVE-2010-2883分析

 F7跟进icucnv36.4A80CB3。

CVE-2010-2883分析

leave在16位汇编下相当于:
mov bp,sp
pop bp
leave在32位汇编下相当于:
mov esp,ebp
pop ebp
/* lead指令将EBP寄存器的内容复制到ESP寄存器中,
以释放分配给该过程的所有堆栈空间。然后,它从堆栈恢复EBP寄存器的旧值。*/

 CVE-2010-2883分析

 add ebp,0x794CVE-2010-2883分析

 CVE-2010-2883分析

leave CVE-2010-2883分析   (0x0012E4E0-0x12E4DC=0x4) 

CVE-2010-2883分析CVE-2010-2883分析

 retnCVE-2010-2883分析

 CVE-2010-2883分析

CVE-2010-2883分析 

 开始执行shellcode

 CVE-2010-2883分析

 shellcode使用了CreateFile 、CreateFileMapping、MapOfViewMap创建了文件iso885,并把该文件映射到了内存中。使用memcpy函数将shellcode复制到了0x0037B0000处。

CVE-2010-2883分析

 CVE-2010-2883分析

 shellcode会对自身进行解密,解密伪代码如下。

key=0x92F9A5A9;
h=0x03EA0018;
for(i=0;i<0x31;i++)
{
	Array[h]=Array[h] xor key;
	key=Array[h]+key;
	h=h+0x4;
}

 解密之后可以在shellcode中看到计算器名称calc.exe。

CVE-2010-2883分析

 再往后就是动态定位ntdll.dll中的函数,找到WinExec,然后用WinExec运行calc.exe。

CVE-2010-2883分析

2.4 动态定位API

从进程环境块(PEB)中找到动态链接库的导出表,搜索出所需API地址,然后调用。

test.pdf中的shellcode使用的就是这种方法调用了WinExec函数。

步骤:

1. 通过段选择字FS在内存中找到当前的线程环境块TEBTEB偏移0x30的地方存放指向PEB的指针。

2. TEB偏移0x30的地方存放指向PEB的指针。

mov edx,FS:[eax+0x30]//edx中现在存储指向PEB的指针

3. PEB中偏移0xC的地方存放着指向PEB_LDR_DATA结构体的指针,其中存放着已经被进程装载的动态链接库的信息。(2+1+1+2*4=0xC)

CVE-2010-2883分析

4.  PEB_LDR_DATA结构体偏移0x14的地方存放着InMemoryOrderModuleList。(8+3*4=0x14)

 CVE-2010-2883分析

InMemoryOrderModuleList代表按内存顺序构成的模块链表。包含两个指针,指向下一个LDR_DATA_TABLE_ENTRY中的InMemoryOrderLinks的Flink和指向上一个LDR_DATA_TABLE_ENTRY中的InMemoryOrderLinks的Blink。可以使用InMemoryOrderLinks的Flink遍历进程加载的整个模块。

CVE-2010-2883分析

 CVE-2010-2883分析

 第一个模块AcroRd32.exe。因为这个双向链表链接的都是InMemoryOrderLinks,所以偏移也从InMemoryOrderLinks开始算。

CVE-2010-2883分析

 CVE-2010-2883分析

 第二个模块时ntdll.dll,导出表偏移0x20处的指针指向存储导出函数函数名的列表。计算并比较函数名hash,找到WinExec后,计算出函数地址,调用。

CVE-2010-2883分析

 得到函数地址后调用WinExec即可。

3 总结

CVE-2010-2883利用中使用了栈溢出、堆喷以及动态定位API技术,分析的时候以为只是简单的栈溢出,没想到牵扯出来这么多东西,脑子转的慢,分析了好几天才算是分析完,忘了在哪里看到的一句换,大致意思是“学习漏洞战争这本书之前,先看一下0day安全”,说的真是太好了,我要是分析这个漏洞之前把0day安全实践完了就好了,肯定会很轻松,不至于这么累。其中堆喷、PDF中的JS以及动态定位API都是0day安全这本书中详细说过的,尤其是shellcode中的定位API,0day安全这本书中有它的汇编代码,基本上一模一样,我要是当初认真看了,也不会再这里卡上半天,所以说啊,认真学习,别想着偷懒,欠的债总是要还的。

感慨一下发现这个漏洞以及利用成功的人,简直太牛了,怎么能这么厉害呢,换做是我,根本就想不到这么多的东西,大佬啊,望尘莫及。

4 参考文献

《漏洞战争》

《0day安全:软件漏洞分析技术》