安全编程

1988 年 11 月,许多组织不得不因为“Morris 蠕虫”而切断 Internet 连接,“Morris 蠕虫”是 23 岁的程序员 Robert Tappan Morris 编写的用于攻击 VAX 和 Sun 机器的程序。 据有关方面估计,这个程序大约使得整个 Internet 的 10% 崩溃。 2001 年 7 月,另一个名为“Code Red”的蠕虫病毒最终导致了全球运行微软的 IIS Web Server 的 300,000 多台计算机受到攻击。2003 年 1 月,“Slammer”(也称为“Sapphire”)蠕虫利用 Microsoft SQL Server 2000 中的一个缺陷,使得南韩和日本的部分 Internet 崩溃,中断了芬兰的电话服务,并且使得美国航空订票系统、信用卡网络和自动出纳机运行缓慢。所有这些攻击 ―― 以及其他许多攻击,都利用了一个称做为 缓冲区溢出 的程序缺陷。

1999 年 Bugtraq(一个讨论安全缺陷的邮件列表)进行的一次非正式调查发现,三分之二的参与者认为第一号的缺陷就是缓冲区溢出(要了解相关背景,请参阅本文后面 参考资料部分列出的“Buffer Overflows: Attacks and Defenses for the Vulnerability of the Decade”一文)。从 1997 年到 2002 年 3 月,CERT/CC 发出的半数安全警报都基于缓冲区缺陷。

如果希望自己的程序是安全的,您需要知道什么是缓冲区溢出,如何防止它们,可以采用哪些最新的自动化工具来防止它们(以及为什么这些工具还不足够),还有如何在您自己的程序中防止它们。

什么是缓冲区溢出?

缓冲区以前可能被定义为“包含相同数据类型的实例的一个连续计算机内存块”。在 C 和 C++ 中,缓冲区通常是使用数组和诸如 malloc() 和 new 这样的内存分配例程来实现的。极其常见的缓冲区种类是简单的字符数组。 溢出 是指数据被添加到分配给该缓冲区的内存块之外。

如果攻击者能够导致缓冲区溢出,那么它就能控制程序中的其他值。虽然存在许多利用缓冲区溢出的方法,不过最常见的方法还是“stack-smashing”攻击。Elias Levy (又名为 Aleph One)的一篇经典文章“Smashing the Stack for Fun and Profit”解释了 stack-smashing 攻击,Elias Levy 是 Bugtraq 邮件列表(请参阅 参考资料 以获得相关链接)的前任主持人。

为了理解 stack-smashing 攻击(或其他任何缓冲区攻击)是如何进行的,您需要了解一些关于计算机在机器语言级实际如何工作的知识。在类 UNIX 系统上,每个进程都可以划分为三个主要区域:文本、数据和堆栈。 文本区域包括代码和只读数据,通常不能对它执行写入操作。 数据区域同时包括静态分配的内存(比如全局和静态数据)和动态分配的内存(通常称为 )。 堆栈区域用于允许函数/方法调用;它用于记录函数完成之后的返回位置,存储函数中使用的本地变量,向函数传递参数,以及从函数返回值。每当调用一个函数,就会使用一个新的 堆栈帧来支持该调用。了解这些之后,让我们来考察一个简单的程序。


清单 1. 一个简单的程序

void function1(int a, int b, int c) {   char buffer1[5];   gets(buffer1); /* DON'T DO THIS */}void main() {  function(1,2,3);}

 

假设使用 gcc 来编译清单 1 中的简单程序,在 X86 上的 Linux 中运行,并且紧跟在对 gets() 的调用之后中止。此时的内存内容看起来像什么样子呢?答案是它看起来类似图 1,其中展示了从左边的低位地址到右边的高位地址排序的内存布局。

你可能感兴趣的:(编程,工作)