缓冲区溢出是当今流行的一种网络攻击方法,它易于攻击而且危害严重,给系统的安全带来了极大的隐患。因此,如何及时有效地检测出计算机网络系统攻击行为,已越来越成为网络安全管理的一项重要内容。
目前有4种基本的方法保护缓冲区免受缓冲区溢出的攻击和影响,包括编写正确的代码、非执行的缓冲区、数组边界检查和程序指针完整性检查。
编写正确的代码是防止缓冲区溢出攻击最直接最有效的方法,也是一件非常有意义的工作,特别是编写像C语言那种具有容易出错倾向的程序更显得很有意义。然而,尽管花了很长的时间使得人们知道了如何编写安全的程序组,但是具有安全漏洞的程序依旧出现。为此,人们又开发了一些工具和技术来帮助经验不足的程序员编写安全正确的程序代码。
最简单的方法就是用grep来搜索源代码中容易产生漏洞的库的调用,然而依然有漏网之鱼存在。为了应对这些问题,人们又开发了一些高级的查错工具,如faultinjection等。这些工具的目的在于通过人为随机地产生一些缓冲区溢出来寻找代码的安全漏洞,还有一些静态分析工具,用于侦测缓冲区溢出的存在。
虽然这些工具可以帮助程序员开发更安全的程序,但是由于C语言的特点,这些工具不可能找出所有的缓冲区溢出漏洞。所以,侦错技术只能用来减少缓冲区溢出的可能,并不能完全地消除它的存在,除非程序员能保证他的程序万无一失。
通过使被攻击程序的数据段地址空间不可执行,从而使得攻击者不可能执行被植入被攻击程序输入缓冲区的代码,这种技术被称为非执行的缓冲区技术。事实上,很多旧的UNIX系统都是这样设计的,但是近来的UNIX和Windows系统为实现更好的性能和功能,往往在数据段中动态地放入可执行的代码,所以,为了保持程序的兼容性,不可能使得所有程序的数据段不可执行。
针对这一问题,用户可以设定堆栈数据段不可执行,这样就可以最大限度地保证了程序的兼容性。Linux和Windows都发布了有关这方面的内核补丁,因为几乎没有任何合法的程序会在堆栈中存放代码,这种做法几乎不产生任何兼容性问题,但是在Linux中的两个特例中,可执行的代码必须被放入堆栈中,因此这个方法虽好,但还是不能完全地杜绝所有的缓冲区溢出漏洞的攻击。
非执行堆栈的保护可以有效地应对把代码植入自动变量的缓冲区溢出攻击,而对于其他形式的攻击则没有效果。通过引用一个驻留的程序的指针,就可以跳过这种保护措施。其他的攻击可以采用把代码植入堆栈或者静态数据段中来跳过保护。
数组边界检查能防止所有的缓冲区溢出的产生和攻击。这是因为只要数组不能被溢出,也就是说,如果数据不允许超过长度,溢出攻击也就无从谈起。为了实现数组边界检查,就需要把所有对数组的读写操作都检查一遍,以确保对数组的操作在正确的范围。最直接的方法是检查所有的数组操作,但是通常可以来用一些优化的技术来减少检查的次数。目前有以下的几种检查方法。
1)Compaq C编译器
Compaq公司为Alpha CPU开发的C编译器支持有限度的边界检查(使用check_bounds参数)。它的检查是有限的,存在以下限制:
(1)只有显示的数组引用才被检查,如a[3]会被检查,而“*(a+3)”则不会。
(2)由于所有的C数组在传送的时候是指针传递的,所以传递给函数的数组不会被检查。
(3)带有危险性的库函数(如strcpy)不会在编译的时候进行边界检查,即便是指定了边界检查。在C语言中利用指针进行数组操作和传递是非常频繁的,因此这种局限性是非常严重的。通常这种边界检查用来程序的查错,不能保证不发生缓冲区溢出的漏洞。
2)C数组边界检查
Richard Jones和Paul Kelly开发了一个gcc的补丁,用来实现对C程序完全的数组边界检查。而且由于没有改变指针的含义,所以被编译的程序和其他的gcc模块具有很好的兼容性。更进一步的是,他们由此从没有指针的表达式中导出了一个“基”指针,然后通过检查这个基指针来侦测表达式的结果是否在允许的范围之内。
(1)Purify工具:存储器存取检查。
Purify是C程序调试时查看存储器使用的工具而不是专用的安全工具。Purify使用“目标代码插入”技术来检查所有的存储器存取。
(2)类型安全的语言。
目前,大部分的缓冲区溢出漏洞都源于C语言的类型不安全。如果只有类型安全的操作才可以被允许执行,这样就不可能出现对变量的强制操作。作为新手,推荐使用具有类型安全的语言,如Java和ML。但是,作为Java执行平台的Java虚拟机是C程序,因此攻击JVM的一条途径是使JVM的缓冲区溢出。
程序指针完整性检查和边界检查有略微的不同。与防止程序指针被改变不同,程序指针完整性检查在程序指针被引用之前检测到它的改变。因此,即便一个攻击者成功地改变程序的指针,由于系统事先检测到了指针的改变,因此这个指针将不会被使用。与数组边界检查相比,这种方法不能解决所有的缓冲区溢出问题;采用其他的缓冲区溢出方法就可以避免这种检测。但是这种方法在性能上有很大的优势,而且兼容性也很好。
防范缓冲区溢出的根本方法对于计算机普通用户并不适合,下面介绍一下普通的用户如何才能有效地防止溢出漏洞的攻击。
防范缓冲区溢出攻击的最简单方法是删除有漏洞的软件,如果默认安装的软件不使用,则关闭或删除这些软件,并关闭相应的端口和服务。
多数情况下,一个缓冲区漏洞刚刚公布,厂商就会发布或者将软件升级到新的版本。多关注一下这些内容,及时安装这些补丁或下载使用最新版本的软件,这是防范缓冲区漏洞攻击非常有效的方法。另外,应该及时检查关键程序,在有些情况下,用户可以自行对程序进行检查,以查找最新的漏洞补丁和版本软件。
对于缓冲区溢出攻击,正确地配置所有的软件并使它们运行在尽可能少的权限下是非常关键的。例如,POLP要求运行在系统上的所有程序软件或是使用系统的任何人,都应该尽量给它们最小的权限,其他的权限一律禁止。
在溢出成功后,黑客必须调用系统中的cmd.exe程序来获得CMD Shell,要想阻止黑客的这一行为,必须对CMD进行权限控制,常用的就是对其进行加密处理。具体的操作步骤如下。
Step 01 下载并解压缩“加密CMD防溢出工具”压缩包,在其中双击可执行文件,即可打开“加密CMD防溢出工具”主界面,如下图所示。
Step 02 单击“加密CMD”按钮,即可弹出成功加密提示框,且默认的密码是admin,如下图所示。
Step 03 在加密成功后,再运行CMD程序时,会要求用户输入密码才能登录,如下图所示。
Step 04 如果想要修改默认的密码,则可以单击“加密CMD防溢出工具”主界面中的“修改信息”按钮,打开“修改CMD窗口信息”代码窗口,在其中的admin参数修改为自己设置的密码即可,如下图所示。
Step 05 修改完毕后,右击,在弹出的快捷菜单中选择“保存”选项,即可保存为自己需要的密码,并弹出“信息”对话框,提示用户保存成功,如下图所示。
Step 06 如果不想再为CMD加密,则可以在主界面中单击“解密CMD”按钮,弹出“信息”对话框,提示用户解密成功,如下图所示。
在对CMD进行加密后,即使黑客获得了CMD Shell,但是在利用系统命令添加账号时,会通过TFTP、FTP和VBS等方式上传文件或进一步控制服务器时,由于各种命令被进行了权限设置,也无法获取溢出主机的控制权,这就起到了保护主机的目的。