首页 >> 网络安全 >>漏洞分析 >> Hyper-V DoS 漏洞分析(CVE-2020-0890 )
详细内容

Hyper-V DoS 漏洞分析(CVE-2020-0890 )

时间:2020-09-17     作者:qwert【转载】   来自:安全客   阅读

简介


启用嵌套虚拟化选项的Guest操作系统会触发漏洞。已在Windows Server 2019 2020年8月更新,Windows 10 20H1 2020年8月更新和Windows 10 21H1 预览版上进行测试。Windows Server 2019的原始版本中也存在漏洞,没有补丁(2018年11月)。

Github上的PoC来源请点击文末“阅读原文”查看。




漏洞分析


在Windows Server 2016和Windows 10(2016年)中引入了Hyper-V嵌套虚拟化技术:https://docs.microsoft.com/en-us/virtualization/hyper-v-on- windows/userguide/nested -virtualization。它可用于在Guest操作系统(或某些功能,例如Windows Sandbox,Hyper-V VM内的MDAG)中启动管理程序。

从技术上讲,Hyper-V编码器的漏洞非常简单:它们没有过滤VP Assist Page的参数,该地址被写入Virtual VP Assist MSR(0x40000073)。早期msr寄存器0x40000073的名称为HV_X64_MSR_APIC_ASSIST_PAGE,现在(在TLFS 6.0中)为HV_X64_MSR_VP_ASSIST_PAGE。

HV_X64_MSR_VP_ASSIST_PAGE MSR 结构:

1.jpg

image.png

根据Hyper-V TLFS 6.0 VP Assist Page是重叠页。该页面的GPA地址被写入PFN字段:

typedef union _HV_VP_ASSIST_PAGE{    struct    {        //        // APIC assist for optimized EOI processing.        //
       HV_VIRTUAL_APIC_ASSIST ApicAssist;        UINT32 ReservedZ0;
       //        // VP-VTL control information        //
       HV_VP_VTL_CONTROL VtlControl;        HV_NESTED_ENLIGHTENMENTS_CONTROL NestedEnlightenmentsControl;        BOOLEAN EnlightenVmEntry;        UINT8 ReservedZ1[7];        HV_GPA CurrentNestedVmcs;        BOOLEAN SyntheticTimeUnhaltedTimerExpired;        UINT8 ReservedZ2[7];
       //        // VirtualizationFaultInformation must be 16 byte aligned.        //
       HV_VIRTUALIZATION_FAULT_INFORMATION VirtualizationFaultInformation;    };    UINT8 ReservedZBytePadding[HV_PAGE_SIZE];} HV_VP_ASSIST_PAGE, * PHV_VP_ASSIST_PAGE;

如果将zeroed page的PFN写入HV_X64_MSR_VP_ASSIST_PAGE msr,则会得到BSOD。

2.jpg

即使禁用了自动重启选项,Windows 10也会立即重启。如果将调试器连接到hvix64.exe (Windows Server 2019, 08.2020 updates,hvix64.exe,build10.0.17763.1397),则会得到:

hv+0x28af50:fffff982`efc8af50 cc              int     31: kd> gAccess violation - code c0000005 (!!! second chance !!!)hv+0x27747e:fffff982`efc7747e 384249          cmp     byte ptr [rdx+49h],al
2: kd> k # Child-SP          RetAddr               Call Site00 00000100`00803d08 fffff982`efc75e1b     hv+0x27747e01 00000100`00803d10 fffff982`efcfd74f     hv+0x275e1b02 00000100`00803d60 fffff982`efc82729     hv+0x2fd74f03 00000100`00803d90 fffff982`efc1691f     hv+0x28272904 00000100`00803df0 fffff982`efc1816b     hv+0x21691f05 00000100`00803e80 fffff982`efc8c571     hv+0x21816b06 00000100`00803fc0 00000000`00000000     hv+0x28c571
2: kd> rrax=ffffe802c560d000 rbx=ffffe802c5607050 rcx=ffffe802c5608d00rdx=0000000000000000 rsi=0000000000000000 rdi=ffffe802c5608000rip=fffff982efc7747e rsp=0000010000803d08 rbp=0000000000000014 r8=0000000000000000  r9=0000000000000000 r10=0000000000000000r11=0000000000000014 r12=0000000000000000 r13=ffffe802c56078d0r14=ffffe802c5608d00 r15=ffffe802c5607630iopl=0         nv up di pl zr na po nccs=0010  ss=0020  ds=0020  es=0020  fs=0020  gs=0020             efl=00010046hv+0x27747e:fffff982`efc7747e 384249          cmp     byte ptr [rdx+49h],

Windows Server 2019生成crash dunp:

3.jpg

4.jpg

Exploit源码仅适用于Intel CPU(技术上,exploit必须工作在AMD平台上,但没有这样CPU的PC),简述:

  • 在guest操作系统中激活VMX功能(在操作系统中必须执行以下命令支持:Set-VMProcessor -VMName -ExposeVirtualizationExtensions $true);

  • 分配和激活VMXON区域;

  • 分配VP Assist Page;

  • 获取VP Assist Page物理地址,写入HV_X64_MSR_VP_ASSIST_PAGE msr;

  • 执行vmclear,然后vmlaunch,并获取BSOD。

当执行 cmp byte ptr [rdx+49h],al指令时,rdx包含0,我们得到的访问指针为零。它是简单的NULL指针解引用,但rdx不受来宾OS地址空间的控制。

  • 5.jpg

  • hvix64.exe没有符号,因此过程具有与BSOD相关的名称,其level调用索引,最接近的level为1。该代码块已准备好在hypervisor上下文中执行vmlaunch 指令所需的所有代码。

  • 这个block什么时候执行?调用者block L2并不是很感兴趣。

  • 6.jpg

  • 但是下一个调用者level很重要。

  • 7.jpg

  • r8b 是如何控制的?

  • 9.jpg

  • 当VP Assist Page归零时:

  • WINDBG>dps poi(@rsi+198)+40ffffe802`c5608040  ffffe802`c561c000 – address of overlay VP Assist Page. Don’t changed after host OS reboot.ffffe802`c5608048  00000000`000f000fffffe802`c5608050  00000000`00000000ffffe802`c5608058  00000000`00000000ffffe802`c5608060  00000000`00000000
    WINDBG>dps ffffe802`c561c000ffffe802`c561c000  00000000`00000000ffffe802`c561c008  00000000`00000000ffffe802`c561c010  00000000`00000000ffffe802`c561c018  00000000`00000000ffffe802`c561c020  00000000`00000000ffffe802`c561c028  00000000`00000000 – rcx+28hffffe802`c561c030  00000000`00000000
  • 如果rcx + 28!= 0,则r8b = 1。

  • 我们可以在来宾操作系统中逐步调试PoC驱动程序,并查看变量的物理和虚拟地址,这些地址被传递到hypervisor:

  • 10.jpg

  • WINDBG> dps ffffe802`c561c000
  • ffffe802`c561c000 00000000`00000000ffffe802`c561c008 00000000`00000000ffffe802`c561c010 00000000`00000000ffffe802`c561c018 00000000`00000000ffffe802`c561c020 00000000`00000000ffffe802`c561c028   00000000`00000001 - pHvVpPage-> EnlightenVmEntryffffe802`c561c030   00000000`7ff23000 -pHvVpPage-> CurrentNestedVmcs ffffe802`c561c038 00000000`00000000ffffe802`c561c040 00000000`00000000ffffe802`c561c048 00000000`00000000ffffe802`c561c050 00000000`00000000ffffe802`c561c058 00000000`00000000
  • 下一步操作非常简单,pHvVpPage-> enlightenment vmentry == 0,我们得到BSOD。当执行vmlaunch时,Hypervisor根本不验证VP-Assist Page的内容。


  • 重叠页面初始化问题

  • BSOD不是一个问题。第二个问题,即使VP Assist Page在写入HV_X64_MSR_VP_ASSIST_PAGE msr之前也填充了实际值,因此参数不会传递给hypervisor。为什么它发生了什么?这是hypervisor重叠page的特性(或bug)。

  • 根据Hyper-V TLFS 6.0的5.2.1小节:

  • hypervisor定义了几个特殊页面,这些页面“重叠”了guest的GPA空间。hypercall代码页是重叠page(页面)的一个示例。重叠由guest物理地址进行寻址,但不包括在hypervisor内部维护的普通GPA映射中。从概念上讲,它们存在于一个单独的map中,该map覆盖了GPA的map。

  • 如果GPA空间内的一个page(页面)被覆盖,映射到GPA page页面的任何SPA 页面都会被有效地“obscured(掩盖)”,并且通常虚拟处理器无法通过处理器内存来访问它们。此外,访问重叠页面时,将不遵守在底层GPA页面上安装的访问权限。

  • 我们来做实验,在将缓冲区地址写入HV_X64_MSR_VP_ASSIST_PAGE msr之前,需要对其进行分配,用数字0x11填充缓冲区。

  • FillBuffer((PCHAR)pHvVpPage, PAGE_SIZE, 0x11);__writemsr(HV_X64_MSR_APIC_ASSIST_PAGE, guestPFN.AsUINT64);

  • 并在LiveCloudKd中查看它的内容,我们从WinDBG知道物理和虚拟地址,在源代码调试模式下启动:

  • 11.jpg

  • 附加到guest操作系统内核调试器:

  • 12.jpg

  • 同时将LiveCloudKd连接到相同的VM。首先,我们可以看到enlightenment结构。CurrentNestedVmcs和EnlightenVmEntry中的某些值:

  • 13.jpg

  • 并在VP Assist Page中看到相同的值:

  • 14.jpg

  • 写入HV_X64_MSR_VP_ASSIST_PAGE msr之后,我们可以看到hypervisor内部有一些历史垃圾(重叠页的地址是不变的,正如我们前面看到的那样,驱动程序重新启动,guest操作系统没有重新启动)。


  • WINDBG>dps ffffe802`c561c000 – inside hypervisorffffe802`c561c000  00000000`00000000ffffe802`c561c008  00000000`00000000ffffe802`c561c010  00000000`00000000ffffe802`c561c018  00000000`00000000ffffe802`c561c020  00000000`00000000ffffe802`c561c028  00000000`00000001ffffe802`c561c030  00000000`7ff23000ffffe802`c561c038  00000000`00000000ffffe802`c561c040  00000000`00000000ffffe802`c561c048  00000000`00000000ffffe802`c561c050  00000000`00000000ffffe802`c561c058  00000000`00000000
  • 返回到guest操作系统调试器。重叠页的0x11值被替换为上次HV_X64_MSR_VP_ASSIST_PAGE msr写入的值:

  • 16.jpg

  • 如果我们想写一些东西在重叠页后,

  • 如果我们想在其地址写入HV_X64_MSR_VP_ASSIST_PAGE msr 之后,在重叠页面中写入某些内容,则所有内容都是正确的。

    17.jpg



  • 总结


  • LiveCloudKd显示旧值,因为它会解析guest内存中的原始值,guest内存是使用MDL和hostPFN-to-GuestPFN页面映射在主机系统中进行映射的。当guest操作系统尝试从其分区读取/写入内存时,重叠页存储在hypervisor中,并被完全替换。有趣的是,guest页面中的page属性未更改。

  • 我检查了一下:hypervisor中的重叠页ffffe802`c561c00不断地改变CR3,但它的物理地址没有改变。可能还需要进一步的分析(但这不是与bug相关的研究)。


  • 发现了2个Bug:

  • 在vmlaunch 模拟期间对VP Assist Page值的处理不正确,会导致空指针引用错误和下一个BSOD。

  • 重叠page初始化的处理不正确,它只需切换到另一个内存缓冲区,即使没有清除保存在hypervisor中的旧值,或者从guest页面复制值,该地址在HV_X64_MSR_VP_ASSIST_page MSR中。

点击图片直接加群
更多
ots网络logo

OTS网络安全门户主要提供网络信息安全教程、文章、工具,让更多的小伙伴加入我们的社区一起学习。

技术支持: 建站ABC | 管理登录