记录黑客技术中优秀的内容, 传播黑客文化,分享黑客技术精华

Xen SMEP (and SMAP) bypass

2016-08-22 16:55

介绍

在先前的博客文章1里,我讨论了我探索Xen的SYSRET bug的流程。我有提到,我能够绕过SMEP,但是我并没有说具体的细节,因为我想做一些深入的研究–我觉得我在Xen使用的绕过SMEP的方法在linux下也适用。

当时我还不知道,这个技术在2014年中旬就已经被发表出来了,叫做”ret2dir”(return-to-direct-mapped-memory)。这个技术已经被公开了,我接下来要说的就是关于”如何利用Xen的direct mapped memory(直接映射内存)来绕过SMEP和SMAP机制”,以及“如何使用我的exploit绕过SMEP并且简化dom0-domU的数据隧道“。

据我所知,目前还没有公开讨论的利用ret2dir在Xen上进行exploit的文章。

SMEP 和 SMAP 简介

SMEP(Supervisor Mode Execution Prevention),在现代intel处理器上,当设置了CR4存器的控制位时,会保护特权进程(比如在内核态的程序)不能在不含supervisor标志(对于ARM处理器,就是PXN标志)的内存区域执行代码。(直白地说就是内核程序不能跳转到用户态执行代码)

这种保护使得以往的exploit使用的ret2user的方法直接失效。ret2user即在内核控制执行流,使之跳转到用户可控的用户空间执行代码的技术。因为SMEP,在用户空间的页表的虚拟地址并没有supervisor标志,当跳转到用户态时,会触发异常。

SMAP( Supervisor Mode Access Prevention),同理,这个和SMEP差不多,只不过SMEP负责执行控制,这里负责读写控制。因此内核态不能读写用户态的内存数据。那你可能会疑惑了,如果这样限制的话,内核和用户态程序怎么交流?通过修改标志位,使某位置临时取消SMAP,来实现精确位置的读写。

SMEP 和 SMAP 的绕过

这里有两种常用方法来绕过SMEP:

  1. 构造一个ROP来修改CR4的对应标志位2
  2. 通过一块可控的可读写可执行(RWX)内存来构造shellcode修改CR4标志位。3456

对于第一个选项,ROP并不理想,你需要担心ROP的稳定性,因为不同的系统对应的ROP可能不同。比如在Xen里,不同开发商的不同编译器会产生不同编译结果。要想使ROP很有效,就需要地址泄露以使ROP不依赖任何系统版本,因此这种方法是下下策。

使用一块RWX属性的内存是最完美的,我也找到一个通用的方法来绕过Xen的SMEP,称之为”direct mapping“,能够在Xen和linux(或者其他系统)上都顶用。就如我一开始说的,已经有人发表过在linux上应用这种方法的技术了6

值得注意的是,利用ret2dir在linux制造不可执行的direct mapped memory(直接映射内存)绕过SMEP的方法已经被成功修补了。不过,这个在绕过SMAP上还是可以用,只是会更加困难7。
另外,感谢缓冲机制的添加,才有了最近row hammering exploit的结果8。由于Xen的系统特性,我们可以利用direct mapped memory直接绕过SMEP和SMAP。

因为自2011年开始,Xen管理系统(hypervisor)已经有SMEP了,意味着我们在利用SYSRET bug的时候,会遇到不能用的情况,或者可能会有更加新的漏洞.

Direct mapped memory 基础

要想进一步理解direct mapped memory,我推荐读5,尤其是其中的3.2节。简单地说:为了提升性能,许多内核利用大块虚拟地址指向大多数或者所有的物理内存。注意,这个虚拟地址的范围在ring0层,用户层并不知情。虚拟地址到物理地址的映射是一对一的。在这个范围内,内核或者hypervisor能够快速地在虚拟地址与物理地址间切换。

任何物理帧号( physical frame number:PFN),可以有效地添加到direct mapped memory内存范围的基址里。然后你有了一个合法的虚拟地址,通过专门的处理虚拟地址的而不是物理地址的函数来操作该地址;同时,虚拟地址的物理帧号可以快速地推导出来而不是通过遍历页表得出。而在linux中,CR3寄存器维护着页表基础,并存储着每一级页表的物理地址,所以该技术在很大程度上使用着页表的代码。

所以,通过直接映射的方法,会出现多个虚拟地址指向相同物理地址的可能。我们把这种多地址指向同一个底层页面称作”aliasing“。

直接映射内存的基址在Linux和Xen上是固定的。即使在Linux上内核地址空间布局随机化,但是映射的基址是不受影响的。在Xen上,没有内存布局随机化,所以映射基址总是固定的。

不废口舌了,回到绕过SMEP的重点上:因为多地址映射同一个物理地址的缘故,我们可以让ring0的虚拟地址指向在用户空间虚拟地址指向的物理地址,只要在用户层能够查询到虚拟地址对应的底层物理地址,就能实现用户层控制ring0的虚拟地址的内容。

Xen 直接映射

让我们进一步接触Xen的map操作。通过查看xen/include/asm-x86/config.h 文件,可以理解它是如何工作的,下面就是相应的条目:

/*
 * Memory layout:
 * 0x0000000000000000 - 0x00007fffffffffff [128TB, 2^47 bytes, PML4:0-255]
 * Guest-defined use (see below for compatibility mode guests).
 * 0x0000800000000000 - 0xffff7fffffffffff [16EB]
 * Inaccessible: current arch only supports 48-bit sign-extended VAs.
[SNIPPED]
 * 0xffff830000000000 - 0xffff87ffffffffff [5TB, 5*2^40 bytes, PML4:262-271]
 * 1:1 direct mapping of all physical memory.
[SNIPPED]

可以看到,在最后一个条目里,直接映射的地址范围是0xffff830000000000 – 0xffff87ffffffffff.起始地址分配给DIRECTMAP_VIRT_START:

/* Slot 262-271/510: A direct 1:1 mapping of all of physical memory. */
#define DIRECTMAP_VIRT_START (PML4_ADDR(262))
#define DIRECTMAP_SIZE (PML4_ENTRY_BYTES * (511 - 262))
#define DIRECTMAP_VIRT_END (DIRECTMAP_VIRT_START + DIRECTMAP_SIZE)

以DIRECTMAP_VIRT_START 常量作为一个突破口,比如__virt_to_maddr() 函数会调用这个常量,借此可以理解Xen hypervisor利用直接映射进行页面转换的过程.

通过调试hypervisor,或者做一个带后门的hypervisor,我们可以轻易地理解到,映射的内存是RWX属性的.这意味着只要是一个Xen 客户操作系统,就能查询任何在使用的底层物理地址,如何就能通过direct map来进行攻击了.

Xen physical-to-machine 表

如果你对Xen很熟悉的话,你应该知道,这里还有额外的抽象层关联着物理地址,一个客户(user domain:domU)操作系统,当需要将虚拟地址映射到物理地址的时候,并不是真的直接映射到物理地址,对于Xen来说,是伪物理地址,或者客户伪物理帧号(GPFN),即使有时候叫做物理地址.Xen 用machine address(机械地址)和machine frame number(MFN)来代表实际的物理地址.physical-to-machine(p2m) 映射是一个用于维护物理地址与机械帧号关系的表.这个表能够通过物理帧号索引,索引值会指向机械帧号,此机械帧号指向实际的物理内存页.更多关于p2m的信息可以查看9

我试着图形化表述一下他们的关系:

1

这个设计允许在不影响系统的情况下实现用户挂起、机器迁移,就像真实的机械帧可以改变,但是被os所虚拟化的物理地址不受影响。

大多数客户操作系统都不知道它认为的真实的物理地址正在被基于Xen驱动层的hypervisor通过hypercall转换。

重点在于,p2m映射会被paravirtualised guest kernel(PV guest kernel)暴露,就像guest中的Xen 驱动需要向各种hypercall查找并提供机械地址。如果这个表被暴露,就意味着我们能够使用内核模块在p2m表之外读取MFN。

绕过SMEP/SMAP

现在让我们把一切串起来。再次审视文章[1]里的exploit,在执行payload前,我们能够控制hypervisor的一个iret的地址,意味着我们可以跳转到任何地址,现在,让它指向我们可控的代码段,但是不违反SMEP.

我们知道,Xen 在hypervisor地址空间维护着一组虚拟地址,例如DIRECT_VIRT_START + MFN指向的是物理页.一个客户操作系统,有权限操作p2m表,能够决定在一个特定用户空间的虚拟分配里返回的物理MFN.这些都是由vaddr->PFN->MFN来实现的.我们知道的是Xen为 DIRECT_VIRT_START使用的静态地址,这意味着用户也知道.因此,为计算MFN,用户需要一个hypervisor-only的地址(不会触发SMEP的地址),来指向用户可控的数据.

下面是图形化的关系:

2

如同前面提到的,direct mapped memory 是RWX(可读可写可执行)的,所以xen为每个用户维护一个所有物理页的直接映射关系,所有的物理页也都是RWX属性的.这意味着我们可以在用户层放shellcode,通过direct mapped 制造一个虚拟地址引用它,然后通过重定向的hypervisor来指向这个地址而不是跳转到用户层的虚拟地址空间,这样我们就能绕过SMEP了.

下面代码的示范了如何在lkm上操作:

p = vmalloc(4096);
<copy shellcode to p>
pfn = vmalloc_to_pfn(p);
mfn = get_phys_to_machine(pfn);
smep_bypass_addr = (char *)(DIRECTMAP_VIRT_START + (mfn << PAGE_SHIFT));

payload 简化

直接映射不只在绕过SMEP的时候顶用,也可以避免很多事:
比如在hypervisor中动态分配内存,查找内存洞去放shellcode等.

如同在[1]里写的那样,这里有3段payload,我可以通过提供直接映射到合适的地址来直接重定向代码到stage1.当钩取各种MSR来允许移植到dom0(ring0 domain)时,我可以直接使hook指向另一个直接映射的内存来解决.

我也可以将dom0到domU的数据隧道简化,在domU的模块可以简化为映射读写buffer到虚拟地址并通知hyperv payload指向它.

当dom0的payload传输或者接收来自我的payload的syscall后面的数据时,数据可以简单地通过直接映射解决,并且domU的payload可以通过mailbox 标志来获得有效的提醒.

结论

利用Xen绕过SMEP和SMAP是相对较容易的,上面描述的方法对任何hypervisor的漏洞都可以非常有效地在用户层触发,Xen 有很多方法可以减缓这个方法的利用.

比如把直接映射的内存设定为不可执行,就可以有效阻止SMEP,虽然不能阻止SMAP.

一些hypervisor内存布局随机化使得搞事情更加困难,攻击者不得不尝试内存喷射或者泄露随机化地址的基址.理想的情况是,随机化应当应用在所有的hypervisor的虚拟内存,而不是仅仅针对直接映射的内存.

 

*原文:nccgroup  译者:VitorV  Mottoin整理发布

未经允许不得转载: » Xen SMEP (and SMAP) bypass

知识来源: www.mottoin.com/87748.html

阅读:259442 | 评论:0 | 标签:逆向破解 bypass Payload SMAP SMAP绕过 SMEP SMEP绕过 Xen

想收藏或者和大家分享这篇好文章→复制链接地址

“Xen SMEP (and SMAP) bypass”共有0条留言

发表评论

姓名:

邮箱:

网址:

验证码:

公告

关注公众号hackdig,学习最新黑客技术

推广

工具

标签云

本页关键词