Use-After-Silence: Exploiting a quietly patched UAF in VMwareJune 27, 2017 | Abdul-Aziz Hariri
Springtime around the Zero Day Initiative (ZDI) means ramping up for the Pwn2Own (P2O) competition held each year at the CanSecWest conference. To say the least, it’s a busy time to be a ZDI researcher as we build targets, answer contestant questions, and review program submissions. This year was no different. In 2016, we introduced the VMware escape category in P2O but did not have any entries. We were expecting some for 2017, so it did not surprise us when we received a VMware vulnerability through the program a week before the contest.
I was very curious about this vulnerability for various reasons. First, I thought it was a defensive submission of some sort, one meant to possibly create a duplicate at P2O, thus preventing another competitor from getting a full P2O win. This has happened in the past and adds a new level of strategy to the P2O contest. Second, and most importantly, it was a Use-After-Free (UAF) vulnerability affecting drag-and-drop (DnD) and was triggered by Remote Call Procedure requests, which is something I’ve never played with before.
This blog covers the vulnerability and the efforts put into exploiting it. It’s also the first in a series of blogs that will discuss various VMware topics, including exploitation, reversing, and fuzzing VMware targets. Going from a virtual client to executing code opens a new world of possibilities – and risks.
Note: This vulnerability existed on VMware Workstation 12.5.2 and earlier versions. It was subsequently patched with VMware Workstation version 12.5.3. All the analysis shown here was done on VMware Workstation 12.5.1.
Before I explain the details of the bugs involved, here’s a quick video showing the full exploit chain in action:
The nice thing about this vulnerability was how simple it was to trigger. Sending the following RPCI requests triggered the vulnerability:
dnd.setGuestFileRoot AAAAA //Technically any DnD function would work.
With pageheap fully enabled on vmware-vmx.exe, WinDbg would break with the following exception:
Reviewing the output from !heap (pronounced bang-heap) gave me more information about the address in @RCX. First, I learned that it was indeed a Use-After-Free, and second, I knew exactly where the free happened:
The next step was to determine the size of that object. By breaking right before the free happened and running !heap on @RCX, this gets me the information I was looking for:
The disassembly above showed that the freed object was of size 0xb8 . By examining the instructions around the crash, I noticed that the dangling pointer was kept in an object of size 0x38 , which was allocated initially when the VM starts:
Exploiting the bug
While examining the disassembly at crash time, it was obvious that I needed some kind of information leak to exploit this vulnerability. To speed up this process, I used one of Tencent Security's Pwn2Own vulnerabilities that leaked the address of vmware-vmx.exe. This particular info leak will be discussed in detail in the future, but it does provide the needed info leak to make this exploit successful.
Usually, when I try to exploit vulnerabilities in a target, I ask myself these questions:
- What type of requests can I send?
- What do I control?
- How can I control the crash?
- How can I gain better exploitation primitives?
At this point, I could send RPCI requests, which are technically sent through the Backdoor interface along with other Backdoor requests. Yes, the official name VMware gave this interface is Backdoor.
So, how could I control the contents of the freed object? I’m used to UAF’s in the browser world, but exploiting and controlling this one was something new to me. I started looking at the RPC functions that I can call from the Guest with normal user privileges, and I stumbled across tools.capability.guest_temp_directory . I thought it would be easy to send a string of a certain size to overwrite the freed block. The result was promising:
Technically, we can control this vulnerability by sending an arbitrary RPC request, though not necessarily tools.capability.guest_temp_directory . This solves the biggest problem.
The next question was whether or not I could put a ROP chain and payload in a deterministic place. Again, I started looking at the RPC functions that I could call from the Guest. There were a few interesting functions to choose from. The one that stood out was unity.window.contents.start . Taking a closer look at the assembly, I noticed that a reference to the contents is kept in a global variable:
In other words, if I sent a unity.window.contents.start request, I’d know exactly where this request was stored: vmware_vmx+0xb870f8.
So, I triggered the crash again with the following RPC calls:
As you can see, @RDI points to the request that triggered the bug.
What did the plan look like at this point?
- Send a unity.window.contents.start request with a ROP chain that sets RSP to RDI.
- Trigger the free.
- Overwrite the freed object with another one. The freed object should contain the address of vmware_vmx+0xb870f8.
- Trigger the re-use using a request that contains the ROP chain to gain RCE.
Visually, it’s pretty simple:
The resulting code execution leaves the virtual client behind to instead run at the hypervisor layer.
When we introduced the VMware category at Pwn2Own 2016, we didn’t really expect to get any entries. We rarely see entries in new categories due to the time it takes researchers to find bugs and craft the needed exploits. However, we were hopeful that we would see some appear in 2017, and sure enough, two different teams successfully elevated from virtual client to executing code in the hypervisor. I’ll be detailing those exploits and techniques in the future. Until then, don’t let Use-After-Free vulnerabilities in VMware scare you. They’re fun to exploit ☺. Every RPCI function has its own story with its own exploit primitive.