基于源代码的缓冲区溢出预防技术

时间:2022-07-11 04:54:11

基于源代码的缓冲区溢出预防技术

摘要:基于缓冲区溢出的攻击是一种常见的安全攻击手段,也是目前惟一最重要最常见的安全威胁。在所有的软件安全漏洞中,缓冲区溢出漏洞大约占一半。该文从编程的角度分析了缓冲区溢出攻击,并提出在源代码阶段尽量避免缓冲区溢出的方法。

关键词:堆栈;缓冲区;溢出;缓冲区溢出攻击

中图分类号:TP311文献标识码:A文章编号:1009-3044(2008)36-2839-02

Prevention Technology Based on Buffer Overflow of Source Code

ZHANG Chuan-juan

(Fujian Communication Technology College, Fuzhou 350007, China)

Abstract: The attack, based on the buffer overflow, is a common means of security attacks and is the only most common security threats at present. Buffer overflow vulnerabilities account for about half Of all the software vulnerabilities. In this paper, from programming point of view, the buffer overflow attacks are analyzed and the methods of avoiding buffer overflow at the stage of source code are introduced.

Key words: stack; buffer; overflow; buffer overflow attacks

1 引言

1988年的Morris蠕虫,是第一次利用缓冲区溢出缺陷的攻击,导致6000多台机器被感染,损失在$100 000至$10 000 000之间。之后,缓冲区溢出缺陷的攻击愈来愈多,成为最常见也是最危险的网络攻击。

缓冲区溢出是由于程序或编译器没有对缓冲区进行边界检查导致的。发展C语言的初衷是为了编写操作系统,后来被广泛使用,其运行高效、精确控制资源等优点成为系统程序员最喜欢选择的编程语言,很多商业软件都是使用C语言编写的。但C语言缺少安全机制,对数组和指针不做边界检查,由此带来很多缓冲区溢出隐患。最直接的预防方法是编程时严格按照规则对边界进行检查,但实际效果不尽如人意,即使是经过严格培训的程序员也会产生错误。为了防止缓冲区溢出,专家学者研究了很多的检测和预防技术。本文将缓冲区溢出的原理进行分析,并对其检测和预防技术进行一次介绍。

2 缓冲区溢出的原理

缓冲区溢出的原因是由于字符串处理函数(gets,strcpy等)没有对数组的越界加以监视和限制,结果覆盖了老的堆栈数据。

在计算机内的程序是按以下形式存储的,见图1。

01

图1 程序在内存中的存储

缓冲区溢出的造成的影响有两个方面:1)覆盖缓冲区相邻内存中的数据,破坏程序数据的完整性;2)覆盖了前一个栈基指针(ebp)、堆栈中的函数返回地址或函数参数,从而改变程序的流程。

许多C 程序都有缓冲区溢出的漏洞,一方面因为很多程序员在写程序时都只考虑到程序的执行效率而忽视错误检查与出错处理。同时,标准C 库函数本身就存在严重漏洞,如常用的strcat()、strcpy()、sprintf()、vsprintf()、bcopy()、gets()、scanf()等。

3 攻击种类与实施过程

C语言中能改变内存地址内容的语句主要有两类:1)*A=B; /*指针型语句*/;2)A[i]=B; /*数组型语句*/;

其中,A,B均为变量,*A为指针,A[]为数组,i 为数组下标。

在第一 类语句(指针型语句)中,由于A 所指向的内存地址取得B 的值,因而攻击者能利用该声明来改变函数的返回地址。由此可构成第一种攻击方法,又可称为指针型攻击方法。

在第二类语句(数组型语句)中,数组A[]中的第i个元素A[i]取得B 的值。这类攻击方式必须满足下列条件:

1)一个循环声明,用于将用户输入数据复制到一个缓冲区数组,而且不能检查数据量,同时数组必须紧靠变量B;

2)一个循环声明,用于将用户输入数据复制到数组A,而且不能检查A 的上界,每次循环后i的值加1,同时数组A必须紧靠一个返回地址。

在此条件下可构造出两种攻击方式。

A)通过(1)改变B 的值,然后通过(2)将B 的新值循环输入数组A,直到返回地址也被该新值覆盖。这种攻击中,不仅返回地址被改变,而且介于数组A与返回地址之间的所有内存区域也全被改写。这种方法在缓冲区溢出攻击中使用得最多。

B)假设A[k]存有函数的返回地址。如果我们用第一种攻击方法使A[k]溢出,就可将返回地址的值改写成任何需要的值。

4 缓冲区溢出攻击举例

下面的程序是典型的缓冲区溢出攻击:

/*StackOverrun.c*/

void OverFlow(char *str)

{char buffer[16];

strcpy(buffer,str);}

void main ()

{char str[256];

int I;

for(i=0;i

OverFlow(str);}

函数OverFlow()将一个字符串不经边界检查就拷贝到另一内存区域。显然程序执行的结果是Segmentation fault (core dumped) 或类似出错信息。因为从buffer 开始的256 个字节都将被*str的内容A 覆盖,包括SFP,RET,甚至&str。A 的十六进值为0x41,所以函数的返回地址变成了0x41414141,超出了程序的地址空间。结果证明我们的应用程序是可以被人利用的,所以一定要担心!

5 检测和常用预防技术

为解决缓冲区溢出问题,我们做了大量的工作,下面介绍几种技术。

5.1 源代码的静态分析

ITS4使用潜在危险结构数据库来检测安全问题。很多程序员在进行安全审计时使用grep 命令查找危险的函数调用。ITS4的设计者目的是提供比grep 更智能的工具,在找到危险的函数调用时,ITS4 还能提供有用的安全建议。类似ITS4的分析工具还有Flawfinder、RATS、 FlexeLint、Pscan等。静态分析的好处是快捷简单,但没有考虑程序的语义,忽略了过程之间的交互、变量值和控制流。

BogoSec是一个源代码安全测量工具,它捆绑了几种源代码扫描器(ITS4 、Flawfinder、RATS),最后产生源代码安全质量值。

5.2 扩展编译器功能

编译器是源码变成可执行代码的桥梁。有很多缓冲区溢出脆弱性检测和预防技术解决方案是通过扩展编译器功能,增加缓冲区边界信息并插入边界检查代码来实现的。

1)StackGuard:StackGuard对编译器进行扩展,调用函数是在堆栈的局部变量和返回地址之间存放一个程序运行时的随机产生的4个字节的“canary”字。若“canary”被破坏,则表明有缓冲区溢出产生,程序被终止。

2)StackShield: StackShield创建一个特别的堆栈---地址栈,用来储存函数返回地址的一份拷贝。把返回地址压栈同时保存到这个特别的地址栈中,在返回地址出栈前把从地址栈中取出返回地址。即使堆栈中的返回地址等信息被破坏,仍然可以保证不会跳转到错误的地方执行。

3)LibSafe:在已知的缓冲区溢出漏洞中,大部分是因为没有正确的使用gets,sscanf,sprintf 等字符串和io 函数. 基于这一事实,LibSafe 提供了一套和标准库兼容的库,用于替换已知的有安全隐患的库。

4)Visual C++.Net 的/GS选项:Visual C++.Net 的/GS选项与StackGuard,它在声明于栈上的变量与EBP指针、返回的地址指针几函数特定的异常处理之间放置一个“canary”。

5)DIRA:DIRA是GCC编译器的扩展。在编译时插入适当的内存修改日志代码,然后在所有对敏感数据引用的地方插入检查代码,最后在程序中插入识别攻击代码和修复程序的函数。

6 结束语

以上是基于源代码的检测安全漏洞的方法,没有运行时的开销,是编写代码及调试过程进行缓冲区检测的常用技术。目前提出了对程序的可执行文件进行渗透测试及对操作系统进行改进设置基于堆栈和堆不可执行、段长限制、使用两个堆栈等。每种技术都有不足之处,根本解决问题的方案是开发出全系列的能预防缓冲区溢出的操作系统、库、编译器和编程语言。

参考文献:

[1] Foster J.C. 缓冲区溢出攻击――检测、剖析与预防[M].北京:清华大学出版社,2006.

[2] 许治坤,王伟,郭添森,等.网络渗透技术[M].北京:电子工业出版社,2005.

[3] 张小斌,严望佳.黑客分析与防范技术[M].北京:清华大学出版社,1999.

[4] 杨朝龙,须文波.嵌入式系统安全中缓冲区溢出防止技术的研究与实现[J].嵌入式系统应用,2005(25):15-17.

[5] 单国栋,戴英侠,王航.计算机漏洞分类研究[J].计算机工程,2002(10):11-14.

上一篇:简述PLC应用中的抗干扰设计 下一篇:网络工程实训中心建设研究