0x00 使用Fuzz工具
ActiveX的Fuzzer相当之多,本次我们暂时使用一个老牌但是性能较弱的开源Fuzzer:COMRaider。选择它的原因是它是一个图形化的Fuzzer,界面元素简单。但是说弱则是因为它的测试用例实在太少,而且比较陈旧(但是你可以手动添加)。比它强悍的工具还有很多,例如AxMan Fuzzer,但是AxMan的界面实在是没法截图,所以我还是用这个来演示好了……
COMRaider可以在https://github.com/dzzie/COMRaider下载到。安装打开后COMRaider的界面如下图所示。开始按钮完美地隐藏到了右边,和背景融为一色。
点击Start之后即可开始Fuzz的第一步——选择ActiveX。在这里我们选择“Choose from controls that should be loadable from IE”。
然后右键选择Scan New。在列表里面挑选一个你看不顺眼的插件,然后点击“Select”按钮即可查看到该插件的详细信息。
新弹出的窗口中可以查看到该ActiveX的所有方法和属性。记得点击“Show only fuzzable”,把它前面的勾去掉。在列表左边显示的灰色内容是不能fuzz的,黑色内容是可以fuzz的。可以看得出来:凡是无参数传入的方法,COMRaider均Fuzz不了。
新弹出的窗口中可以查看到该ActiveX的所有方法和属性。记得点击“Show only fuzzable”,把它前面的勾去掉。在列表左边显示的灰色内容是不能fuzz的,黑色内容是可以fuzz的。可以看得出来:凡是无参数传入的方法,COMRaider均Fuzz不了。
是的,你编辑的文件是VBScript文件,所以一切请遵守VBS的语法。至于为什么要用VBS,COMRaider发布第一版的时候(时代的眼泪)VB还是很流行的,以至于COMRaider都是VB写的。
例如,我们向Long Args加入parent.lngs.add 65535,这样在Fuzz Long类型的参数的时候65535就会作为一个testcase被使用。
0x01 如何测试逻辑问题
本节我们只介绍使用COMRaider来挖掘逻辑漏洞并编写PoC。以此控件为例。
Loaded File: F:\Windows\SysWOW64\QoePlug.ocx
Name: QOEPLUGLib
Lib GUID: {15144D65-D22E-4768-8980-7411EF722FDE}
Version: 1.0
Lib Classes: 1
Class QOEPLUG
GUID: {B2F9A248-3AB5-493F-A7F8-5B7A9D026ED2}
Number of Interfaces: 1
Default Interface: _DQOEPLUG
RegKey Safe for Script: True
RegKey Safe for Init: True
KillBitSet: False
它包含如下方法和属性:
Interface _DQOEPLUG : IDispatch
Default Interface: True
Members : 43
strOsName
strCpuName
strNetLoad
strCpuUsage
strMemSize
strMemUsage
strProxyServer
strDnsServer
strNumComputer
strTraceInfo
strProcessInfo
strKillPid
strDnsName
strConnectIp
strUrl
strMultiDownLoadUrl
strDnsTime
strConnectTime
strUrlTime
strMultiDownLoadResult
strVersion
strDownloadUrl
strDownloadTime
GetOsName
GetCpuName
GetNetLoad
GetCpuUsage
GetMemSize
GetMemUsage
GetProxyServer
GetDnsServer
GetNumComputer
GetTraceInfo
GetProcessInfo
KillProcId
GetDnsTime
GetConnectTime
GetUrlTime
GetMultiDownLoad
StartMultiDownLoad
StopMultiDownLoad
GetVersion
GetDownloadTime
点击其中一项可以看到该项的定义。
COMRaider在展示信息的时候,显示的方法名也是VB模式的,如果你用过VB那还好,没用过的话只需要大致记得这样的模式即可:
Sub 函数名(参数名 As 类型名, 参数名2 As 类型名2 ……)
Function 函数名(参数名 As 类型名, 参数名2 As 类型名2 ……) As 返回值类型
Sub对应一个没有返回值的方法,大致等同于C++里面的void 函数名(类型名 参数名,类型名2 参数名2……)
Function对应一个有返回值的函数,大致等同于C++里面的返回类型 函数名(类型名 参数名,类型名2 参数名2……)
如果一项是可以Fuzz的,我们可以右键点击选择Fuzz member,或者直接Fuzz Library,这将会Fuzz它的所有成员。
COMRaider使用Windows Scripting Host来Fuzz,生成的文件是wsf类型的(WSF是含有XML代码的文本文档)。COMRaider生成的testcase结构类似如下,所以如果看到外面某个漏洞PoC的代码出现了熟悉的参数名和代码风格,那不用想,肯定是COMRaider的功劳:)。
#!xml
<?XML version='1.0' standalone='yes' ?>
<package><job id='DoneInVBS' debug='false' error='true'>
<object classid='clsid:B2F9A248-3AB5-493F-A7F8-5B7A9D026ED2' id='target' />
<script language='vbscript'>
'File Generated by COMRaider v0.0.134 - http://labs.idefense.com
'Wscript.echo typename(target)
'for debugging/custom prolog
targetFile = "F:\Windows\SysWOW64\QoePlug.ocx"
prototype = "Invoke_Unknown strDownloadTime As String"
memberName = "strDownloadTime"
progid = "QOEPLUGLib.QOEPLUG"
argCount = 1
arg1=String(3092, "A")
target.strDownloadTime = arg1
</script></job></package>
通过右键点击testcase,然后选择Test Exploit in IE可以在IE中测试对应代码。也可以手动处理生成可在ie加载的代码。如上述代码,掐头去尾取中间就可以了:
#!xml
<object classid='clsid:B2F9A248-3AB5-493F-A7F8-5B7A9D026ED2' id='target' />
<script language='vbscript'>
arg1=String(3092, "A")
target.strDownloadTime = arg1
</script>
COMRaider基本不能验证逻辑漏洞,因此在挖掘的时候需要人工介入。以GetCpuName为例,虽然这是一个无返回值的方法,但是我们同样看到了这个ActiveX还有一个strCpuName的属性,让我们将这两个串联起来。
PoC:
#!xml
<object classid='clsid:B2F9A248-3AB5-493F-A7F8-5B7A9D026ED2' id='target' />
<script language='vbscript'>
target.GetCpuName
alert(target.strCpuName)
</script>
在IE中验证一下,可以发现CPU挺老的了,该换电脑了。
0x02 Fuzzer怎么知道ActiveX信息的?
Fuzzer怎么枚举属性和方法?有一个通用的方法,详细表示如下:
- 先CoCreateInstance创建一个实例,查询其IObjectSecurity接口;
- 如果实现了这个接口,查询是否设置了Safe for init和Safe for script位,这个是它待会儿要写到测试的配置里面去的;
- 调用IDispatch中的GetTypeInfo获取ITypeInfo接口用来展开相关的内容;
MSDN表示: The ITypeInfo interface provides access to the following: The set of function descriptions associated with the type. For interfaces, this contains the set of member functions in the interface. The set of data member descriptions associated with the type. For structures, this contains the set of members of the type. The general attributes of the type, such as whether it describes a structure, an interface, and so on.
简单的说就是ITypeInfo接口提供了对这个接口中的成员函数、成员变量、通用属性(是否定义了一个结构体,一个接口等等)。
- 对TypeInfo调用GetDocumentation获取函数数量,然后对各个函数调用GetFuncDesc获取函数描述,然后这里就可以获得函数名,返回值,参数数量和参数。
由于COMRaider也是开源的,你也可以下载它的代码,并查看它的具体实现方式。