freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

绕过Windows Control Flow Guard思路分享
FreeBuf_303266 2018-04-17 10:00:39 570238

前言

本文的主要内容来源于2018NDSS的文章Back To The Epilogue: Evading Control Flow Guard via Unaligned Targets.

通常,攻击者可以通过利用内存漏洞来截获控制流。但是研究人员也提出了各种各样的防御手段避免发生这样的问题,例如地址空间随机化(ALSR),异或执行(XOR Execute),控制流完整性(CFI)等各种各样的防御措施。CFI通过强制控制流完整性保证程序的执行不会出现问题,目前部署最为广泛的CFI是windows提供的control flow guard(CFG)。CFG目前部署在最新的Windows 8.1,Windows 10上,已经超过了5亿使用量。因此一旦在CFG上出现问题,可能导致非常严重的后果。

Windows CFG实现

Windows的CFI实现称为Control Flow Guard(CFG),因为实际的性能要求,不可能做到非常精确的CFI,因此,实际在windows上部署的CFI是粗粒度的、前向CFI。首先,粗粒度的CFI是:所有的有效跳转地址为一个全局的集合,即不精确的为每一个间接跳转指定一个有效跳转地址;其次,什么叫做前向CFI:只考略call,jump的直接跳转和间接跳转,没有计算ret的情况。此外,Windows CFG实现还依赖于bitmap表,该表存储的信息是关于目标地址是否有效的一张表。bitmap表中的两位与实际地址的16byte一一对应,因此有四种情况:

00:该地址范围没有有效的跳转地址

01:地址范围包含导出抑制表目标

10:只有16位对其的地址有效(该范围的第一个地址)

11:地址范围的所有地址均有效

因此,可以看出一个非常明显的漏洞:

image

在编码为11的情况在,整个16位地址均为有效跳转地址,此时,如果存在间接跳转漏洞,例如:jump [eax] (eax = 0x1007),当eax的值可以修改的时候,跳转地址可以跳转到0x1007地址的上面的指令,(add rsp, 0x40)这是Windows CFG的设计漏洞之一。其次,由于Windows CFG是前向的CFI防御,因此不能阻止重写return address的情况,则利用该特点,如果可以改写ret addr,也可以达到绕过CFG的目的。

Bypass CFG

在论文中提到了一种绕过CFG的方法,该方法和以往的绕过相比较:

需要更少的栈控制,只需要控制栈顶的区域即可

灵活性更大,在实际攻击场景中可以复现

所需gadget在Windows系统中广为存在

文章定义了两种gadget,通过两种gadget的配合可以实现绕过CFG。定义P(p)R(r) gadget:

该gadget是一个有效的CFG目标

该gadget是一条 add {e, r}sp, m 指令,可以不存在

该gadget是n条 pop 指令,可以不存在

该gadget是一条 ret r 指令,r可以为0

p = m + wn(w是一个字的长度,32-bit是4,64-bit是8)

这样一系列定义其实描述了程序函数调用结束的操作。例如上图中有效代码段

add rsp, 0x40
pop rdi
pop rbx
ret

根据定义,该gadget可以定义为P(80)R(0),p = 64 + 8 * 2, r = 0。该gadget链主要目的是更改栈帧的位置,以便修改ret addr。在32位系统中,参数传递是通过栈来传递,通过改变参数即可以影响栈中的内容,通过这种方式可以达到修改ret addr的目的。然而,在64位系统中参数传递是通过寄存器完成的,因此,栈中的内容一般不会被影响,所以重新定义了 S gadget 以便可以修改栈中内容。通常一个尾调用优化可能产生S gadget。

定义S gadget:

该gadget是一个有效的CFG目标

该gadget溢出n个寄存器到寄存器参数区域(RPA)

该gadget以一个受控制的间接跳转结束

S(2) gadget DEMO

mov [rsp + 0x8], rcx
mov [rsp + 0x10], rdx
sub rsp, 0x40
...
mov rax, [rcx]
mov rax, [rax + 0x20]
add rsp, 0x40
jmp [dispatch_fptr]

rcx, rdx一般在Windows 64-bit函数调用中是作为第一个参数和第二个参数,假设参数可以被攻击者控制,则在这段gadget中,一个被攻击者控制的参数被传入栈中,即有机会修改ret addr。

下图展示了一个PR-P链的连接过程:

Attack

如何利用PR,P gadget进行攻击,论文中以Edge作为攻击目标,实施远程攻击。首先需要知道object在内存中的地址,因此需要有地址泄露的过程,其次,我们需要伪造一些数据,要有一定的写内存操作。在攻击的Demo中,利用CVE-2016-7200和CVE-2016-7201两个Edge漏洞,达到地址泄露和任意内存读写的权限。

image

S(2) gadget

1 ; @ chakra+0x31f0000
2 chakra!ScriptEngine::EnumHeap:
3 mov r11, rsp
4 ; Spill arguments to RPA
5 mov [r11+0x10], rdx
6 mov [r11+0x8], rcx
7 ; Allocate stack frame
8 sub rsp, 0x28
9 ; Prepare call to rcx->__vfptr[10]
10 mov rax, [rcx]
11 mov r8, rdx
12 xor edx, edx
13 mov rax, [rax+0x50]
14 ; Deallocate stack frame
15 add rsp, 0x28
16 ; Perform indirect call via CFG
17 jmp cs:__guard_dispatch_icall_fptr

P(16)R(0) gadget

pop rdi
pop rsi
ret

目标函数是JavascriptFunction::HasInstance虚函数,首先定位JavascroptFunction object在内存中的位置,通过修改VTable pointer指向一个伪造的VTable,其中instanceof函数在VTable中的位置为0x200,将该函数修改为S(2) gadget 地址。当instanceof函数调用时即执行S(2) gadget。

S gadget 得到一个指向JavascroptFunction object的指针作为第一个参数,指向Var的指针做为第二个参数,S gadget 在第5行和第6行将参数放入栈中。第13行将JavascroptFunction偏移0x50的放入rax中,之后jmp rax执行P(16)R(0) gadget。

我们只需要设置一个自己构造的Var指针,即可截获控制流。

截获控制流之后,便可以通过传统的ROP进行攻击。

总结

论文中提出了一种新的绕过Windows CFG的方法,具有一定的灵活性,并且文章中提到在Windows系统中存在较多的可用gadget,因此,如果进行系统性的扫描Windows所有常用动态库,可以在很多场景下进行利用。

*本文作者:jaguoooooo,转载请注明来自FreeBuf.COM

# windows # 绕过 # control flow guard
本文为 FreeBuf_303266 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
FreeBuf_303266 LV.1
这家伙太懒了,还未填写个人描述!
  • 1 文章数
  • 0 关注者
文章目录