ActiveX是网络中比较常见的一种软件程序,其上出现的各种漏洞自然就成了安全界关注的焦点。由于ActiveX本身的特殊性,不同于一般的DLL程序,调试逆向有其自身的特点。Activex运行原理及逆向对ActiveX进行过安全研究的人都知道,每个ActiveX组件中可能包含多个class类,每个class类可能包含了多个接口,每个接口可能包含了多个函数。每个class类有一个自己的classid。在通过脚本调用ActiveX中的某个函数的时候,会事先通过classid来引入class。
ActiveX组件中调用函数的机制叫做分发,顾名思义,就是拿着东西去寻找某个人,然后将东西给他。这里的某个人是指被调用函数,东西就是函数调用时的参数,那么又是根据什么来找某个人呢?就是根据人的姓名,也就是函数的编号。com组件在调用某个函数时,首先使用被调用函数的函数名来调用GetIDsOfNames函数,返回值是函数编号,再使用该函数编号和函数参数来调用Invoke函数。
分发接口其实就是存在两个数组,一个存放dispid与接口方法名称的对值(pair),一个存放的是dispid与接口方法指针(也就是函数指针)的对值。只要有这两部分,我们就认为它是一个分发接口。之所以会存在dispatch分发机制,是为了解决脚本语言中使用C++中的虚函数的问题,先通过函数名来找函数编号,然后利用函数编号来调用函数的方法来绕开直接调用虚函数的方法。
Invoke函数内部其实是调用DispCallFunc完成分发功能的,DispCallFunc函数接口定义为:OLEAUT32!DispCallFunc(HWND ActiveX_instant, dispatchID id))。这也是为什么过去我们在调试 ActiveX时,断点设在 OLEAUT32!DispCallFunc,然后跟进 call ecx中的缘故了。
Activex相关信息获取
如果想进行深度的逆向或者是自制漏洞挖掘工具,还需要知道一些基本信息,比如类名、接口名、函数名、函数参数等。这些信息可以通过多种途径获得,具体采用什么方法视具体情况而定。无论是通过静态分析工具,如IDA,还是通过动态调试工具,如ollydbg等,都不能看到函数的名称和地址,这为分析调试带来了不小的困难。怎样才能解决这个问题,业界普遍的方法是利用OLEAUT32!DispCallFunc函数来对调试函数进行跟踪分析。
1)注册表
注册表 HKEY_CLASSES_ROOT\CLSID中记录的就是classid。每个 classid下面有个typelib,typelib记录的是所属com组件的id。组件id记录在注册表的HKEY_CLASSES_ROOT\TypeLib目录下。
2)OLE View工具
IDL是接口描述语言,类似于 Java中的接口和虚拟类。也就是说,在开发 ActiveX的时候,要先设计和编写IDL。类型库(TypeLib)是IDL编译后的结果。IDL和类型库的区别在于,IDL方便阅读,而类型库(TypeLib)是二进制的,方便机器处理。VC6tools里面的OLE View是一个很有用的工具,可以使用OLE View打开com组件,查看里面的typelib信息。很多漏洞挖掘工具也是通过事先获取typelib类型库中的信息,来获取函数名、参数等信息的。
3)WhoHasTlb
获取系统中没有注册的组件的接口定义语言(IDL)。
4)自制函数方法
下面是用Python代码编写的部分代码片段。
dialog = wx.FileDialog(None, Choose a file, os.getcwd(),, wildcard,wx.OPEN) adobe=dialog.GetPath() tlb=pythoncom.LoadTypeLib(adobe) className=tlb.GetDocumentation(pos)[0] interfaceName=tlb.GetDocumentation(pos+1)[0] info=tlb.GetTypeInfo(pos+1) attr=info.GetTypeAttr() desc=info.GetFuncDesc(i) names=info.GetNames(id) content=content+'\n\t\t'+name+','+VTS[desc.args[i][0]]
从中可以发现,也是借助了typelib等信息。
5)分发函数
在网页中调用ActiveX组件,在浏览器背后都会先后调用GetIDsOfNames函数和Invoke函数。因为Invoke函数内部最终要调用OLEAUT32!DispCallFunc函数,因此可以在该函数上下断点。GetIDsOfNames函数和Invoke函数中分别使用了函数名称表和函数地址表。
漏洞挖掘技术比较
ActiveX漏洞挖掘领域有很多工具,例如 Dranzer、axfuzz、COMRaider、AxMan等。
1)Axfuzz特点
Axfuzz是 ActiveX漏洞挖掘软件的鼻祖,其他很多工具的底层都直接使用或借鉴了Axfuzz工具。Axfuzz为创建Dranzer工具提供了初始化模型。Axfuzz同时使用axenum程序和axfuzz工具来对系统上的软件进行评估。其中axenum程序用于枚举系统上的COM对象。axfuzz本身设计比较简单,仅仅使用 0和超长字符串“AAAA…”来对组件的属性和方法进行测试。重要的是,Axfuzz提供了两个非常好的基础软件axenum程序和axfuzz工具,这两个软件可以作为其他漏洞软件的底层接口。
2)Axman特点
AxMan是一个基于Web的ActiveX的fuzz引擎。AxMan的目标是通过浏览器发现COM对象中的漏洞。既然 AxMan是基于Web的,那么浏览器的任何安全变化都将影响到fuzz进程的结果。这比起其他的基于 COM的评估工具更具有贴近实战的效果。图1是我梳理出来的 AxMan程序的架构。
图1
总的来说,漏洞发现是通过浏览器异常崩溃来完成的,畸形数据的生成比较单一。对于多参数的函数fuzz问题,使用的是多种异常数据的排列组合。崩溃后不能自动重新启动,需要有人坚守,检查过的和没有检查过的函数与属性需要手动添加到列表中。
3)Comraider特点
Comraider是一款比较流行的漏洞挖掘软件,最大的特点就是图形界面,简单易用。该款软件也有很多缺点,例如被测试ActiveX路径中存如果在中文,将导致Comraider出现很多莫名其妙的错误。Comraider的漏洞挖掘脚本使用的是vbs,而其他的一些漏洞挖掘软件使用的是js来进行测试。因为在微软的浏览器插件体系结构中,在不同组件之间,广泛使用了COM对象和VARIANT来定义和传送对象。JavaScript对象在本地运行环境中被表示成了COM对象。
VBScript对象在本地运行环境中表示成了VARIANT结构。也正是这个原因,说明了为什么有些ActiveX漏洞js可以发现,而comraider却发现不了。
4)Dranzer特点
毫不客气的说,Dranzer是我至今看到的,在ActiveX漏洞挖掘领域考虑最细致的软件。
下面列举一下它的特点:
①Dranzer会模拟浏览器中的相关策略,例如脚本是否安全,是否设置killbit位。Dranzer在测试过程中,将直接在测试工具的进程空间中调用ActiveX,会创建一个异常处理句柄来捕获访问违规细节。
②由于本地主机域比起网络域有着不同的安全属性,为了更好的评估ActiveX漏洞的危害程度,dranzer设置了AlternateDataStreamZone.Identifier标识。Dranzer首先生成测试用HTML文件,然后设置HTML文件的AlternateDataStreamZone.Identifier,使用ollydbg附加到浏览器上,然后让浏览器访问测试用例。
③Dranzer使用了两个技术来辨识初始化参数。一项技术是使用ActiveX控件的IPropertyBag接口,第二项技术是在COM服务器二进制区域搜索文本。通过上面两种方法,Dranzer先得到一个初始化参数的列表,并依据它生成HTML测试用例文件,并且加载进入浏览器,进行实例崩溃测试。其中,测试用例中的OBJECT区域有一个PARAM元素,该元素包含了异常数据。
④当因为调用一个方法或属性导致访问违规发生,Dranzer将记录完整的回溯过程。因为可能发生这种情况,例如,当访问异常发生时,最后一个方法调用不是实际存在问题的方法调用。例如下面的情况:
Method1(BSTRparam1) Method2()
很可能Dranzer报告在Method2中存在访问违规,但是实际上Method1是发生缓冲区溢出的地方。
⑤Dranzer安装了一个全局钩子,能进行自动按键功能或结束探出窗口过程,这样可以使测试继续进行。
⑥一些ActiveX缺陷可能引起测试进程遇到不能处理异常。有时一个缓冲区溢出能够覆盖测试进程的SEH,导致测试进程不能记录溢出的日志信息,无论是能处理的异常,还是不能处理的异常,Dranzer都能够继续测试,保证测试不中断。
⑦当对ActiveX控件进行测试或初始化的时候,ActiveX控件可能会创建其他进程,当进行大量的控件测试时,这些多出来的额外进程将严重消耗系统资源,更恐怖的是干扰测试结果。当对一个对象进行测试时,Dranzer将对系统上运行的所有进程做一个快照。测试完毕后,所有额外进程将中止。Dranzer在测试之前如果检测到其他的浏览器在运行,将关闭已经运行的浏览器。在我们的测试中,个别的ActiveXcontrols将因为另一个浏览器的打开,而表现出不同的行为。通过消除这些额外的变数,可以保证结果更加准确。
⑧能够检测出在安装软件过程中,安装了哪些com组件。
⑨可以通过ActiveXWorkspace来测试业务逻辑漏洞。使用该软件,控件的属性将被获取和设置,方法将被调用,与此同时,我们会检测系统的行为。比方说使用PM可以监控注册表、文件和线程细节,使用Wireshark监控网络流量。软件设计方面
①如果ActiveX有本地域的操作,可以为相关组件在文件系统中划出一个专门的区域来进行隔离,保证ActiveX不能直接访问本地文件系统。
②Activex在网络传输过程中,建议使用软件签名处理。采用许可证检查,让ActiveX控件都支持设计时刻和运行时刻的许可证检查。
③可以使用IObjectSafety接口或注册表实现控件的SFS和SFI,但是更建议使用IObjectSafety来标记控件的安全与否。这可以阻止别人通过包装你的控件将控件从不安全包装成安全。IObjectSafety是一个COM下的接口,对于C++程序员来说,只需要实现它就行了,而.NET之下没有这个接口,在这种情况下,我们的ActiveX控件就是一个不带类型库的COM组件,必须使用C#代码重新定义COM接口。
④可以让COM组件在浏览器的本地域中运行,而不能在网络域中运行。解决方法有三种:采用现代化技术,IE7引入了一种做ActiveXOpt-In的新特性,使用这种控件前有提示;使ActiveX不能用,使这些控件在浏览器的网络域不能使用;使用一个不同的浏览器。
⑤phoenix-bit(凤凰位)是一个指向控件的新的CLSID。这可以让开发者以一个安全的、新的CLSID来安装一个已经更新的控件。如果请求旧的控件,IE浏览器可以将请求转给新的控件。
⑥使用sitelock。sitelock是微软提出的针对ActiveX安全的一个解决方案,可以帮助ActiveX控件只运行在指定域里面,这样即使插件有漏洞,也可以将危害降到最低,导致利用者无法随便挂马。
⑦如果ActiveX控件不被用于浏览器,那么没有必要考虑“SafeforScripting”标记。
⑧如果ActiveX控件被用于浏览器中使用,就得考虑是否将其标记为“SafeforScripting”。微软给了一个非常宽松的判断标准,该标准是以若干个问题为参照物,如果都不符合,那么最好不要将控件标记为脚本安全或初始化安全。也就是说,为了标记为脚本安全或初始化安全,必须能满足提出的大部分问题。按照这个标准要求,我们可以设计一个控件是否安全的标准规范,相当于一个调查表格,有5个等级,给出每一个面的评判标准,然后进行统计,说明它是否安全。
⑨根据这个标准看看业内其他同类软件公司的ActiveX控件的安全程度,给出一个安全等级,并进行对比。
结语
软件的攻击和防御一直是信息安全界的一个热门话题,只有熟悉了攻击,才能真正做好防御,也只有掌握了防御才能真正有效的去测试,去攻击。之前对ActiveX的学习,也是结合攻击和防御来学习的,我想大家和我一样,也是深有体会。
本文内容所提及均为本地测试或经过目标授权同意,旨在提供教育和研究信息。作者不鼓励或支持任何形式的非法破解行为。