Breaking Turtles All the Way Down An Exploit Chain to Break Out of VMware ESXi Hanqing Zhao, Yanyu Zhang , Kun Yang, Taesoo Kim Chaitin Security Research Lab Georgia Institute of Technology Tsinghua University 1
What is ESXi? ● Bare-metal hypervisor ● Widely used in private cloud 2
What is VM Escape? ... Guest OS Guest OS ... Guest OS 0 1 N exploitation VMM Excute arbitrary codes network connection on the host Host OS 3
Attack I/O devices (Pwn2Own 2017) Graphic (TianfuCup Ethernet 2018) USB (Pwn2Own 2019) SATA SCSI Several Workstation escape COM have been demonstrated 4
No ESXi Escape? What makes it so challenging? (Pwn2Own 2017) Graphic There has been no escape of (TianfuCup Ethernet 2018) ESXi !!! USB (Pwn2Own 2019) SATA SCSI COM 5
The customized architecture has not been studied RPC ● VMKernel RPC VMX handlers ○ VMM(hypervisor) guest OS virtual ○ User world API hardwares ○ VMFS ○ Drivers PIO/ Sandbox MMIO ● VMX Process #VM launch #VM-exit ○ Virtual hardwares #VM resume ○ RPC handlers USER API VM-Exit handlers VMM VMKernel Physical Hardware 6
Limited attack surfaces ● VM-Exit handlers RPC RPC host Ring3 VMX handlers ● Virtual Hardwares guest OS virtual ● RPC hardwares ● compact VMX Sandbox process #VM launch I/O #VM-exit #VM resume USER API VMM VM-Exit handlers host Ring0 7
Challenging mitigations and protections RPC RPC host Ring3 VMX ● ASLR handlers guest OS virtual ● NX/DEP hardwares ● sandboxing PIO/ Sandbox MMIO #VM launch #VM-exit #VM resume USER API VM-Exit handlers VMM host Ring0 8
Overview: VulnerabilitIes and Exploitation VMX Uninitialized Stack Usage (CVE-2018-6981) Sandbox Uninitialized Stack Read (CVE-2018-6982) 9
Overview: VulnerabilitIes and Exploitation VMX Uninitialized Stack Usage → Arbitrary Address Free Sandbox Uninitialized Stack Read → Information Leakage 10
Overview: VulnerabilitIes and Exploitation VMX Uninitialized Stack Usage → Arbitrary Address Free Sandbox Uninitialized Stack Read → Information Leakage Arbitrary Shellcode Execution in VMX process 11
Overview: VulnerabilitIes and Exploitation VMX VMX Uninitialized Stack Usage → Arbitrary Address Free Sandbox Sandbox Escape Uninitialized Stack Read → Information Leakage Arbitrary Shellcode Execution in VMX process 12
CVE-2018-6981: Uninitialized Stack Variable void destruct_page_struct(page_struct * a1 ) void __usercall vmxnet3_reg_cmd() { { ... if(page_count == 1) case 4: // VMXNET3_CMD_UPDATE_MAC_FILTERS free(a1->addr) * dma_memory_create(..., &page); // free the pointer on stack vmxnet3_cmd_update_mac_filters(v6, &page, a5); else * destruct_page_struct(&page); free(a1->page_array); } } break; page ... } char __fastcall dma_memory_create( unsigned addr , uint64 translate_size size , … , page_struct * page ) page_offset { // check the addr page_count * if ( addr > v5 || !size || size > v5 - addr + 1 ) addr 0x10 * return 0; set_page_struct(addr, size, a3, a4, page); page_array 0x18 return 1; } ... 13 a struct on stack for address translation
CVE-2018-6981: Uninitialized Stack Variable void destruct_page_struct(page_struct * a1 ) void __usercall vmxnet3_reg_cmd() { { ... if(page_count == 1) case 4: // VMXNET3_CMD_UPDATE_MAC_FILTERS free(a1->addr) * dma_memory_create(..., &page); // free the pointer on stack vmxnet3_cmd_update_mac_filters(v6, &page, a5); else * destruct_page_struct(&page); free(a1->page_array); } } break; page try to initialize the “page” structure on stack ... } char __fastcall dma_memory_create( unsigned addr , uint64 translate_size size , … , page_struct * page ) page_offset { // check the addr page_count * if ( addr > v5 || !size || size > v5 - addr + 1 ) addr 0x10 * return 0; set_page_struct(addr, size, a3, a4, page); page_array 0x18 return 1; } ... 14 a struct on stack for address translation
CVE-2018-6981: Uninitialized Stack Variable void destruct_page_struct(page_struct * a1 ) void __usercall vmxnet3_reg_cmd() { { ... if(page_count == 1) case 4: // VMXNET3_CMD_UPDATE_MAC_FILTERS free(a1->addr) * dma_memory_create(..., &page); // free the pointer on stack vmxnet3_cmd_update_mac_filters(v6, &page, a5); else * destruct_page_struct(&page); free(a1->page_array); } } break; check the size and addr page ... } char __fastcall dma_memory_create( unsigned addr , uint64 translate_size size , … , page_struct * page ) page_offset { // check the addr page_count * if ( addr > v5 || !size || size > v5 - addr + 1 ) addr 0x10 * return 0; set_page_struct(addr, size, a3, a4, page); page_array 0x18 return 1; } ... 15 a struct on stack for address translation
CVE-2018-6981: Uninitialized Stack Variable void destruct_page_struct(page_struct * a1 ) void __usercall vmxnet3_reg_cmd() { { ... if(page_count == 1) case 4: // VMXNET3_CMD_UPDATE_MAC_FILTERS free(a1->addr) * dma_memory_create(..., &page); // free the pointer on stack vmxnet3_cmd_update_mac_filters(v6, &page, a5); else * destruct_page_struct(&page); free(a1->page_array); } } break; illegal combination! skip initalization page ... } char __fastcall dma_memory_create( unsigned addr , uint64 translate_size size , … , page_struct * page ) page_offset { // check the addr page_count * if ( addr > v5 || !size || size > v5 - addr + 1 ) addr 0x10 * return 0; initialization set_page_struct(addr, size, a3, a4, page); page_array 0x18 return 1; } ... 16 a struct on stack for address translation
CVE-2018-6981: Uninitialized Stack Variable void destruct_page_struct(page_struct * a1 ) void __usercall vmxnet3_reg_cmd() { { ... if(page_count == 1) case 4: // VMXNET3_CMD_UPDATE_MAC_FILTERS free(a1->addr) * dma_memory_create(..., &page); // free the pointer on stack vmxnet3_cmd_update_mac_filters(v6, &page, a5); else * destruct_page_struct(&page); free(a1->page_array); } } break; page return and enter into the “destruct” function ... } char __fastcall dma_memory_create( unsigned addr , uint64 translate_size size , … , page_struct * page ) page_offset { // check the addr page_count * if ( addr > v5 || !size || size > v5 - addr + 1 ) addr 0x10 * return 0; initialization set_page_struct(addr, size, a3, a4, page); page_array 0x18 return 1; } ... 17 a struct on stack for address translation
Uninit Variable → Arbitrary Address Free void __usercall handle_port_io(__int64 a1 , __int64 a2 , __int64 a3 ) { ... v3 = *(a1 + 4); Abusing a function to spray stack! v4 = *(a1 + 13); read_or_write = *(a1 + 48); ... if ( *(a1 + 60) && (v10 = *(a1 + 52) << 12, v10 > 0x8000) ) v11 = malloc_heap_memory(v10); // copy the data into heap else translate_size v11 = &v35; void destruct_page_struct page_offset if ( read_or_write & 1 ) (page_struct * a1 ) page_count { { if ( *(v8 + 60) ) … { ... addr 0x10 // free the pointer on stack v15 = v11; free(a1->page_array); page_array 0x18 do } ... { ... memcpy(v15, v18, v17); // copy the data into stack 18 18 ...
CVE-2018-6982: Uninitialized Stack Variable bool __fastcall vmxnet3_cmd_get_coalesce(__int64 a1 , char a2 ){ struct buffer { uint64_t member0; At first, all stack variables are uninitlized uint64_t member1; }; size_t length; ... get_length_from_guest(..., &length); if(length != 16) return; ... * buffer.member0 = 0xFA000000003LL; // first 8-byte of src is initialized, but 16-byte is read // (length == 16) * write_back_to_guest(v19, &buffer, length, ...); return 1; } ... 19 }
CVE-2018-6982: Uninitialized Stack Variable bool __fastcall vmxnet3_cmd_get_coalesce(__int64 a1 , char a2 ){ struct buffer { uint64_t member0; uint64_t member1; }; size_t length; ... set length get_length_from_guest(..., &length); must be 16 if(length != 16) return; ... * buffer.member0 = 0xFA000000003LL; // first 8-byte of src is initialized, but 16-byte is read // (length == 16) * write_back_to_guest(v19, &buffer, length, ...); return 1; } ... 20 }
CVE-2018-6982: Uninitialized Stack Variable bool __fastcall vmxnet3_cmd_get_coalesce(__int64 a1 , char a2 ){ struct buffer { uint64_t member0; uint64_t member1; }; size_t length; ... get_length_from_guest(..., &length); if(length != 16) return; ... initialize the first 8-byte * buffer.member0 = 0xFA000000003LL; // first 8-byte of src is initialized, but 16-byte is read // (length == 16) * write_back_to_guest(v19, &buffer, length, ...); return 1; } ... 21 }
CVE-2018-6982: Uninitialized Stack Variable bool __fastcall vmxnet3_cmd_get_coalesce(__int64 a1 , char a2 ){ struct buffer { uint64_t member0; uint64_t member1; }; size_t length; ... get_length_from_guest(..., &length); if(length != 16) return; ... * buffer.member0 = 0xFA000000003LL; // first 8-byte of src is initialized, but 16-byte is read // (length == 16) member1(uninitilized) * write_back_to_guest(v19, &buffer, length, ...); will be write back to the return 1; } guest OS ... 22 }
Abusing a special RPC named “backdoor” ● A special hypercall ● Guest ○ Send messages through special I/O ports ● Host ○ Handle messages in VMX process 23
Recommend
More recommend