译者:xd0ol1 (知道创宇404安全实验室)

原文链接:https://labs.bluefrostsecurity.de/files/Look_Mom_I_Dont_Use_Shellcode-WP.pdf
上篇,这里为后3部分的翻译,不对之处还望多多指正。

4 沙箱逃逸

默认情况下,Windows 10系统中的Internet Explorer 11并未启用增强保护模式(EPM),而我们的目标是要在最高级别的安全设置下进行漏洞利用,因此在设置中我们手动启用增强保护模式和增强保护模式的64位进程这两项。

在完成上述更改后,我们的payload将在受限的AppContainer沙箱中运行。为了能对系统进行更改,我们需要找到一种突破沙箱的方式,这样才能以更高的Integrity Level(Medium IL或以上)来执行代码。

4.1 关于Internet Explorer里的Zone

在Internet Explorer中有个zone的概念,不同的安全设置对应于不同的zone,其中,Internet上的页面通常在Internet Zone里进行渲染,而本地内网上的页面则在Local Intranet Zone里进行渲染。

这里需要注意一点,即便你手动启用了EPM,但Local Intranet Zone中却不会启用EPM,也就意味着在Local Intranet Zone里渲染的网页是由沙箱外的32位Medium IL进程来加载的。

此性质已是人尽皆知了,过去也曾被多次用于绕过Internet Explorer下的保护模式[9][10]。这些攻击首先会从沙箱进程内启用一个本地Web服务,然后让浏览器访问http://localhost/并再次执行这个exploit,此时页面渲染就会由沙箱外的Medium IL进程来完成。

但是微软并不决定修复这个问题,而是建议用户启用EPM来防止沙箱逃逸[11]。启用EPM后,渲染过程将在拥有网络隔离功能的AppContainer沙箱内运行[12],特别的,它能阻止沙箱进程和本地机器建立连接并且阻止它接受新的网络连接,这就成功解决了前面所描述的攻击形式。

另一方面,在执行这种攻击时,我们可以不必局限于localhost域名,如果我们能设法将被认为是Local Intranet Zone中的域名解析到外部的Web服务器地址,那么我们还是能在AppContainer沙箱外以Medium IL进行页面的渲染。Internet Explorer基于许多规则来判断站点是否属于Local Intranet Zone[13],其中有个PlainHostName规则,也就是如果域名中不包含任何句点,那么它将被自动映射到Local Intranet Zone上。

所以问题就变成如何在沙箱进程内注册一个不含任何句点的且解析到外部IP地址的域名信息,事实证明这能通过本地NetBIOS Spoofing技术来实现。

4.2 NetBIOS Spoofing

NetBIOS Name Service (NBNS) 协议是Windows系统上进行名称解析的UDP广播协议。通常程序在进行域名解析时会用到DNS协议,但如果由于某些原因导致DNS查询失败,那么系统就会尝试使用NBNS协议来进行解析。

而NetBIOS Spoofing则是一种常见的网络攻击方式,当然,在Hot Potato Exploit[14]中它也被用来进行Windows系统的本地权限提升。

另外注意一点,NBNS数据包中的Transaction ID(TXID)字段将用于保证请求包和响应包的正确匹配,其中,域名“BLUEFROST”对应的NBNS请求包如下:

在典型的NBNS Spoofing期间,攻击者将响应本地网络上接收到的任何NBNS请求,由于此过程中初始的NBNS请求包信息是不可见的,因此我们无法获知使用的16位TXID,但是我们可以通过快速迭代来遍历可能的65536个TXID值,并最终猜测出正确结果。

正如前面所述,AppContainer的网络隔离功能将阻止沙箱进程向本地机器发送数据包,但事实证明这个规则是有例外情况的,比如沙箱进程仍然能向本地的137端口发送UDP数据,这就使得在沙箱进程内进行本地NBNS Spoofing成为可能。

因此,我们首先借助本地NBNS Spoofing注册一个不含任何句点且解析到我们外部Web服务器IP的域名信息。之后,我们通过浏览器访问新注册的域名,即我们的Web服务器,虽然此Web服务器位于Internet上的某个地方,但渲染的页面现在却被认为是位于Local Intranet Zone中的,因此渲染进程将会在沙箱外运行。而后,我们再次触发exploit,这次就会由沙箱外的32位渲染进程以Medium IL来执行代码。

上面的截图显示我们成功在沙箱外以Medium IL创建了一个新的notepad.exe进程。

5 禁用EMET保护

对于特定EMET保护的绕过或直接完全禁用EMET的研究在过去已经有很多了,相关文章的链接可在FireEye的最新博文“Using EMET to Disable EMET”[15]中找到。

但是,不同于之前的大部分技术,在我们的exploit中进行EMET绕过时,我们并没有执行代码的能力。因此如前面提到的FireEye文章中那些依赖于执行特定ROP代码以禁用EMET保护的技术,虽优雅,然却不适用于我们的情况。

不过,我们却拥有强大的内存读写能力,我们可以借此来尝试绕过特定的EMET保护或者将其完全禁用掉。

在本部分中,我们将看下EMET针对我们的exploit所用到的保护技术以及我们如何成功绕过最新的EMET 5.5版本。

另外,下述的分析都是基于的EMET64.dll 5.5.5870.0版本。

5.1 Attack Surface Reduction (ASR)

我们在EMET 5.5启用的情况下执行exploit,EMET会检测到威胁并将其阻止,给出的警告为“ASR check failed”。更多详细信息可在事件日志中找到:

对于EMET中的ASR保护,它可阻止有潜在风险的特定模块或插件的加载。

当我们试图实例化WScript.Shell(wshom.ocx)时,由于此控件在ASR的黑名单中,所以EMET将会停止exploit的运行。我们知道EMET是通过hook LoadLibraryEx函数来检测控件加载的,为了快速验证ASR是否为阻止exploit执行的唯一保护措施,我们在调试器中动态对kernelbase!LoadLibraryEx*函数进行patch来临时去掉相应的hook,此时,再次执行exploit,这次很顺利,利用是可以成功的,也就意味着在我们的情况中只需绕过ASR保护即可。

现在我们就需要在exploit运行时找到一种借助内存读写来及时禁止ASR检查的方法。

如果我们从被hook的kernelbase!LoadLibraryExW函数开始跟起,那么最终会来到sub_1800864F0这个函数,它做的第一件事就是读取存储在EMET64.dll模块内偏移136800处的全局变量。

该读取值是一编码后的指针,由上图可知它需要通过DecodePointer函数进行解码,然后从该解码指针的0x28偏移处读取另一指针,最后再取偏移0x0处的flag值与0进行比较,如果flag值为0,那么后面所有关于LoadLibrary的检查都将被绕过。

其中,全局指针通过EncodePointer函数中使用的每个进程都不同的secret值来进行保护,而位于0x28偏移处的指针存储在堆中,我们不知道其具体分配的地址,并且存储最终flag值的内存空间会被映射到只读页上,这些都在Offensive Security的博文中[16]有详细描述。

由于我们并不拥有执行任意代码的能力,也就无法使用诸如ROP链的方式来禁用或者绕过任何保护。我们需要找到一种仅通过读写内存就能禁用EMET的方法,因此,我们接下去的精力主要放在使用EncodePointer和DecodePointer函数进行保护的全局指针上。

5.2 指针的解码

首先让我们看下EncodePointer和DecodePointer函数是如何实现的,下图为ntdll.dll模块中的RtlDecodePointer函数:

可以知道这两个函数最终都调用了ntdll!ZwQueryInformationProcess,并将内核返回的32位数作为secret值用于指针的编码或解码。但由于secret值并不保存到内存中的具体位置,也就意味着我们不能单纯通过读内存来获取它进而来对指针进行手动解码,因此接下来考虑如何获取这个secret值。

以下伪代码表示的是EncodePointer函数所执行的操作:

encoded_ptr = (secret ^ plain_ptr) >> (secret & 0x3f)

相应DecodePointer函数执行的操作如下:

plain_ptr = secret ^ (encoded_ptr >> (0x40 - (secret & 0x3f)))

其中,运算符>>表示循环右移。由于secret值的低字节会影响计算结果右移的比特数,所以我们不能直接通过异或编码指针(encoded_ptr)和相应明文指针(plain_ptr)的方式来得到secret值。

但是,我们可以很容易对secret值进行暴力破解,因为对于右移操作最多只有0x3f种可能。因此,我们将遍历从0到0x3f的所有可能情况,先对编码指针执行右移操作,然后再将结果与相应的明文指针进行异或,这样我们就会得到一个可能的secret值。此算法的伪代码如下:

for (var i = 0; i < 0x3f; i++) {
    var k = (encoded_ptr >> (0x40 - (i & 0x3f))) ^ plain_ptr;
    if (encode_ptr(plain_ptr, k) == encoded_ptr) {
    /* Found potential secret key k */
    }
}

最终我们将猜出正确的secret值。但是,由于不同secret值对同一指针的编码仍可能得到相同的编码指针,因此对单独的明文指针和编码指针组合,可能会返回多个正确的secret值。并且相较64位进程,这种影响在32位进程中则更加明显。

为了提高猜测secret值的准确性,至少需要使用两对已知的编码指针和明文指针组合。我们通过其中一对指针来暴力破解可能的secret值,然后使用第二对指针做验证,只需将其中的明文指针用可能的secret值编码,再将结果与已知的编码指针比较即可。这样,我们就将secret值的碰撞降到了可接受的水平。

5.3 查找指针对

让我们看下能否在EMET模块内找到通过读内存就能获取的已知编码指针和明文指针的组合。 如果你查看过emet64.dll内所有的EncodePointer调用,那么你会注意到,其中有次初始调用是发生在sub_180048110函数中的,如下图:

可以看到,此函数对NULL指针进行了编码,结果保存在函数第一个入参指向的地址,该函数被调用的其中一个地方是在函数sub_1800204B0内,如下所示:

其中,Ptr是EMET64模块的.data段中偏移量为0x135b80处的全局变量。

通过快速的调试查看可以知道,当EMET进行ASR检查时,该位置仍然保存着NULL指针的编码结果。因此我们找到了所需的第一对指针。

通过查看sub_180081038函数我们可以找到另一对编码指针和明文指针的组合。

此函数将对第一个入参指针进行编码,并且仅有一处被调用的地方,相应参数为函数sub_180080B40的地址。如下所示:

该函数指针编码后的结果保存在EMET64+1362a0起偏移为EMET64+0x135320相应值乘8的地址处。我们可以很容易在内存中读取这些值,从而得到第二对已知的编码指针和明文指针组合。

因此,这将使得我们可以解码iexplore.exe进程中的所有编码指针。我们不仅提供了一种禁用ASR保护的通用方法,而且该方法还可用于完全消除EMET保护的任何进程中基于EncodePointer和DecodePointer函数实现的那些保护(假设你已具有读取任意内存和获取EMET模块基址的能力)。

5.4 泄漏EMET模块基址

这里我们将借助EMET中已知的几个被hook函数,其中包括了ntdll.dll模块中的NtProtectVirtualMemory函数。我们首先通过读取jscript9.dll导入表中的RtlCaptureContext函数地址来泄漏ntdll.dll模块基址,然后我们接着看下NtProtectVirtualMemory函数开头的这几条指令。

很显然,通过检查前几字节,我们就可以确定当前进程是否受到EMET保护。为了泄漏EMET模块的基址,我们跟下EMET启用时最开始的这两条jmp指令,最终可以看到如下所示的这条指令,它将EMET64.dll模块内的偏移量赋值给了一个寄存器:

通过这条寄存器赋值指令,我们就可以计算出EMET模块的基址。

5.5 禁用ASR保护

既然我们能得到EMET模块的基址且拥有解码被保护指针的能力,那么很自然的想法就是将校验的flag值置为0以绕过ASR保护。但是,正如前面所述,该flag值存储的页面是只读的,因此我们转而替换指向此页面的指针。

所以,在泄露EMET模块的基址后,我们先按照前面的方法计算出EncodePointer/DecodePointer保护中所使用的secret值。而后借助该secret值,我们对EMET64.dll模块内偏移0x136800处的全局指针进行解码,最后使用指向NULL的指针来覆盖其中偏移量0x28处的指针。此处用到的覆盖值为EMET64+0x110ef8,它指向EMET64.dll模块.rdata段中的NULL值。

经过这么处理后,我们可以成功绕过ASR保护,进而执行我们的exploit。如果需要,也可以使用同样的方法来禁用其它的EMET保护技术。

6 结语

本文详细描述了利用我们发现的一个关于Internet Explorer 11中JavaScript实现方面的漏洞来进行exploit开发的完整过程。其中,我们阐述了许多现有的诸如DEP或CFG这样的漏洞利用保护措施就算不借助传统的ROP代码和shellcode也是可以实现轻松绕过的,只要我们能将漏洞转换成对任意内存空间的读写就可以了,之后再通过浏览器中已有的功能来执行系统命令,同时,我们还分析了如何仅通过写一个null字节就可在最新的Internet Explorer 11版本中实现这种方式的攻击。

接下去我们给出了一种借助本地NetBIOS Spoofing进行Internet Explorer中EPM绕过的新方法,我们详述了即便在开启EPM的情况下,利用之前的Local Intranet Zone方式还是可以实现Internet Explorer沙箱逃逸。

最后,我们讨论了最新的EMET 5.5版本是如何被绕过的以及我们如何通过计算secret值的方式来消除EMET中使用的EcodePointer保护。当然,所讨论的这些方法不仅可以用于禁用ASR保护,而且还可用于消除EMET保护的进程中基于EncodePointer和DecodePointer函数实现的那些缓解措施。

这里所有提到的漏洞和技术都作为Mitigation Bypass Bounty项目提交的一部分报告给了微软。其中,第2部分描述的Typed Array Neutering漏洞(CVE-2016-3210)已在MS16-063中修复,有趣的是,Edge的ChakraCore引擎自发布时就修复了同样的漏洞。

3.6节中描述的借助null字节开启上帝模式的技术(CVE-2016-0188)则在MS16-051中得到了修复,微软通过引入QueryProtectedPolicy函数来缓解此问题。

而第4部分描述的通过本地NetBIOS Spoofing实现EPM下的沙箱逃逸技术(CVE-2016-3213)在MS16-077中也得到了修复。

但最后第5部分介绍的EMET绕过技术尚未被修复,而且微软目前也没有计划去解决此问题。

总体来说,伴随着当前Windows系统中漏洞利用保护措施不断增长的数目以及稳定性的提升,exploit的开发成本被大幅增加了。但是,如果借助合适的漏洞,那么许多保护仍然是可以被绕过的,所缺乏的仅仅是想象力和创造性。 例如文中所述的data-only attacks,它就允许攻击者绕过许多的保护措施,虽然微软已经开始着手进行一些修复,但我们预计这种利用方式在未来会变得更加常见。

7 参考

[9]  Verizon, "Escaping from Microsoft’s Protected Mode Internet Explorer":
https://www.exploit-db.com/docs/15672.pdf
[10]  Zero Day Initiative, "There’s No Place Like Localhost: A Welcoming Front Door To Medium Integrity, HP Security Research":
http://community.hpe.com/t5/Security-Research/There-s-No-Place-Like-Localhost-A-Welcoming-Front-Door-To-Medium/ba-p/6560786
[11]  Zero Day Initiative, "(0Day) (Pwn2Own\Pwn4Fun) Microsoft Internet Explorer localhost Protected Mode Bypass Vulnerability":
http://www.zerodayinitiative.com/advisories/ZDI-14-270/
[12]  M. V. Yason, "Diving Into IE 10’s Enhanced Protected Mode Sandbox":
https://www.blackhat.com/docs/asia-14/materials/Yason/WP-Asia-14-Yason-Diving-Into-IE10s-Enhanced-Protected-Mode-Sandbox.pdf
[13]  Microsoft, "IEInternals: The Intranet Zone":
http://blogs.msdn.com/b/ieinternals/archive/2012/06/05/the-local-intranet-security-zone.aspx
[14]  FoxGlove Security, "Hot Potato Windows Privilege Escalation Exploit":
http://foxglovesecurity.com/2016/01/16/hot-potato
[15]  FireEye, "Using EMET to Disable EMET":
https://www.fireeye.com/blog/threat-research/2016/02/using_emet_to_disabl.html
[16]  Offensive Security, "Disarming and Bypassing EMET 5.1":
https://www.offensive-security.com/vulndev/disarming-and-bypassing-emet-5-1/


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/196/