导语:卡巴斯基研究人员将VBScript编译成p代码,在字节码级别启用VBScript调试,这有助于分析漏洞利用并了解VBScript的运行方式。CVE-2018-8174的案例表明,当内存分配具有高度可预测性时,use-after-free漏洞很容易被利用。

4月下旬,我们在沙箱中发现了一个新的Internet Explorer 0 day漏洞CVE-2018-8174并写了一篇描述文章。该漏洞使用了CVE-2014-6332 poc中一种众所周知的技术,它基本上“破坏”了两个内存对象,并将一个对象的类型更改为Array(用于对地址空间的读/写访问),另一个对象更改为为Integer用于获取任意对象的地址。

CVE-2014-6332是针对写入任意内存位置的整数溢出利用,但我的兴趣在于如何调整此技术以利用use-after-free漏洞。要回答这个问题,让我们考虑一下VBScript解释器的内部结构。

无文档记录的平台

调试VBScript可执行文件是一项繁琐的工作。在脚本执行之前,它被编译成p代码,然后由虚拟机解释。没有找到关于此虚拟机的内部结构及其说明的开源信息。我花了很多精力来追踪几个网页,其中包含1999年和2004年的微软工程师报告,这些报告与p代码相关。那里有足够的信息让我完全逆向所有VM指令并写一个反汇编程序!在我们的Github存储库中可以找到用于在IDA Pro和WinDBG调试器的内存中反汇编VBScript p代码的最终脚本。

通过理解解释的代码,我们可以精确地监视脚本的执行:可以获得任何给定时刻执行代码的完整信息,并且可以观察脚本创建和引用的所有对象。所有这些都有利于分析。

运行反汇编脚本的最佳位置是CScriptRuntime :: RunNoEH函数,它直接解释p代码。

CScriptRuntime类中的重要字段

CScriptRuntime类包含有关解释器状态的所有信息:局部变量,函数参数,指向堆栈顶部和当前指令的指针,以及编译脚本的地址。

VBScript虚拟机是面向堆栈的,包含100多条指令。

所有变量(本地参数和堆栈上的变量)都表示为16个字节的VARIANT结构,其中高位字表示数据类型。某些类型值在相关的MSDN页面上给出。

CVE-2018-8174 利用

下面是类'Class1'的代码和反汇编的p代码:

1.png

函数34是类'Class1'的构造函数。

OP_CreateClass指令调用VBScriptClass :: Create函数来创建VBScriptClass对象。

OP_FnBindEx和OP_CreateVar指令尝试获取参数中传递的变量,这些参数尚不存在,它们由VBScriptClass :: CreateVar函数创建。

此图显示了如何从VBScriptClass对象获取变量。变量的值存储在VVAL结构中:

要了解利用,非常重要的一点是,了解变量在VBScriptClass结构中的表示方式。

当在function 36 ('SetProp')中执行OP_NamedSt'mem'指令时,它调用先前堆叠的类的实例的默认属性Getter,然后将返回的值存储在变量'mem'中。

***BOS(8292,8301)*** mem=Value *****
0000OP_Bos1 0
0002OP_LocalAdr -1 <-------- put argument on stack
0005OP_NamedSt ‘mem’ <-------- if it's a class dispatcher with Default Property Getter, call and store returned value in mem

下面是function 30 (p)的代码和反汇编的p代码,在执行OP_NamedSt指令期间调用它:

2.png

该函数的第一个基本块是:

***BOS(8626,8656)*** P=CDbl(“174088534690791e-324”) *****
0000OP_Bos1 0
0002OP_StrConst ‘174088534690791e-324’
0007OP_CallNmdAdr’CDbl’ 1
000EOP_LocalSt 0

该块将字符串'174088534690791e-324'转换为VARIANT ,并将其存储在本地变量0中,为函数的返回值保留。

设置好返回值但返回之前,此函数执行:

For IIIl=0 To 6
IIIlI(IIIl)=0
Next

这会调用“Class1”实例的garbage collector,并导致悬空指针引用,就是我们之前讨论过的Class_Terminate()中的use-after-free漏洞。

***BOS(8855,8874)*** Set llII=New Class2 *****
0047OP_Bos1 4
0049OP_InitClass ‘Class2’
004EOP_LocalSet 1

OP_InitClass'Class2'指令在先前释放的VBScriptClass的位置创建类'Class1'的“evil twin”实例,该实例仍由function 36 ('SetProp')中的OP_NamedSt 'mem'指令引用。

“Class2”类是“Class1”类的“evil twin”:

3.png

内存中变量的位置是可预测的。VVAL结构占用的数据量等于0x32 + UTF-16变量名的长度。

下面的图表显示了在分配'Class2'代替'Class1'时,'Class1'变量相对于'Class2'变量的位置。

当function 36 ('SetProp')中的OP_NamedSt 'mem'指令执行完成时,function 30 (p)返回的值通过Class1中VVAL 'mem'的悬空指针写入存储器,覆盖 Class2中的VVAL 'mem'。

因此,String类型的对象被转换为Array类型的对象,之前被认为是字符串的数据被视为Array控件结构,允许访问进程的整个地址空间。

总结

我们的脚本将VBScript编译成p代码,在字节码级别启用VBScript调试,这有助于分析漏洞利用并了解VBScript的运行方式。此脚本位于我们的Github存储库。

CVE-2018-8174的案例表明,当内存分配具有高度可预测性时,use-after-free漏洞很容易被利用。野外攻击针对旧版Windows。在Windows 7和Windows 8.1中最有可能发生其利用所需的内存中对象的位置。

自动漏洞利用保护(Automatic Exploit Protection (AEP))是卡巴斯基实验室产品的一部分,它通过以下判决阻止漏洞利用的各个阶段:

· HEUR:Exploit.MSOffice.Generic

· HEUR:Exploit.Script.CVE-2018-8174.a

· HEUR:Exploit.Script.Generic

· HEUR:Trojan.Win32.Generic

· PDM:Exploit.Win32.Generic

源链接

Hacking more

...