软件安全漏洞挖掘技术探讨
- 来源:中国信息化周报 smarty:if $article.tag?>
- 关键字:软件,Windows7,函数 smarty:/if?>
- 发布时间:2015-09-28 10:45
软件安全漏洞挖掘,国内还有漏洞分析的叫法,漏洞分析和漏洞挖掘业界也是有区别的,有些就是把漏洞挖掘归在漏洞分析之下,我们这里讲的漏洞挖掘是指对位置漏洞的挖掘。当前,漏洞挖掘本身是很难的问题。Windows7发现了很多远程管理的漏洞,但Windows7发布之后,远程管理漏洞,尤其是系统级的变得比较少了,这和微软SDL开发模式有一定的关系,他们有安全的开发平台。
漏洞挖掘技术正处于发展过程中
实际漏洞挖掘技术也是在发展的,早期主要是通过一些漏洞的函数,构建函数模型来进行漏洞挖掘。后期会引入路径模型的概念,包括原代码审计系统,二进制代码反馈之后也是一种源码,也就是说我们可以根据代码直接的上下文关系,语义解析构建出一些路径模型来挖掘漏洞。系统的安全对抗也是发展的,既然有了新的技术和安全机制,同样也会推出对抗的技术,例如数据执行保护制,可以通过ROP构造出来各种各样的Gaget,调用系统里相关的函数,因为攻击者攻击对方之后,更多是用被攻击机器上的资源完成攻击的过程。
以Windows系统为例介绍一下它的内存保护机制,传统内存机制,GS、SafeHEP、SafeSEH、DEP和SLF,Windows8里也引入了新的能够检测到ROP的方法。对堆进行了更多的改进,比如随机化的LFH,对页面属性的保护,对其他内存方面比如虚指针也提供了相应的安全机制,对于空页面、内存分配的随机化,GS方面也进行了积极的增强,也就是StackCookie,Windows7和Windows8最大的一个区别就是在Cookie生成算法里采用了Intel的SQL-key算法和技术,使得Cookie更难以进行猜测。在SL方面,他又提出了高算地址的随机化,研究过Win8或调试过Win8的系统安全人员应该都很清楚它的机制。DEP里也提出了检测ROP的机制。
以微软Windows为例,Windows出现蓝屏事件时会有系统转存,转存模式有三种:一是完全的淡化,把当前物理内存里的所有信息都存下来;二是核心内容的存储,除了进程之外的信息我们把它下载下来;三是小内存的存储,以16位为单位进行转存。得到这些信息之后,就可以通过微软自身提供的Win DBG进行分析,每一个出错的信息都可以形成陷阱针,可以通过bing看到它当时出错的场景,比如堆栈是什么情况,在一条什么指令上出错,可能大家从这条指令就能够看出,它在读一些不应该读的地址,读出一个错误。
回溯之后,可以把整个函数调用顺序清晰地展示出来。下一步我们可以借助强大的反馈链平台,像IDA来进一步判断它是不是存在逻辑的缺陷,判断这个漏洞有没有可能被利用。其中一个依据就是看看用户态里的参数或数据能不能传递到内核态里。基于这样的假设,也就是假设我们给厂商自己的产品打补丁时,打的补丁存在一些安全隐患,或者打的不完备,因为软件厂商发现自己的产品出来漏洞之后一定希望用最小的代价去修复当前这个漏洞,所以,它一般比较注重当前漏洞点的修补,而很少考虑漏洞上下文的环境,尤其Windows在大型逻辑上是很严谨的,但对很多的逻辑条件在别的地方可能也存在相应的改变,也就是它不能考虑到整个系统或者第三方代码会给变量和逻辑条件带来影响,这样我们可以形成参考,安全补丁比对逻辑挖掘的思路。这种技术在清华大学学报上已经形成论文,思路很简单,就是说我们可以通过路径查找找出所有可能执行的路径。
进一步对这个逻辑条件进行相应判断或者进行约束,最后进行求解,能不能找到绕过这个逻辑条件直接执行到漏洞点的路径,如果能找到的话,就意味着这个漏洞修补可能是不完全的。
这里有个典型的漏洞,这个漏洞应该说是已经公开的。漏洞之前和之后实际在前面就是加了一个逻辑条件和框段,同时Windows系统和其他开发者在其他地方又对这个地方进行了修改,如果我们采用某一种方法,能够把它的条件先进行重置,就可以把以前的漏洞进行重现。
改变新思路进行漏洞挖掘
系统内核函数的无序调用,这里面不仅仅是内核函数,也可以是API函数,Windows7、Windows8出现之后,系统漏洞的确很难继续挖掘,我们需要改变一些新的思路进行漏洞挖掘,这种方法实际是很好的能够去挖掘本地学习提升漏洞的方法,它可以面向Windows的内核模块,也可以面向一些驱动程序进行漏洞挖掘。
它的思路很简单,一个普通用户能够驱动打印机,就意味着一个普通用户能够调用打印机驱动里面的函数,既然是普通用户能够驱动的函数,完全可以通过自己的代码编程把这些函数剥离出来,其目的就是为了进行无序的调用,所以,我们可以有正常的顺序序列,也可以有打乱顺序的调用,譬如顺序里的函数经过多次调用之后在内存里会不会打架。也可以看调用的顺序能不能改变,或者调用一些条件或参数,或者没有公开过的API函数。这也是MS10-010的特点,它是客户端子系统的漏洞,在微软里它应该属于重要级的漏洞。MS10-010,也就是客户端子系统主要是完成这样的功能,用户登录之后开启的每一个进程可以在SDRSD里留下一个PLD,就是进程列表。用户退出操作系统,但是曾经开启过的进程依然留在这个系统里,这应该是存在安全隐患的,这和操作系统设计原则是违背的。
这种方式怎样让它重现呢?就是打乱它的调用数据,这里列出的一段代码,我们可以改变它的逻辑条件,绕过它的安全补丁。这里面每一步都可以通过安全函数实现。正常情况下会先连接ApiPort——退出——关闭,我们的标志就结束了。如果打乱这个顺序的调用,先连接,接着关闭,最后调用退出函数,这样它就会在寄存器里变成0,进程却依然留在系统里。基于协议握手的漏洞管理技术,这也没有什么太多的新意,主要是针对一些网络软件,这个测试空间是很大的。尤其是针对网络的应用软件,原来我们在进行Fuzzing测试时比较关注的是它的第一步,现在可以关注到第二步或第三步。首先可以把整个网络通信流程模拟出来,再结合立项工程,立项主要用在C端(Server端),也就是说解析传递过去的数据包,最后在Client端或Server端,我们能够去定制更加自动化的Fuzzing测试用例,从而缩小测试用例的空间。
这是个典型的例子,我们往往关注的是第一步,实际往往很多漏洞会出现在第二步或第三步,在连接创建之后或者用户已经登陆进去之后,后续数据包的传递可能会导致一些安全漏洞,最近我们团队也在研究URL的漏洞,主要是针对浏览器和Flash的一些对象,比如SWF。一提到UAF可能大家都知道,就是User After Free。我们在解析HTML时,HTML里可以通过Create Edident去创建对象,同时通过JS完成事件的回调,事件回调中可以销毁对象或者对对象属性进行修改,修改完了之后后面还会有继续的引用,这样就会导致UAF的漏洞。
(以上内容系根据文伟平教授在“2015中国网络安全大会”上的演讲整理而成,未经本人确认)
北京大学副教授 文伟平