竟态攻击:Hyper-V安全问题分析

硬件虚拟化为广大年夜从事IT行业的同伙供给了极大年夜的便利。同时也是“云”这一观点的紧张支持技巧之一。微软在前有VM,QEMU等产品的广泛利用下毅然决然的宣布了微软编写的虚拟化产品Hyper-V,并运用到了Microsoft Azure 云谋略平台中。今年的 Blackhat 大年夜会中也有议题对 Hyper-V 的安然问题展开了评论争论。本日我们将对其从安然角度长进行深度的阐发。

0×01 事情道理

先上一张Hyper-V布局的结构图:

当用户开启虚拟化(Intel VT)支持后,物理时机在进入Windows 内核前启动 hvix64.exe/hvax64.exe 初始化 Hypervisor 层再运行 Windows 内核法度榜样完成系统加载。

当 Hypervisor 层被启用后,宿主机在操作硬件时也会经由过程 Hyperisor 再传至物理设备,是以 Hyperisor 层的分级则为 Ring -1 (最新版的 Hyper-V 则会支持部分操作不进入Ring -1层直接传至物理设备进行操作)

宿主机内核与虚拟机内核都是Ring 0级操作,只不过宿主机可以节制虚拟机,以是,假如虚拟机发生了故障,不会影响到宿主机;宿主机发生了非致命故障,例如并非蓝屏等Ring 0下的故障,也不会影响虚拟机的正常运行。

宿主机与虚拟机之间的数据传输经由过程VMBus(虚拟数据总线)实现,VMBus是微软开拓的虚拟数据传输总线,用来宿主机和虚拟机之间互换数据和信息。应用VMBus的优点便是能进行快速、高效、大年夜数据量的数据传输,极大年夜的提升了虚拟机的机能。VMBus的道理和QEMU中的VirtIO设备类似,经由过程共享环形内存,每当要传输的数据写满全部环形内存时,就把数据发送到宿主机中。可以说,微软成功的借鉴了VirtIO设备的优点,取其优点用之,才会使得Hyper-V虚拟机机能大年夜幅提升。

和QEMU模拟设备端口读写的措施不合的是,Hyper-V整个应用了虚拟设备,而不是模拟硬件端口。Hyper-V不再应用传统的读写模拟硬件端口的要领进行硬件设备的虚拟化,而是应用了虚拟设备作为设备模拟。例如,在虚拟机中网卡,硬盘等设备的驱动都是由微软供给,假如没有这些驱动法度榜样,虚拟机则无法应用虚拟设备,就像是QEMU中的VIRTIO设备一样,必要加载特殊驱动,而不是应用和真实硬件一样的驱动。

下图表示了虚拟机若何经由过程宿主机造访收集:

此中虚拟机与物理机的数据交互如下图:

虚拟机与物理直接的数据交互经由过程环形内存的读写来完成。对环形内存的读写操作由VMBus来完成

下面我将经由过程这个例子来阐述虚拟机是若何与物理机进行交互的:

虚拟机用户经由过程 foo.exe 提议一个 TCP 哀求;

哀求通报到虚拟机的网卡驱动;

虚拟机网卡驱动会经由过程 VMBus 将哀求封装成一个数据包通报到环形内存中;

在虚拟机写满一个环形内存或将数据成功写入环形内存后;

虚拟机应用Hypercall指令看护宿主机,数据已经写完,并孕育发生一个VM-Exit事故陷入 Hyperisor 层履行代码;

这时 Hyperisor 层就会启程注册在 WIndows 内核中的中断例程(IDT);

Windows 内核接管到消息后会根据虚拟设备类型调用相对应的函数读取环形内存的数据,并将数据分发到相对应的虚拟设备驱动;

这样数据就由虚拟机成功的转移到物理机,相关的虚拟驱动会继承解析数据;

由物理机传入数据至虚拟机事理相同;

更细致的阐发可以参考文章。

0×02 测试

根据 Joe Bialek 和 Nicolas Joly 在大年夜会中所讲,对付 Hyper V 的进击主要在于对宿主机内核态的进击,大年夜部分环境是会造成宿主机的崩溃。

有关用户态的进击平日无法造成实质的效果,一样平常环境会直接被非常接收,破绽使用及其繁杂。

以下是宿主机内核态组件:

VMSwitch.sys:供给半虚拟化收集

StorVSP.sys:供给半虚拟化存储

VID.sys:虚拟化举措措施驱动

WinHVr.sys:内核到hypervisor的接口(hypercall)

VMBusR.sys:VMBUS,认真guest与host的通信

vPCI.sys:半虚拟化PCI

根据看雪ID: ifyou 的先容,在用户态中的 vmuidevices.dll 组件也异常轻易受到进击,这是一个认真图形显示的组件,因为图形显示的法度榜样编写及其繁杂,以是这里出问题的概率也会大年夜很多。

在 Blackhats 大年夜会中 Joe Bialek 者阐述了一个经由过程VMSwitch.sys组件实施逃逸的案例。这个时刻我们要具体的解说一下有关于虚拟机与宿主机的数据交互细节。 在道理中我们讲到,宿主机与虚拟机的数据交互经由过程VMBus节制,但数据并不直接由VMBus进行传输,而是缓存到两者之间的环形内存中,环形内存至少存在两个 一个哀求内存,一个应答内存。

下面是虚拟机与宿主机经由过程环形内存进行数据交互的历程:

虚拟机发送的数据经由过程VMBus传入哀求内存。

随后经由过程Hypercall的要领看护宿主机提取数据,孕育发生VM-EXIT事故陷入Hyperisor层 当宿主机收到消息后会触发中断,随后读取哀求内存的数据,分发给相关的虚拟驱动法度榜样处置惩罚。

数据处置惩罚完成后向虚拟机发送处置惩罚成功的消息,并将应答给虚拟机的数据,写入应答内存。 虚拟机读取应答内存的数据并回应一个消息奉告宿主机,应答数据有有效。

宿主机才会开释线程进入下一个数据包的处置惩罚。 当然,环形内存是会被瓜分成数个子区。环形内存的描述(GPADL)由虚拟机供给,环形内存中的子区大年夜小及其数量由宿主机自适应。

举个例子:一个应答环形内存的地址以及大年夜小由虚拟机应用GPADL看护宿主机,宿主时机根据GPADL;里供给的指针索引到应答环形内存的地址,然后根据GPADL中供给的内存大年夜小去调剂这一段环形内存中子区的大年夜小并天生适配这一段内存的子区分配表。

Blackhats 大年夜会中 Joe Bialek 使用的破绽就是针对付数据交互中,更新内存指针与更新和天生这一内存中的子区大年夜小及其数量,并非是原子操作(中心存在光阴差),提出了竞态进击。

[1] [2] [3]下一页

进击设想:

我们可以节制宿主机接管的数据;

我们传入的数据可以经由过程竟态完成越界;

越界之后的数据可以履行可控的进击。

作者经由过程RNDIS control message responses来节制写入的内容。这是虚拟机要发送的收集数据颠末虚拟机内核态中的虚拟收集组件构成的 RNDIS 协议数据。

第二点实际上是要求我们节制数据包的延迟,已达到,应答内存的指针已经更新到新的内存地址,但宿主机上依然保留着旧内存地址的子区分配表,这样就会存在,子区分配表中所描述的总内存大年夜小与新内存的大年夜小不匹配,这会给我们的越界操作供给越界内存。

首先虚拟机发送GPADl看护内存地址指针,宿主机收到看护后更新内存指针,指到新的内存地址,但依旧保留这旧的子区分配表:

然后宿主机根据GPADL中看护的此段内存的大年夜小分配子区大年夜小及其数量,天生新的子区分配表:

天生子区分配表后,履行更新动作,将适配与本来内存的子区分配表量更新到新的子区分配表:

如图所示,在更新内存指针之后,宿主机还没有更新子区分配表,子区内存的总大年夜小是和新内存不适配。这样就存在越界内存 ,给我们供给了寄放进击载荷的空间。

针对付 RNNIS 协议的数据,宿主机在处置惩罚完虚拟机发送的数据后会将应答给虚拟机的数据封装成 cmplt 数据包,宿主机处置惩罚完数据后发送处置惩罚成功的消息,并将 cmplt 包 写入应答内存,等待虚拟机的回应。假如虚拟机没有回应,则认真处置惩罚该数据的线程会不停处于等待状态,不会处置惩罚下一个数据。

当然,并不是每一个 cmplt 包都邑被虚拟机回应,比如畸形的 cmplt 数据包。

以是我们可以经由过程虚拟机通报给宿主机的 RNDIS 协议数据 使宿主机在处置惩罚数据后天生畸形的 cmplt 数据包。达到壅闭宿主机数据处置惩罚线程,造成延迟。 而后在N个畸形数据包后附加一个有效的并带有进击载荷的cmplt数据包,使其在宿主机更新到新的应答内存历程中,指针已经偏移但子区分配表未更新时,写入越界内存。

当然,最紧张的,是我们在成功越界写入之后,所造成的效果是否是我们可控的,否则将无法造成有效进击。

Jordan Rabet 在大年夜会中做出进一步阐发。MDL(注解虚拟内存缓冲区的物理页面结构)映射到物理内存,而这些MDL会被映射到SystemPTE区域。这个区域里平日寄放的是其他的MDL以及内核栈。

毫无疑问,我们将内核栈作为我们进击的目标,Win的内核栈一共有7页,6个页面作为栈空间,而着末一个页面在底部作为guard page。

那么问题来了,我们如何将内核栈放到我们可以操控的越界空间中,并且我们如何开启一个线程去履行这一步操作。

先来看一下 SystemPTE 分配内存的流程:

它基于一个可以进行扩展的Bitmap 分配以及检索内存空间;

每个位代表一个页面的状态 位0表示余暇页,1表示已分配应用 内存分配基元 进行内存分配;

从内存分配基元 的位置开始扫描 Bitmap;

假如必要改变某一个内存空间的状态,则包装此空间并改变此空间的位;

内存分配基元 会放在成功分配的空间的尾部;

假如找不到余暇内存,则展开Bitmap 搜索新的可用内存。

下面是它分配页面的一个示例:

由此发明,我们必要一个可控的内存分配基元赞助我们在 SystemPTE 区域中结构内存。 但着实,回首环形内存的特点,虚拟机可以随意率性构造大年夜小和数量不限的MDL(他们存在上限,然则异常高,以至于我们不用斟酌大年夜小的问题)。

因为宿主机应答给虚拟机的数据(NVSP_MSG1_TYPE_REVOKE_RECY_BUF和NVSP_MSG1_TYPE_REVOKE_SEND_BUF)是可以被撤回的,当然这是一个bug,当多个撤销消息被处置惩罚时,除了着末一个事情线程,其它的事情线程都邑被永远逝世锁,但我们依然有措施经由过程这样的机制去撤回内存的应用。

是以我们就有了内存分配和开释的基元来赞助我们操控这个区域。但我们还必要天生新的内核栈,以便我们越界后对其进行操控。以是我们还必要客栈分配基元。

vmswitch依附系统事情线程履行异步义务,这些线程被放在内核掩护的线程池中,于是我们可以经由过程向里边添加线程的要领获取这一内核栈的权限。只有所有的进程都在忙的时刻,我们才可以向里边加入新的线程。以是我们要做到:

上一页[1] [2] [3]下一页

多次快速的触发异步义务。假如孕育发生的义务足够快,那么就会有新的线程加入。有几类vmswitch消息依附于系统事情线程,例如我们应用的NVSP_MSG2_TYPE _SEND_NDIS_CONFIG。 破绽发掘者 在实验的历程中使用这样的措施创建了5个线程。

假如无法创建更多的线程,阐明线程池中已经有了足够多的线程。这个时刻我们就要经由过程上述的撤回bug,锁逝世其他线程,造成一个受限的线程栈喷射。(在shellcode的前面加上大年夜量的slide code(滑板指令),组成一个注入代码段。然后向系统申请大年夜量内存,并且反复用注入代码段来添补。这样就使得进程的地址空间被大年夜量的注入代码所盘踞。)

这样我们便可以天生一个接近应答内存的内核栈:

内核的保护机制,能使任何堆缓冲区溢出到内存区域的末端。我们必要多次申请内存以最大年夜限度的打仗到 SystemPTE 的末端,如图中所示,实验历程中,可调换的应答数据与内核栈间隔已经很靠近了。

着末的着末我们必要绕过空间地址随机化防御Bypassing KASLR。

这里用到一个信息泄露的破绽,造成信息泄露破绽的布局体是nvsp_message,它在栈长进行分配,它只初始化了前8个字节,却返回了sizeof(nvsp_message)大年夜小,是以32字节未被初始化的栈内存会被发还给guest,造成信息泄露。经由过程泄露的信息,我们能够得到vmswitch的返回地址,进而构造rop链。

综上,全部使用历程就是:

应用infoleak定位vmswitch的返回地址;

应用信息建 ROP 链,但因为我们并不知道我们破坏的是那个堆,以是我们要构建一个ROP NOP-sled 这意味着我们要继续履行一串RET 指令;

经由过程 SystemPTE massaging天生可控内核;

应用竞争前提覆盖宿主机原 内核线程客栈与ROP链;

在宿主机上履行ROP。

防御手段:

上述破绽只呈现在Windows Server 2012 R2 中 Win 10并没有这类破绽。

虚拟机治理法度榜样强制履行的代码完备性(HVCI);

进击者无法将随意率性代码注入主机内核;

内核模式节制流保护(KCFG);

进击者无法经由过程挟制函数指针来实现内核ROP;

这里作者采纳的防御手段是将内核栈迁移到零丁的区域,实现隔离。

后记

搭建 Windbg 双机调试时,收集双机调试掉败,依然是经由过程串口进行双机调试(延迟略高,调试了一天。。)

Vmware 14.0 可以加载Windows Server 12 虚拟机镜像(VM12 不支持),假如采纳虚拟机嵌套,内存制少分配8G

测试 Joe Bialek 在大年夜会上演示的逃逸破绽,必要多次调试,本人在测试中多次崩溃(操控SysPTE内存。。。不要泄气,你总能成功!

上一页[1] [2] [3]

赞(0) 打赏
分享到: 更多 (0)
免责申明:本站所有资料均来自于网络,版权归原创者所有!本站不提供任何保证,不保证真实性,并不承担任何法律责任

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

阿里云优惠网 更专业 更优惠

阿里云优惠券阿里云大礼包