今天接着写安全入门话题之堆栈溢出。
堆栈溢出简单说就是所定义数据结构存放在堆栈中,并且输入数据超过了定义数据的大小,覆盖了属于或者不属于堆栈的部分,通常会引起访问非法或者段错误。如果没有发现就成为了系统漏洞,而且这种漏洞很常见也很容易被开发人员忽视。
如果只是简单的出现执行错误,就很容易发现,现在溢出带来的最大问题是安全的漏洞,各种软件产品几乎都免不了有它的身影,安全漏洞是一个更广的概念,现在的流程是黑客或者用户发现了系统的漏洞,然后软件公司发布补丁,后者安全公司发布能够防御攻击的更新,即使symantec自己的产品也有漏洞不断被发现,只是公司更加重视这点,在软件开发中加入安全的因素。
堆栈溢出如何成为漏洞,它是如何能够被蠕虫等病毒利用? 首先来看一个程序的内存空间。
Stack和heap在动态数据段中,数据段和代码段在空间上不连续。当有数据溢出,不会影响到代码段的数据。
再来看堆栈的数据结构
红色标记出的是关键点,在堆栈底部存放着程序的返回地址,当程序执行到结束,即pop出返回地址,并从该地址开始执行下一条指令,所以当发生溢出,此地址很容易被覆盖,因而程序指向了一个错误的地址,发生段错误或者访问非法。当溢出是被病毒精心利用,RET被一个指向病毒代码的地址所覆盖,则在执行返回时,实际上是指向了病毒程序。
分析最简单的情况,看段代码:
程序包含一个main函数和一个over子程序。在over子程序中定义了一个int 数组,它将被存放在堆栈中,指令8就是溢出指令,访问了超过定义长度的空间,array[15]存放的就是返回空间地址,指令8把返回地址修改为array[16]也就是病毒代码。这里的病毒代码就是四条NOP指令,其代码为ox09。这条由指令9完成。在array[16]后的一段空间可以被注入病毒代码。
这个程序被执行时,在指令11处开始跳转,跳转到设定的array[16]地址,然后执行设定的空指令,当然如果被注入病毒就没这么幸运。
然后看一段接近实际的漏洞代码是这样的:
用户的输入被不加检查的直接给了array字符串组,当输入是用户精心准备的数据时,就可以很轻松的注入病毒,比如用户输入AAAAAAAAAAA/08/04/01/04/virus code/.....
如何防御?
基本上分为三步骤
1) 代码检查,请有经验的程序员检查代码,及早发现漏洞
2) 使用编译器的防治溢出的功能,有gcc的扩展Stack Guard;visual studio的Buffer Security Check,IBM的ProPolice。他们的原理基本上是在返回地址后加一个警报器,一旦修改这个地址就跳转到错误处理,而不会执行病毒代码。
3) 操作系统级别来阻止,有处理器提供某种保护机制,如SPARC的Solaris; 以及Linux的扩展Libsafe能在进程空间增加预防攻击的代码。但是windows有这种机制吗?暂时没发现。
关于如何保护还需要进一步学习和研究,这又是入门级的简单文档,欢迎讨论,J
Ps: 写个病毒其实很简单,但如何防御确实成本大且需要考虑周全,所以不要盲目把写个小病毒的人就叫他黑客或计算机高手。