早些时间,Fireeye 发现了一个用 docx 格式的文件进行攻击的 0day。参见《Two for One: Microsoft Office Encapsulated PostScript and Windows Privilege Escalation Zero-Days THE EPS AWAKENS》。
CVE-2015-2545, 这个 CVE 引起了我的注意,当 @PhysicalDrive0 在推特上发出下面这个样本哈希值时。我觉得这个哈希可能与上面提到的文章有关,我检查了这个样本。
哈希值:375e51a989525cfec8296faaffdefa35
在一番分析之后,我发现这个样本完全逃避了 EMET 的检测。
这是运行截图:
现在,一个doc利用也逃避了 EMET 的检测,而且是以一种非常整洁的手段。
幸运的是,Malware Bytes Anti Exploit 和 Hitman Alert 抓到了它(那些想要保护自己的人永远尝试多种防护手段),尽管攻击者比较好地制作了他们的载荷,他们也没有逃过 MBAE 的堆检测(改天我也许会讲一下这个故事)。
这是在加载它的 dll 之前,对一些 api 的调用追踪:
ntdll!ZwCreateEvent + 0x5
r eax = ordinal_ZwProtectVirtualMemory // 获取 ZwProtectVirtualMemory 的调用序号
kernelbase.dll!GetModuleHandleA()
kernel32.dll!GetTempPathA()
kernel32.dll!CreateFileA()
kernel32.dll!WriteFile()
kernel32.dll!CloseHandle()
kernel32.dll!LoadLibraryA()
这里有一份可用的 windbg 调试日志。
这些 api 可用在利用的不同阶段帮助导航分析。
ba r4 ZwProtectVirtualMemory -> 对 ZwProtectVirtualMemory 在这里下一个内存读取断点,既然这个利用用到了它的原始调用序号,显然它需要去从 ntdll 的内存里面获取这个序号。剩下的 api 很容易就能获取到。
现在让我们来关注一下保护机制,和这个特别的样本是如何来 Bypass EMET 的。
这个样本利用内存破坏来覆写一个长度为 0x7fffffff 的字符串对象,然后使用 ROP 和 ShellCode,所以 EMET 理应能在 SimExecFlow、Stack Pivot、Caller Check、EAF 与 EAF+ 这几个阶段捕获它的行为。然而没有...
ROP 逃逸
这个漏洞将一个 String 对象的长度覆写为 0x7fffffff,并且利用它去读取整个内存空间以搜索 ROP 小部件。下面包含了一些它搜索的小部件,这从 EPS 文件利用代码的调用方法里面很容易看得出来。
String 对象替换:注意0x7fffffff
ROP 部件搜索
既然 EMET hook 了 ZwProtectVirtualMemory,直接返回到这个函数会变得很明显,因此才有了下面这种新颖的方式。ZwCreateEvent 或者其他任何没有被 EMET hook的 ntdll 的导出函数都可以被用在这里,既然所有的 Nt/Zw 函数跳转共享同一个函数体,任何 函数头+5 都可以被传入任意调用序号以跳转过来,以调用一个不同的 NT API。作者想到了这种创新的方式,并且发现了一个通用的逃逸技巧,前提是它能对抗 ASLR。
x86:
[B8] [xx xx xx xx] mov eax, ordinal no.
mov edx,0x7ffe0300
call [edx]
retn [no of params]
x64:
[B8] [xx xx xx xx] mov eax, ordinal no.
xor ecx,ecx | mov ecx, somevalue
call fs:[0xc0]
retn [no of params]
这种方法的唯一问题是 ZwProtectVirtualMemory 的调用索引需要被硬编码。攻击者使用任意地址读取在内存里搜索 ZwProtectVirtualMemory 的头部并且读取其序号。
现在,这种技巧面临的问题是,如果 ZwProtectVirtualMemory 被一些防护软件 Hook 了,函数的前部分看起来会像是这样:
x86:
[E9 xx xx xx xx] jmp Hook
[CC] int3
int3
int3
int3
int3
call [edx]
retn [no of params]
x64:
[E9 xx xx xx xx] jmp Hook
[CC] int3
int3
call fs:[0xc0]
retn [no of params
在这种情况下,如果攻击者试着去获取索引号,他们只会获得 E9 指令后面一个随机相对偏移里面的一个字节。为了处理这种情况,攻击者精心构造了 PS 文件,这个 PS 文件里面会从 ZwProtectVirtualMemory 开启的内存里面搜寻 B8 [索引号] 00 00 这样的字节模式,并且累加计算它读过 0xC2(0xC2 是 RET N 指令的字节码) 的次数。通过这种方式,它将会知道有多少函数被跳过,直到它遇到一个没有被 Hook 的 NT系列函数调用头,然后获取这个函数的调用索引,最后减去它遇到的 0xC2 的次数。
在我的例子里,另外一些 Hook 也可能被其他所设置,所以对应的汇编看起来是下面这样子的:
现在,利用代码读取了整个内存,直到它发现 0x77be0024,它从这里获取了 0x50,这是 ZwTerminateThread 的调用序号。从 ZwProtectVirtualMemory 开始,它读取了 3 个的 C2,将这两个值进行相减...
完美地逃过了 ROP 检测。
直到现在,EMET、MBAE 和 Hitman 都没有检测到任何异样。
EAF 逃逸
ROP 检测是利用检测产品的核心检测方法,一旦攻击者让 ShellCode 执行起来,攻击者就和防护软件处在同一内存空间,现在理论上上还无法防御这种类型的攻击。
当 ROP 为检测机制的时候,想要逃避 ROP 的审查而做些什么事是很困难的,因为攻击面很窄(只能利用小部件),但是一旦代码(指 ShellCode)在内部完全执行起来,没有内核模式的支持,任何检测产品都无法站在恶意载荷的上面。
基本来讲,EAF 在 kernel32, kernelbase, ntdll 三个dll 的导出地址表上各放了一个硬件断点。只要导出地址表被访问,EMET 就会判断调用地址是否位于堆上(更确切地说它会判断地址是否位于所有已加载的模块内),且尝试去锁住攻击,让进程崩溃。
通常大多数 ShellCodes 都以通过 PEB 查找 kernel32.dll 的基地址开始,然后开始映射导出表中攻击所需用到的函数,这样一来,EMET 就会将其抓获。
然而,在这个例子里面我们清晰地看到, ShellCode 并没有查找 PEB,取而代之的是,它从 fs:[00] 查找当前的 SEH 链,这给了他们一个 msvcrt.dll 里面的一个句柄地址
然后,按照反汇编代码所示的那样,他们开始回退搜索 0x5A4D('MZ'), 并且进一步校验PE头的特征,以确保他们获得了正确的 msvcrt 模块的基址。有了 msvcrt 模块的基址后,利用代码寻找它的导入表(EMET并没有审查对导入表的操作), 并且发现导入模块。
kernel32.dll!GetTempPathA()
kernel32.dll!CreateFileA()
kernel32.dll!WriteFile()
kernel32.dll!CloseHandle()
kernel32.dll!LoadLibraryA()
有了这些导入表的信息后,ShellCode(shellcode 与 dll都被嵌入在 PS 文件内)将 plugin.dll 写入并且加载它。既然上述 Windows api 是从堆里面被调用的, MBAE 检测到了该行为但是 EMET 没有检测到。Hitman Alert 产品在另一方面都不允许 ZwProtectVirtualMemory 调用获得成功,所以它甚至没有让 ShellCode 开始执行,并且在 ShellCode 执行时触发了 DEP异常)
在这个文件里面,我们可以看到 6064a100000 是
pushad , mov eax, fs:[0x0]
对应的机器码。
紧随其后的是:
putinterval xx_26500 xx_17410 1072 xx_23655
<55555555666666664d5a90000300000004000000f
(作者当时)在 VT 上搜索了一下,似乎很多攻击者很粗暴地就把这个 eps文件拷贝到了新的工程里面,并且覆写了里面嵌入的 dll,VT上对此类样本的检出率都是 12/49 (当时)。
现在,有了一个已加载的 dll, 攻击者想干什么都不关安全审查什么事了。
特别的,这个载荷启动了一个叫做 igfxe.exe(也许在下一篇文章里我会分析这个)
哈希值:6c33223db475f072119fe51a2437a542
感谢 @PhysicalDrive0 提供哈希值。
结论:这个在野外的样本逃逸了像 EMET(这种被政府或组织鼓励安装的软件) ,导致只有一种可能的保护机制,从而可以获取一些别人不知道的私有的东西。
敬请关注另一篇如何防御这类攻击的博文。
r41p41 于 2016年2月5号发表
原文链接:http://casual-scrutiny.blogspot.sg/2016/02/cve-2015-2545-itw-emet-evasion.html
翻译 by 看雪翻译小组 银雁冰
[培训]《安卓高级研修班(网课)》月薪三万计划,掌
握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法