首页
社区
课程
招聘
[翻译]野外的 CVE-2015-2545 逃逸了 EMET
2017-3-2 21:51 6333

[翻译]野外的 CVE-2015-2545 逃逸了 EMET

2017-3-2 21:51
6333

早些时间,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虚拟机自动化脱壳的方法

收藏
点赞1
打赏
分享
打赏 + 1.00雪花
打赏次数 1 雪花 + 1.00
 
赞赏  CCkicker   +1.00 2017/05/08
最新回复 (6)
雪    币: 6103
活跃值: (1207)
能力值: (RANK:30 )
在线值:
发帖
回帖
粉丝
CCkicker 2017-3-3 10:38
2
0
(^∇^*) Good
雪    币: 140
活跃值: (125)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
karlx 1 2017-3-3 16:46
3
0
看雪翻译组=百度+GG ?
雪    币: 9662
活跃值: (4588)
能力值: ( LV15,RANK:800 )
在线值:
发帖
回帖
粉丝
银雁冰 16 2017-3-3 17:11
4
0
karlx 看雪翻译组=百度+GG ?
bd和gg的前提是你得思考为和bd和gg这些文章,为什么是这个CVE?这个CVE经典吗?这个CVE相关的APT多吗?这个CVE的文章国内发的多吗?国内想了解这个CVE的需求量大吗?这个CVE调试难度大吗?为什么不翻译已经烂大街的0158?样本经典吗?为什么挑选过EMET的文章来翻译?为什么挑选组合漏洞的样本文章来翻译?为什么一次翻译有关联的两篇文章?你思考过这些吗?
雪    币: 292
活跃值: (680)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
Keoyo 2 2017-3-7 08:25
5
0
银雁冰 bd和gg的前提是你得思考为和bd和gg这些文章,为什么是这个CVE?这个CVE经典吗?这个CVE相关的APT多吗?这个CVE的文章国内发的多吗?国内想了解这个CVE的需求量大吗?这个CVE调试难度大 ...
不明白你在回复你楼上什么...楼上的意思是你们这个翻译是直接靠百度和谷歌机翻的吧...
雪    币: 18
活跃值: (979)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
猪会被杀掉 1 2017-3-7 10:20
6
0




Keoyo

不明白你在回复你楼上什么...楼上的意思是你们这个翻译是直接靠百度和谷歌机翻的吧...

hhhhhhhhhhhhhhhhh

雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
DannyJenny 2017-3-7 15:08
7
0
哪位大神能分享下样本,小弟想学习学习
游客
登录 | 注册 方可回帖
返回