指针保护是堆栈保护针对这种情况的一个推广。通过在所有的代码指针之后放置附加字节来检验指针在被调用之前的合法性。如果检验失败,会发出报警信号和退出程序的执行,就如同在堆栈保护中的行为一样。这种方案有三点需要注意:
a.附加字节的定位:
附加字节的空间是在被保护的变量被分配的时候分配的,同时在被保护字节初始化过程中被初始化。这样就带来了
问题;为了保持兼容性,我们不想改变被保护变量的大小,因此不能简单地在变量的结构定义中加入附加字。还有,对各种类型也有不同附加字节数目。
b.检查附加字节:
每次程序指针被引用的时候都要检查附加字节的完整性。这个也存在
问题;因为“从存取器读”在编译器中没有语义;编译器更关心指针的使用,而各种的优化算法倾向于从存储器中读入变量。
c.还有随着不同类型的变量,读入的
方法也各自不同。
已经开发的指针保护的一个原型(还是基于gcc的),通过附加字节来保护静态分配的函数指针,但不适用于结构和数组类型。这个计划还远没有完成。一旦这个项目完成了,那么用它和堆栈保护构成的可执行代码将不会受到缓冲区溢出的攻击了。
目前为止,只有很少一部分使用非指针变量的攻击能逃脱指针保护的检测。但是,可以通过在编译器上强制对某一变量加入附加字节来实现检测,这时需要程序员自己手工加入相应的保护了。
(7)利用编译器将静态数据段中的函数地址指针存放地址和其他数据的存放地址分离
我们知道缓冲区溢出的一个基本条件是在缓冲区的高地址附近存放着可供溢出覆盖的函数地址指针,如果我们破坏了这一条件,就会使缓冲区溢出不能覆盖函数地址指针。比如,我们可以假定编译器在编译程序时会将静态数据段中的函数地址指针存放地址和其他数据的存放地址隔开相当大的一段距离,例如数10M,数100M,这样才会迫使攻击者只有送入长的出乎想象数据才能抵达函数地址指针存放地址并覆盖它,以这样的不可操作性来制止攻击者实现攻击意图。另外,我们还可以使这两种数据段间的线形地址空间不分配物理地址并设置为不可读写,这些都可以通过硬件实现,这样每当缓冲区溢出进入这段区域,就会出现地址保护错误,从而阻止了缓冲区溢出攻击。
另外一种较为简洁的
方法是始终保持使静态数据段中的函数地址指针存放地址低于其他数据的存放地址。但是这个方法仅仅是防止了静态数据段中的缓冲区溢出攻击,而不能避免堆的缓冲区溢出攻击,因为编译器和操作系统并不知道用户申请的内存是用来存放函数地址指针还是其他数据,从而无法为其隔离分配内存。表1是针对静态数据段、堆栈和堆的缓冲区溢出的防范策略,其中没有把边界检查包括在内,因为它能有效地防止所有的缓冲区溢出,但其运行开销也是惊人的。表的最上面一行是攻击代码所植入的内存空间,表的最左面一列是溢出方法,而中间单元就是相应的防范策略。
表1 缓冲区溢出的防范策略
|
|
堆栈
(Stack Buffer) |
堆
(Heap Buffer) |
静态数据段
(Static Buffer) |
|
活动记录 |
堆栈保护
非执行的缓冲区 |
堆栈保护 |
堆栈保护 |
|
函数指针 |
指针保护
非执行的缓冲区 |
指针保护 |
指针保护 |
|
长跳转缓冲区 |
指针保护
非执行的缓冲区 |
指针保护 |
指针保护 |
|
其它变量 |
手工的指针保护
非执行的缓冲区 |
手工的指针保护 |
手工的指针保护 |
为了防止静态数据段、堆栈和堆这三种数据段中的一个缓冲区溢出覆盖另一个段中的函数地址指针,我们应该为这三种数据段隔离分配线形地址空间。
缓冲区溢出是当今很流行的一种
网络攻击方法,它易于攻击而且危害严重,给系统的安全带来了极大的隐患。因此,如何及时有效地检测出
计算机
网络系统入侵行为,已越来越成为网络安全管理的一项重要
内容。缓冲区溢出的漏洞一般有以下几种情况:
(1) 系统漏洞
如操作系统、服务器程序、数据库程序等,这种漏洞可以通过升级软件、打安全“补丁”等方法来解决。
在软件开发过程中,如果程序员没有很强的安全意识和良好的编程习惯,也会产生很多安全漏洞。
本文从上面的系统环境及程序设计语言角度,对
目前主要的网络攻击方式:缓冲区溢出攻击的出现和原理进行了详细的
分析,并根据缓冲区溢出攻击的类型提出了相应的防范策略。