|
前面:
该文是去年某月份写的,今日需要写 shellcode 再重看此文(想想好像没在大萝卜的地盘发帖过),所以… 望路过的朋友指点下关于double free的问题,thx!
分析过程:
1、异常后的栈回溯 /////////////////////////////////////////////////////////////////////////////////////////////// 0:000> ub <Unloaded_ta.dll>+0xba898a: 00ba898b 0000 add byte ptr [eax],al 00ba898d 13d6 adc edx,esi 00ba898f 3083c7415764 xor byte ptr [ebx+645741C7h],al 00ba8995 ff30 push dword ptr [eax] 00ba8997 648920 mov dword ptr fs:[eax],esp // 添加shellcode 的异常处理 00ba899a ba3243313a mov edx,offset <Unloaded_ta.dll>+0×3a314331 (3a314332) 00ba899f 81c214131211 add edx,offset <Unloaded_ta.dll>+0×11121313 (11121314) 00ba89a5 bf00001400 mov edi,offset <Unloaded_ta.dll>+0×13ffff (00140000) 0:000> u <Unloaded_ta.dll>+0xba89a9: 00ba89aa 3b17 cmp edx,dword ptr [edi] // 异常位置 00ba89ac 7403 je <Unloaded_ta.dll>+0xba89b0 (00ba89b1) 00ba89ae 47 inc edi 00ba89af ebf9 jmp <Unloaded_ta.dll>+0xba89a9 (00ba89aa) 00ba89b1 83c704 add edi,4 00ba89b4 67648f060000 pop dword ptr fs:[0000h] 00ba89ba 57 push edi 00ba89bb c3 ret ///////////////////////////////////////////////////////////////////////////////////////////////
异常时的状态 /////////////////////////////////////////////////////////////////////////////////////////////// First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000000 ebx=00142b00 ecx=00000000 edx=4b435646 esi=00000000 edi=00feeffd eip=00ba89aa esp=0011aca4 ebp=6c030a01 iopl=0 nv up ei pl nz na po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010203 <Unloaded_ta.dll>+0xba89a9: 00ba89aa 3b17 cmp edx,dword ptr [edi] ds:0023:00feeffd=00000000
注意到寄存器已经被覆盖 edx=4b435646 ebp=6c030a01
我们再回头看看SEH的回调处理是如何的?
00ba8995 ff30 push dword ptr [eax] 00ba8997 648920 mov dword ptr fs:[eax],esp // 添加shellcode 的异常处理
0:000> dd poi(fs:0) l2 0011aca4 0012f904 00ba896d
这里已经是shellcode了,异常是shellcode搞得鬼。 ///////////////////////////////////////////////////////////////////////////////////////////////
2、栈回溯问题 显然我们这时候用k命令进行回溯已经是错误的了 /////////////////////////////////////////////////////////////////////////////////////////////// 0:000> k ChildEBP RetAddr WARNING: Frame IP not in any known module. Following frames may be wrong. 0011ace8 30d60800 <Unloaded_ta.dll>+0xba89a9 0011acec 00000000 mso!Ordinal2171+0×2ab /////////////////////////////////////////////////////////////////////////////////////////////// 手工回溯栈 /////////////////////////////////////////////////////////////////////////////////////////////// 0:000> !teb TEB at 7ffdd000 ExceptionList: 0011aca4 StackBase: 00130000 // 基地址 StackLimit: 0011a000 // 边界 SubSystemTib: 00000000 FiberData: 00001e00 ArbitraryUserPointer: 00000000 Self: 7ffdd000 EnvironmentPointer: 00000000 ClientId: 000006a4 . 00000fe0 RpcHandle: 00000000 Tls Storage: 00142ad0 PEB Address: 7ffde000 LastErrorValue: 0 LastStatusValue: c0000034 Count Owned Locks: 0 HardErrorMode: 0 ///////////////////////////////////////////////////////////////////////////////////////////////
栈是从基地址往低地址生长的,我从0011a000这个边界往回找 /////////////////////////////////////////////////////////////////////////////////////////////// 0:000> dds 0011a000 0011a000+1000 0011a000 00000000 0011a004 00000000 0011a008 00000000 0011a00c 00000000 0011a010 00000000 0011a014 00000000 0011a018 00000000 0011a01c 00000000 … // 往下是异常处理 0011a87c 7c930833 ntdll!RtlpImageNtHeader+0×56 0011a880 00ba896d <Unloaded_ta.dll>+0xba896c 0011a884 7c920000 ntdll!RtlDosPathSeperatorsString <PERF> (ntdll+0×0) 0011a888 0011ac00 <Unloaded_ta.dll>+0×11abff 0011a88c 7c9200e0 ntdll!RtlDosPathSeperatorsString <PERF> (ntdll+0xe0) 0011a890 0011a880 <Unloaded_ta.dll>+0×11a87f … 0011a9a8 7c92eafa ntdll!KiUserExceptionDispatcher+0xe 0011a9ac 7c92d625 ntdll!NtContinue+0xc 0011a9b0 7c92eb08 ntdll!KiUserExceptionDispatcher+0×1c 0011a9b4 0011a9d8 <Unloaded_ta.dll>+0×11a9d7 0011a9b8 00000000 0011a9bc c0000005 … 0011ace0 00000000 0011ace4 ebc03300 0011ace8 0000003a <Unloaded_ta.dll>+0×39 0011acec 30d60800 mso!Ordinal2171+0×2ab // 这里就 kb 命令能回溯到的地方,出问题的就在下一个吧 0011acf0 00000000 0011acf4 00000000 0011acf8 00000000 0011acfc 00000000 … 0011afac 00000000 0011afb0 00000000 0011afb4 0011aff0 <Unloaded_ta.dll>+0×11afef 0011afb8 300316e8 winword+0×316e8 // 这个就是出问题的函数了 0011afbc 0011aff0 <Unloaded_ta.dll>+0×11afef 0011afc0 30cb099d mso!MsoReleaseMemCore+0×1e // 注意到这个 内存 释放函数 0011afc4 00000003 <Unloaded_ta.dll>+0×2 0011afc8 00000001 <Unloaded_ta.dll> 0011afcc 00000000 ///////////////////////////////////////////////////////////////////////////////////////////////
3、问题函数
我们回头看看 winword+0×316e8 这个函数 /////////////////////////////////////////////////////////////////////////////////////////////// 0:000> uf winword+0×316e8 winword+0×316e8: 300316e8 85db test ebx,ebx 300316ea 8bf0 mov esi,eax 300316ec 5f pop edi 300316ed 0f84d3eb0100 je winword+0×502c6 (300502c6)
winword+0×316f3: 300316f3 ff75fc push dword ptr [ebp-4] 300316f6 ff157c20a730 call dword ptr [winword!wdGetApplicationObject+0x2817a0 (30a7207c)] // 跟的时候这里就是 mso!MsoReleaseMemCore
winword+0×316fc: 300316fc 5b pop ebx 300316fd 8bc6 mov eax,esi 300316ff 5e pop esi 30031700 c9 leave 30031701 c21400 ret 14h
winword+0×502c6: 300502c6 837dfc00 cmp dword ptr [ebp-4],0 300502ca 0f842c14feff je winword+0×316fc (300316fc)
winword+0×502d0: 300502d0 e9f32e3200 jmp winword!wdCommandDispatch+0×9350f (303731c8)
winword!wdCommandDispatch+0×9350f: 303731c8 ff75fc push dword ptr [ebp-4] 303731cb ff150c20a730 call dword ptr [winword!wdGetApplicationObject+0x281730 (30a7200c)] 303731d1 e926e5cbff jmp winword+0×316fc (300316fc) /////////////////////////////////////////////////////////////////////////////////////////////// 既然有释放也必然有 alloc /////////////////////////////////////////////////////////////////////////////////////////////// 0:000> x mso!Mso*MemCore 30cafa50 mso!MsoFAllocMemCore (<no parameter info>) 30cafccb mso!MsoFMarkMemCore (<no parameter info>) 30cb097f mso!MsoReleaseMemCore (<no parameter info>) ///////////////////////////////////////////////////////////////////////////////////////////////
显然这是个堆溢出,用IDA看了下 /////////////////////////////////////////////////////////////////////////////////////////////// int __stdcall sub_30031687(void *a1, int a2, int a3, int a4, int a5) { int v5; // ebx@2 int v6; // esi@4 int v8; // eax@2 int v9; // [sp+10h] [bp-4h]@2 int v10; // [sp+4h] [bp-10h]@4 int v11; // [sp+Ch] [bp-8h]@4 unsigned int v12; // [sp+8h] [bp-Ch]@4
if ( (unsigned int)a3 <= 0xA8C ) { v6 = sub_30050378(a1, a2, a3, a4, a5); } else { v8 = MsoFMarkMemCore(&v9, 0×3FA3u); v5 = v8; if ( !v8 ) v9 = MsoPvAllocCore(0×3FA3u, 2); if ( v9 ) { v10 = 0; v11 = v9; v12 = 0×3FA3u; v6 = sub_30031704(a1, a2, a3, a4, a5, (int)&v10); if ( v5 ) { MsoReleaseMemCore(v9); } else { if ( v9 ) MsoFreePv(v9); } } else { v6 = sub_308FE25F(a1, a2, a3, a4, a5); } } return v6; } ///////////////////////////////////////////////////////////////////////////////////////////////
在最后EBP被覆盖前,有Double Free的现象 /////////////////////////////////////////////////////////////////////////////////////////////// 0:000> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 0012bc84 30038e74 00b80418 08b3b9f4 00000000 mso!MsoReleaseMemCore 0012c0cc 3006df62 08b3b9f4 00000117 00000000 winword+0×38e74 0012c100 3006deb0 00000117 000c0838 0012c128 winword+0×6df62 0012c138 3006db3f 00b80398 00b80398 0cea08ca winword+0×6deb0 0012c170 30071151 00000001 00b80398 0cea08ca winword+0×6db3f 0012c228 30073769 00b80398 00000000 00000000 winword+0×71151 0012c2b8 3007250e 00b80398 0cea07e8 08b388dc winword+0×73769 0012c2e0 3006a9a0 00b80398 08b388dc 00000008 winword+0×7250e 0012c520 30067b12 08b3b060 08b388dc 00000800 winword+0×6a9a0 0012c640 7c80ac78 30c90000 00000000 30c90000 winword+0×67b12 0012c6bc 7c80ac66 0012c6e4 7c80ac78 30c90000 kernel32!GetProcAddress+0×5b 0012c6e4 0012c6d4 30c90000 0012f904 315ddcb7 kernel32!GetProcAddress+0×43 0012c6fc 31444fc6 31444ff3 00b80174 314450a8 <Unloaded_ta.dll>+0×12c6d3 0012c700 31444ff3 00b80174 314450a8 00b95de8 mso!Ordinal3198+0×5f 0012c708 314450a8 00b95de8 000000d8 300d4250 mso!Ordinal2669+0×1f 0012c724 305d3ca5 00000001 000000d8 000000c8 mso!Ordinal2402+0×13 0012c73c 305d410b 00000000 00000003 00b80174 winword!wdCommandDispatch+0×2f3fec 0012c764 305db543 305db54a 0012c798 00000000 winword!wdCommandDispatch+0×2f4452 0012c7d8 3003ce45 3003ce53 08b3809c 08b37c7c winword!wdCommandDispatch+0×2fb88a 00000000 00000000 00000000 00000000 00000000 winword+0×3ce45 0:000> g Breakpoint 1 hit eax=00000001 ebx=08b3b9f4 ecx=0012bc58 edx=7c92eb94 esi=00000000 edi=0012beb4 eip=30cb097f esp=0012bc80 ebp=0012bd98 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 mso!MsoReleaseMemCore: 30cb097f 57 push edi 0:000> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 0012bd98 00000000 0012f904 00000002 0e19ab00 mso!MsoReleaseMemCore 0:000> g Breakpoint 1 hit eax=00000001 ebx=00000000 ecx=08b3bad4 edx=7c92eb94 esi=00000001 edi=08b3bad4 eip=30cb097f esp=0012bc6c ebp=0012bc80 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 mso!MsoReleaseMemCore: 30cb097f 57 push edi 0:000> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 0012bc80 30038e74 00b80418 08b3bad4 00000000 mso!MsoReleaseMemCore 0012c0c8 3006df62 08b3bad4 00000116 00000000 winword+0×38e74 0012c0fc 3006e74c 00000116 000c0838 0012c128 winword+0×6df62 0012c138 3006e701 00b80398 00b80398 0cea08ca winword+0×6e74c 0012c170 30071151 00000001 00b80398 0cea08ca winword+0×6e701 0012c228 30073769 00b80398 00000000 00000000 winword+0×71151 0012c2b8 3007250e 00b80398 0cea07e8 08b388dc winword+0×73769 0012c2e0 3006a9a0 00b80398 08b388dc 00000008 winword+0×7250e 0012c520 30067b12 08b3b060 08b388dc 00000800 winword+0×6a9a0 0012c640 7c80ac78 30c90000 00000000 30c90000 winword+0×67b12 0012c6bc 7c80ac66 0012c6e4 7c80ac78 30c90000 kernel32!GetProcAddress+0×5b 0012c6e4 0012c6d4 30c90000 0012f904 315ddcb7 kernel32!GetProcAddress+0×43 0012c6fc 31444fc6 31444ff3 00b80174 314450a8 <Unloaded_ta.dll>+0×12c6d3 0012c700 31444ff3 00b80174 314450a8 00b95de8 mso!Ordinal3198+0×5f 0012c708 314450a8 00b95de8 000000d8 300d4250 mso!Ordinal2669+0×1f 0012c724 305d3ca5 00000001 000000d8 000000c8 mso!Ordinal2402+0×13 0012c73c 305d410b 00000000 00000003 00b80174 winword!wdCommandDispatch+0×2f3fec 0012c764 305db543 305db54a 0012c798 00000000 winword!wdCommandDispatch+0×2f4452 0012c7d8 3003ce45 3003ce53 08b3809c 08b37c7c winword!wdCommandDispatch+0×2fb88a 00000000 00000000 00000000 00000000 00000000 winword+0×3ce45 ///////////////////////////////////////////////////////////////////////////////////////////////
覆盖后的 /////////////////////////////////////////////////////////////////////////////////////////////// 0:000> r ebp ebp=6c030a01
注意doc便宜 BE8 位置上的内容 Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000BE0 00 00 00 FF 34 D6 06 00 01 0A 03 6C C4 33 00 30 …�4?….l?.0 00000BF0 00 00 06 00 00 16 24 01 49 66 01 00 00 00 00 05 ……$.If…… ///////////////////////////////////////////////////////////////////////////////////////////////
往下走的时候 /////////////////////////////////////////////////////////////////////////////////////////////// 0:000> u winword+0×33c4: 300033c4 55 push ebp 300033c5 8bec mov ebp,esp 300033c7 833d74d2a83002 cmp dword ptr [winword!wdGetApplicationObject+0x29c998 (30a8d274)],2 300033ce 0f855c903600 jne winword!wdCommandDispatch+0×8c777 (3036c430) 300033d4 ff15bc130030 call dword ptr [winword+0x13bc (300013bc)] 300033da 85c0 test eax,eax 300033dc 7410 je winword+0×33ee (300033ee) 300033de ff750c push dword ptr [ebp+0Ch] 0:000> u winword+0×33e1: 300033e1 ff7508 push dword ptr [ebp+8] 300033e4 50 push eax 300033e5 e80d000000 call winword+0×33f7 (300033f7) 300033ea 5d pop ebp 300033eb c20800 ret 8 // 需要用到 ret 8 来协调 /////////////////////////////////////////////////////////////////////////////////////////////// 接下来就是要的shellcode
总结如下: 利用 WORD 存在的 Double Free 实现覆盖, 然后通过300033eb地址上的通用调转来实现最终shellcode的执行。 shellocode 利用 异常机制来反杀毒软件对shellcode的检测。(其实我对 double free 是不明白的,望大牛路过指教下!)
AVP特征: /////////////////////////////////////////////////////////////////////////////////////////////// 0xb7e – 0xbf7
所在格式:
Border Code (BRC) -> sprmTTableBorders
sprmTTableBorders 0xd613 change tap.rgbrcTable BRC[6] (see below) variable length sprmTTableBorders (opcode 0xD613) sets the tap.rgbrcTable. The sprm is interpreted by moving the 48 bytes of the sprmBRCs) to tap.rgbrcTable.
avp不是这个格式来定位特征,应该是死偏移来解决的。 ///////////////////////////////////////////////////////////////////////////////////////////////
支持大萝卜的 softrce~~
|