首页 百科知识 缓冲区溢出

缓冲区溢出

时间:2024-10-04 百科知识 版权反馈
【摘要】:正常情况下,程序应该检查所使用的数据长度以防止出现输入的字符长度超过缓冲区长度的情况出现,但是绝大多数程序在编写时都会假设数据长度总是与所分配的储存空间相匹配,这就为缓冲区溢出埋下了安全隐患。缓冲区溢出攻击通常是利用堆栈段的溢出。如果能有效地消除缓冲区溢出的漏洞,则很大一部分的安全威胁可以得到缓解。

任务概述

缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种操作系统、应用软件中广泛存在。利用缓冲区溢出攻击,攻击者可以导致程序运行失败、系统崩溃、重新启动等后果,更为严重的是,可以利用它来执行非授权指令,甚至取得系统控制权,进而进行各种非法操作。

任务目标

●能够了解缓冲区溢出的概念及原理

●能够了解缓冲区溢出的危害

●能够掌握保护缓冲区免受缓冲区溢出的攻击和影响的4种方法

学习内容

一、缓冲区溢出

缓冲区溢出攻击现在已经成为一种常见的安全攻击手段,因为缓冲区溢出漏洞太普遍且易于实现,不论是Unix/Linux还是Windows都存在这样的漏洞。而在遭受缓冲区溢出攻击后,Linux和Windows的结果是不同的,Linux缓冲区溢出的必然结果就是获得管理员的权限,而Windows则不一定,可能是系统崩溃,也可能是获得管理员的权限。

缓冲区,简单说来是一块连续的计算机内存区域,可以保存相同数据类型的多个实例。缓冲区溢出是指当程序向缓冲区内填充数据的长度位数超过了缓冲区本身的长度时,溢出的数据覆盖在合法数据上或被放置到其他的内存区域的现象。一个应用程序,为了不用太多的内存,通常在代码中都使用了许多的动态变量以使程序在运行时才为它们分配使用内存,这样就很容易造成程序在动态分配缓冲区放入太多的数据而使得缓冲区溢出。单单的缓冲区溢出,并不会产生安全问题,但是如果一个缓冲区溢出的应用程序将能运行的指令放在了有root权限的内存中,一旦运行这些指令,就能以root权限控制计算机了。正常情况下,程序应该检查所使用的数据长度以防止出现输入的字符长度超过缓冲区长度的情况出现,但是绝大多数程序在编写时都会假设数据长度总是与所分配的储存空间相匹配,这就为缓冲区溢出埋下了安全隐患。

缓冲区溢出攻击指的是一种系统攻击的手段,通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行其他指令,以达到攻击的目的。

二、缓冲区溢出攻击的危害

在当前的网络与分布式系统攻击中,被广泛利用的系统攻击手段有50%以上都是缓冲区溢出,因为缓冲区溢出攻击可能会令攻击者能够植入并且执行攻击代码。被植入的攻击代码以一定的权限运行有缓冲区溢出漏洞的程序,从而得到被攻击主机的控制权。

在缓冲区溢出中,最为危险的是堆栈溢出,因为入侵者可以利用堆栈溢出,在函数返回时改变返回程序的地址,让其跳转到任意地址,带来的危害一种是程序崩溃导致拒绝服务,另外一种就是跳转并且执行一段恶意代码,比如得到shell,然后为所欲为。操作系统所使用的缓冲区被称为“堆栈”,其代码中所使用的动态变量在程序运行时都保存于堆栈之中,可见,缓冲区溢出攻击对操作系统的危害是很大的。缓冲区溢出攻击通常是利用堆栈段的溢出。

三、缓冲区溢出攻击的过程和防范

1.缓冲区溢出攻击的过程

缓冲区溢出攻击的目的在于扰乱具有某些特权的程序的功能,这样可以使得攻击者取得程序的控制权,如果该程序具有足够的权限,那么整个主机就被控制了。一般而言,攻击者攻击root程序,然后执行类似exec(sh)的执行代码来获得root权限的shell。为了达到这个目的,攻击者必须达到如下的两个目标:

(1)代码植入:在程序的地址空间里安排适当的代码。攻击者向被攻击的程序输入一个可以在这个被攻击的硬件平台上运行的指令序列字符串,程序接收这个字符串后就会把这个字符串放到缓冲区里。缓冲区可以是堆栈(stack,存放动态变量)、堆(heap,动态分配的内存区)和静态资料区等内存区域,这样,攻击代码就可以被执行,从而达到攻击者的目的。

如果攻击者试图使用已经常驻的代码而不是从外部植入代码,他们通常必须把代码作为参数调用。举例来说,在libc(几乎所有的C程序都要它来连接)中的部分代码段会执行exec(something),其中something就是参数。攻击者使用缓冲区溢出改变程序的参数,然后利用另一个缓冲区溢出使程序指针指向libc中的特定的代码段。

代码植入和缓冲区溢出不一定要在一次动作内完成。攻击者可以在一个缓冲区内放置代码,这是不能溢出的缓冲区,然后,攻击者通过溢出另外一个缓冲区来转移程序的指针。这种方法一般用来解决可供溢出的缓冲区不够大(不能放下全部的代码)的问题。

(2)地址跳转:通过适当的初始化寄存器和内存,让程序跳转到入侵者安排的地址空间执行。改变程序的执行流程,使之跳转到攻击代码,最基本的就是溢出一个没有边界检查或者其他弱点的缓冲区,这样就扰乱了程序的正常的执行顺序。通过溢出一个缓冲区,攻击者可以用暴力的方法改写相邻的程序空间而直接跳过系统的检查。攻击者所寻求的缓冲区溢出的程序空间类型原则上可以是任意的空间。实际上,许多的缓冲区溢出是用暴力的方法来寻求改变程序指针的,区别是程序空间的突破和内存空间的定位不同。

2.缓冲区溢出攻击的防范

缓冲区溢出攻击占了远程网络攻击的绝大多数,这种攻击可以使得一个匿名的Inter-net用户有机会获得一台主机的部分或全部的控制权。如果能有效地消除缓冲区溢出的漏洞,则很大一部分的安全威胁可以得到缓解。

目前有4种基本的方法保护缓冲区免受缓冲区溢出的攻击和影响:编写正确的代码,非执行的缓冲区,数组边界检查,程序指针完整性检查。

(1)编写正确的代码:编写正确的代码是一件非常有意义但耗时的工作,特别是像编写C语言那种具有容易出错倾向的程序,虽然这种风格是由于追求性能而忽视正确性的传统所引起的。尽管人们花了很长的时间知道了如何编写安全的程序,但具有安全漏洞的程序依旧出现,因此人们开发了一些工具和技术来帮助经验不足的程序员编写安全正确的程序。最简单的方法就是用GREP(Unix/Linux系统)来搜索源代码中容易产生的漏洞时库的调用,比如对strcpy和sprintf的调用,或者使用一些高级的查错工具通过人为随机地产生一些缓冲区溢出来寻找代码的安全漏洞,也可以使用一些静态分析工具来侦测缓冲区溢出的存在。虽然这些工具可以帮助程序员开发更安全的程序,但是它们也只能用来减少缓冲区溢出的可能,并不能完全地消除它的存在,除非程序员能保证他的程序万无一失。

(2)非执行的缓冲区:通过使被攻击程序的数据段地址空间不可执行,从而使得攻击者不可能执行植入被攻击程序输入缓冲区的代码,这种技术被称为非执行的缓冲区技术。事实上,很多老的Unix系统都是这样设计的,但是近来的Unix和Windows系统为实现更好的性能和功能,往往在数据段中动态地放入可执行的代码,所以为了保持程序的兼容性不可能使得所有程序的数据段不可执行。但是人们可以设定堆栈数据段不可执行,这样就可以最大限度地保证程序的兼容性。Linux和Solaris都发布了有关这方面的内核补丁。因为几乎没有任何合法的程序会在堆栈中存放代码,这种做法几乎不产生任何兼容性问题,除了在Linux中的两个特例——信号传递和GCC的在线重用,这时可执行的代码必须被放入堆栈中。

(3)数组边界检查:数组边界检查可以避免缓冲区溢出的产生和攻击,因为只要数组不能被溢出,溢出攻击也就无从谈起。为了实现数组边界检查,所有的对数组的读写操作都应当被检查,以确保对数组的操作在正确的范围内。最直接的方法是检查所有的数组操作。

(4)程序指针完整性检查:程序指针完整性检查和边界检查略有不同。与防止程序指针被改变不同,程序指针完整性检查在程序指针被引用之前需检测它是否被改变。这样,即便一个攻击者成功地改变了程序的指针,但由于系统事先检测到了指针的改变,所以这个指针将不会被使用。与数组边界检查相比,这种方法不能解决所有的缓冲区溢出问题,采用其他的缓冲区溢出方法就可以避免这种检测,但是这种方法在性能上有很大的优势而且兼容性也很好。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈