MS07-014调试手记

前面:

该文是去年某月份写的,今日需要写 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~~


2 Responses to “MS07-014调试手记”

  1. gz1x 说:

    分析的不错,再待佳作 :)

    [回复]

  2. 狐狸 说:

    呵呵,路过,顶一下。

    [回复]

Post a Comment