何为缓冲区溢出
缓冲区溢出是指当计算机程序向缓冲区内填充的数据位数超过了缓冲区本身的容量。溢出的数据覆盖在合法数据上。理想情况是,程序检查数据长度并且不允许输入超过缓冲区长度的字符串。但是绝大多数程序都会假设数据长度总是与所分配的存储空间相匹配,这就为缓冲区溢出埋下隐患。操作系统所使用的缓冲区又被称为堆栈,在各个操作进程之间,指令被临时存储在堆栈当中,堆栈也会出现缓冲区溢出。
当一个超长的数据进入到缓冲区时,超出部分就会被写入其他缓冲区,其他缓冲区存放的可能是数据、下一条指令的指针,或者是其他程序的输出内容,这些内容都被覆盖或者破坏掉。可见一小部分数据或者一套指令的溢出就可能导致一个程序或者操作系统崩溃。
溢出根源在于编程
缓冲区溢出是由编程错误引起的。如果缓冲区被写满,而程序没有去检查缓冲区边界,也没有停止接收数据,这时缓冲区溢出就会发生。缓冲区边界检查被认为是不会有收益的管理支出,计算机资源不够或者内存不足是编程者不编写缓冲区边界检查语句的理由,然而摩尔定律已经使这一理由失去了存在的基础,但是多数用户仍然在主要应用中运行十年甚至二十年前的程序代码。
缓冲区溢出之所以泛滥,是由于开放源代码程序的本质决定的。一些编程语言对于缓冲区溢出是具有免疫力的,例如Perl能够自动调节字节排列的大小,Ada95能够检查和阻止缓冲区溢出。但是被广泛使用的C语言却没有建立检测机制。标准C语言具有许多复制和添加字符串的函数,这使得标准C语言很难进行边界检查。C++略微好一些,但是仍然存在缓冲区溢出。一般情况下,覆盖其他数据区的数据是没有意义的,最多造成应用程序错误,但是,如果输入的数据是经过“黑客”或者病毒精心设计的,覆盖缓冲区的数据恰恰是“黑客”或者病毒的入侵程序代码,一旦多余字节被编译执行,“黑客”或者病毒就有可能为所欲为,获取系统的控制权。
溢出导致“黑客”病毒横行
缓冲区溢出是病毒编写者和特洛伊木马编写者偏爱使用的一种攻击方法。攻击者或者病毒善于在系统当中发现容易产生缓冲区溢出之处,运行特别程序,获得优先级,指示计算机破坏文件,改变数据,泄露敏感信息,产生后门访问点,感染或者攻击其他计算机。
2000年7月,微软Outlook以及Outlook Express被发现存在漏洞能够使攻击者仅通过发送邮件就能危及目标主机安全,只要邮件头部程序被运行,就会产生缓冲区溢出,并且触发恶意代码。2001年8月,“红色代码”利用微软IIS漏洞产生缓冲区存溢出,成为攻击企业网络的“罪魁祸首”。2003年1月,Slammer蠕虫利用微软SQL漏洞产生缓冲区溢出对全球互联网产生冲击。而在近几天,一种名为“冲击波”的蠕虫病毒利用微软RPC远程调用存在的缓冲区漏洞对Windows 2000/XP、Windows Server 2003进行攻击,波及全球网络系统。据CERT安全小组称,操作系统中超过50%的安全漏洞都是由内存溢出引起的,其中大多数与微软技术有关,这些与内存溢出相关的安全漏洞正在被越来越多的蠕虫病毒所利用。
缓冲区溢出是目前导致“黑客”型病毒横行的主要原因。从红色代码到Slammer,再到日前爆发的“冲击波”,都是利用缓冲区溢出漏洞的典型。缓冲区溢出是一个编程问题,防止利用缓冲区溢出发起的攻击,关键在于程序开发者在开发程序时仔细检查溢出情况,不允许数据溢出缓冲区。此外,用户需要经常登录操作系统和应用程序提供商的网站,跟踪公布的系统漏洞,及时下载补丁程序,弥补系统漏洞。
一个溢出攻击的实例分析
下面是一个简单实例,可以显示缓冲区溢出是如何产生的以及缓冲区溢出是如何被黑客或病毒利用的。首先,我们先来分析一段程序。
int i;
void function(void)
{char buffer[240]; //create a buffer
for (i=0;
buffer[i]='A';//copy the letter A return}
接下来是当这个函数被执行时的后果。
1)函数使用长度为240个字节的缓冲区,该缓冲区恰好位于内存地址是00000077
缓冲区地址(8字节)
00000077
缓冲区内容(240字节)
空白
旧基址指针(8字节)
12345678
返回的指令指针(8字节)
00401000
2)程序被执行时,函数开始将A填写到缓冲区中
缓冲区地址(8字节)
00000077
缓冲区内容(240字节)
AAAAAAAAA......
旧基址指针(8字节)
12345678
返回的指令指针(8字节)
00401000
3)超过240个字节,缓冲区被写满了,240个字节以后的内容溢出到下一个内存区域,覆盖旧基址指针和返回指令指针
缓冲区地址(8字节)
00000077
缓冲区内容(240字节)
AAAAAAAAA......
旧基址指针(8字节)
AAAAAAAA
返回的指令指针(8字节)
AAAAAAAA
4)现在假设函数没有填写A,而是插入了恶意代码
缓冲区地址(8字节)
00000077
缓冲区内容(240字节)
恶意代码......
旧基址指针(8字节)
12345678
返回的指令指针(8字节)
40100000
5)缓冲区被填满了恶意代码,旧基址指针也被改写
缓冲区地址(8字节)
00000077
缓冲区内容(240字节)
恶意代码......
旧基址指针(8字节)
××××××××
返回的指令指针(8字节)
00401000
6)接下来返回的指令指针也被改写,不是随机而是根据现在包含恶意代码的缓冲区本身的地址
缓冲区地址(8字节)
00000077
缓冲区内容(240字节)
恶意代码......
旧基址指针(8字节)
××××××××
返回的指令指针(8字节)
00000077
7)在缓冲区被填满之后,程序定位在指令指针提供的地址处,并且开始执行恶意代码。