
堆栈溢出对于我们软件开发人员来说,最严重的后果是毁坏了存储中的指针,及其导致的一系列难查的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找不到它的返回地址导致的。但是现在我们的目的,利用溢出执行其它代码的任务即将实现了
1988年,世界上第一个缓冲区溢出攻击——Morris蠕虫在互联网上泛滥,短短一夜的时间全世界6000多台网络服务器瘫痪或半瘫痪,不计其数的数据和资料损毁。造成一场损失近亿美元的空前大劫难!
缓冲区
计算机程序通常还会使用到一些存储,这些内存或是程序内部使用,或是保存客户的输入数据,这样的存储通常也称缓冲区。
溢出

溢出是指盛放的东西超过容器容量而溢起来了,在计算机程序中,就是数据使用至了被分配存储空间之外的内存空间。
缓冲区溢出
缓冲区溢出简单的说就是计算机对接收的输入数据没有进行有效的监测(理想的状况是程序检测数据长度并不允许输入超过缓冲区长度的数组),向缓冲区内填充数据时达到了缓冲区本身的容量,而造成数据溢出至被分配空间之外的存储空间,使得溢出的数据覆盖了其它存储空间的数据。
缓冲区溢出是一种非常危险的漏洞,在各类操作系统、应用工具中广泛存在。利用缓冲区溢出攻击,可以避免程序运行失败、系统断电、重新启动等后果。更为严重的是,可以运用它执行非授权指令,甚至可以获得平台特权,进而进行各类非法操作。
缓冲区溢出就好比一个杯子倒太多的水,洒出去,这叫溢出。它是一种非常普遍、非常危险的漏洞,最常发生在C/C++编写的程序中。
早期,人们还不这么重视数据安全的之后,往往会使用像strcpy这类不安全函数,这种变量对客户的输入不作任何检查,总之,来自不拒,那么,分配的存储空间是有限的,如果输入超长的字符串,必然会导致溢出。

讲了这么多,小伙伴会不会有点晕吗?其实,缓冲区溢出很容易理解的。下面我们看一个具体的举例:

这段代码存在一个经典的缓冲区溢出漏洞strcpy,为str变量分配了8个字节的空间,输入大于等于8个字符,那没问题:

但是当我们输入超长的数据时,问题发生了

缓冲区溢出带来的危害
在计算机安全领域,缓冲区溢出就好比帮自己的程序开了个后门,这种安全隐患是致命的。缓冲区溢出在各类操作系统、应用工具中广泛存在。而运用缓冲区溢出漏洞实施的伤害就是缓冲区溢出攻击。
缓冲区溢出攻击,可以避免程序运行失败、系统开机、重新启动,或者执行攻击者的指令,比如非法提升权限。假如问题发生在常见的一些工具,比如操作系统、浏览器、通讯工具等,那后果不堪想象。
缓冲区溢出中,最为危险的是堆栈溢出,因为入侵者可以利用堆栈溢出,在变量返回时改变返回程序的地址,让其跳转至任意地址,带来的伤害一种是程序崩溃造成反对服务,另外一种就是跳转并且执行一段恶意代码,比如得到系统权限,然后为所欲为。
有也许小伙伴你会对病毒/蠕虫没有概念,那我们来举一个简单的事例吧。平时玩手机的之后,你正在听歌,突然间收到未知的“朋友”发给你的一个m3u音频文件,并引导你进行电击——“这首歌很好听呢,你也看看”。
凑巧的是,你电脑刚好了就装了VUPlayer.exe 这个播放器,不多想,就打开这个音乐想看看看,奇怪的是,软件闪了一下就退出了,你以为是文件损坏了了吧。其实,这个之后,你将要被红了,没错!这就是那个播放器。

很普通的播放器,但是它存在致命缓冲区溢出漏洞。我们构造10000个A的m3u文件,然后用调试器附加VUPlayer.exe,打开文件:

我们发现以下的存储全部被字符A覆盖了,其实就是使用了不安全的lstrcpyA函数引起溢出,这个是栈溢出,还有一种是堆溢出,但本质是一样的。
证明有溢出漏洞然后缓冲区溢出攻击,往往必须进一步探讨,不同的人目的不却相似,但必须注意的是,也有众多“黑市”的会攻击政府机构或企业的平台,盗取机密文件等,这是十分危险的。
如何预防
缓冲区溢出是代码中固有的漏洞,除了在开发阶段应留意编写正确的代码之外,对于用户而言,一般的应对机制为
1、关闭端口或服务,管理员应该了解自己的平台上安装了哪个,并且这些服务正在运行。
2、安装工具厂商的补丁,需要尽快安装漏洞补丁。
3、在防火墙上过滤特殊的流量,无法阻挡内部人员的溢出攻击。
4、检查关键的服务程序,看看能否有可怕的漏洞。
5、以所必须的最小权限运行硬件。
6、可通过安防软件提高操作系统安全级别,比如优炫操作系统安全提升系统。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-144399-1.html
打个比方
Luna真的变美好多