缓冲区溢出说白了就是因为内存中的非法访问而导致的一些状态的破坏。
这一点,C语言中的一些和数组有关的库函数最容易导致这类情况。
缓冲区溢出攻击,有很大一部分是通过数据的溢出,内存的非法访问来执行一些攻击代码,因为数据在栈中一旦溢出,那么他就会覆盖一些重要的状态,从而被攻击者操控。
那么关于对抗缓冲区溢出的攻击,有这样的几种方法
1、栈的随机化
在植入缓冲区溢出攻击的代码的时候,还要植入指向这段代码的指针,指针指向这段代码的栈的位置。因为执行这段代码是考指针进行跳转过去的。由于以前的操作系统程序的栈的位置相对来说比较固定,所以是很好找的。也就是说,每一次执行一个程序,他的程序栈的位置都是不固定的,这样一来,第一个是很难植入攻击代码,第二个是即使你植入了,那么你的指针要指向这段攻击代码的栈空间也很困难,因为他是一直在变动的。
但是攻击者仍然可以通过枚举不同的地址进行攻击。这里有一个办法就是在攻击代码之前加入空雪橇操作,即加入很长一段的nop操作来是程序计数器+1.
我对这种攻击方式的理解是这样的,攻击的代码已经嵌入到了一个程序的栈中,但是由于这个栈的位置在不断的变化所以找不到这段攻击代码的准确位置。所以在攻击代码之前加入很长的一段Nop操作,使得程序计数器+1指向下一条指令。只要在执行nop操作的过程中能够找到攻击代码相应的地址数据,就能够跳转到攻击代码进行执行。
要破解指定范围内的栈的随机化,就要进行不断的尝试,尝试次数诚意nop的大小就能够判断出是否能够破解。
2、栈破坏的检测
由于我们不能够真正的杜绝数组的越界书写,我们找到一个新的办法就是在超越局部缓冲区边界的时候,在修改生效之前,先根据一个标志值进行判定,如果越界修改那么这个值肯定就会改变,那么就拒绝这次访问,这个值的音译是金丝雀值,他的位置在局部缓冲区和局部栈状态之间。也就是说,当局部缓冲区溢出想要影响到栈的状态的时候,要先经过这个金丝雀的值才行,这样的话通过设立一个哨兵就 可以防止非法访问的事实发生。并且这个值是随机的,攻击者是不能够猜出它是什么的。一般来说如果真的要使用这种办法来防止栈的缓冲区溢出的时候,缓冲区向栈底的方向,相邻的必须放置金丝雀值,不能放置任何其他的数值,因为很可能会遭到破坏。
3、限制可执行代码区域
很多系统对内存或者存储器有着三种访问形式的区别:可读,可写,可执行。这种方法就是要限定可执行的内存区域,从而让攻击代码即使在内存也不能够执行。
X86中,可读和可执行合成为一个标志位来进行表示,这错误的,会给攻击代码留下机会。但是AMD就在内存保护中增加了NX位,也就看是不可执行位,把三个权限都分开了。通常来说,整个内存中应该都有可读的权限,可执行的权限只有在保存编译器产生代码的存储区域内才会有。