Escaping VMware Workstation through COM1
Kostya Kortchinsky - Google Security Team
These bugs are subject to a 90 day disclosure deadline[1]. If 90 days elapse without a broadly available patch, then the bug report will be made available to the public.
VMware Workstation offers printer “virtualization”, allowing a Guest OS to access and print documents on printers available to the Host OS. On VMware Workstation 11.1, the virtual printer device is added by default to new VMs, and on recent Windows Hosts, the Microsoft XPS Document Writer is available as a default printer. Even if the VMware Tools are not installed in the Guest, the COM1 port can be used to talk to the Host printing Proxy.
vprintproxy.exe is launched on the Host by vmware-vmx.exe as whichever user started VMware. vmware-vmx.exe and vprintproxy.exe communicate through named pipes. When writing to COM1 in the Guest, the packets will eventually end up in vprintproxy.exe for processing.
I won’t go over the subtleties of the protocol, but basically the printer virtualization layer is a glorified file copy operation of EMFSPOOL[2] files from the Guest to the Host. The EMFSPOOL and contained EMF[3] files are processed on the Host by vprintproxy.exe, and can be previewed on the Host thanks to TPView.dll. By supplying specially crafted EMFSPOOL and EMF files to COM1, one can trigger a variety of bugs in the vprintproxy.exe process, and achieve code execution on the Host.
The rest of this document assumes a Windows 8.1 amd64 Host, a Windows 7 x86 Guest running under VMware Workstation 11.1, with all patches installed. Other platforms have not been investigated.
A fully working exploit is provided for this particular environment.
The function CTPViewDoc::WriteEMF in TPView.dll pre-processes an EMF and rewrites it, replacing a couple of custom EMR record types. In the case of an EMR of type 0x8000 and 0x8002, the program will allocate memory based on the size specified for the record, then copy the 8 bytes of the record, subtract 8 to the size and read from the file into the dynamically allocated buffer that amount of bytes. For an EMR record size strictly lower than 8, the subtraction will underflow and result in a heap overflow.
…
…
This snippet of code doesn't ensure that the size of the record is at least 8. The integer underflow at (1) will make the program read a large number of bytes into a small buffer, resulting in a heap overflow.
A similarly vulnerable portion of code is handling custom EMR 0x8000.
In the case of custom EMR record 0x8002, TPView.dll blindly trusts sizes and offsets provided in the relevant structures and performs unsafe memcpy() operations.
Here, both the contents of esi and ebx are under user’s control, and correspond to the contents of a custom 0x8002 EMR structure. The size of the memory allocated for ebx is not even checked to be at least 0x50 bytes. This results in some heap overflow conditions, as well a relative memory overwrite.
The custom EMR 0x8000 appears to hold a structure describing a JPEG2000 compressed image. There are several integer overflows when computing the size of a dynamically allocated chunk of memory, that can result in heap overflow conditions.
The program performs unsafe 32-bit arithmetic, leading to an invalid size check prior to a memcpy() operation, leading to a heap overflow. The size allocated for that memory check is itself prone to a wrap due to the previous arithmetic operations, as well as the following addition that also might wrap the 32-bit integer:
This vulnerability looks conspicuously like CVE-2012-0897[4], and it might very well be that the same JPEG2000 library was used in both cases but has been left unpatched in TPView.dll for the last couple of years. Anyway, when processing record 0xff5c (Quantization Default), a user can trigger an overflow of a stack based buffer in a function without a stack cookie - which leads to direct EIP control.
Here, the JPEG2000 parser will just read words as long as the size of the 0xff5c record permits it, while the destination buffer can only hold 0xc4 bytes at most.
The CEMF::EnhMetaFileProc function in TPView.dll is used as a callback to EnumEnhMetaFile[5], and applies some specific processing to several EMR types prior to “playing” them. The sanity of those records is poorly checked, leading to multiple out-of-bounds read or write operations.
Here, the length of the EMR_SMALLTEXTOUT[6] record is not checked to be at least 0x34 prior to operations being carried on fields of the structure.
Same issue here for an EMR_EXTTEXTOUTW[7] record.
When extracting a TrueType font from the EMFSPOOL file, TPView.dll will verify the checksum of the font prior to further processing. To do so, it will walk the tables, zero out the padding at the end of a table and checksum the table[8]. In doing so, it will trust the ‘offset’ field of the table record and add it to a pointer to the font buffer. While there is a check to make sure that we don’t go past the end of the font, nothing prevents us from referencing and zeroing memory prior to the font, as the 32-bit arithmetic will wrap.
The above checks can be bypassed with a “negative” offset, leading to the following memset() and checksum:
As a result, it is possible to zero 1 to 3 bytes (size of the padding) at an arbitrary location relative to the font buffer, as long as it’s located before.
Even when running on a 64-bit platform, vprintproxy.exe is only available as a 32-bit process. It is to be noted that several modules loaded within vprintproxy.exe do not support ASLR, namely:
Since all those DLLs share the same image base of 0x10000000, only iconv.dll (the 1st to be loaded) will be located at this address. The others’ base will be randomized as their original loading address is unavailable.
Also the JPEG2000 parsing is done within a try-catch that catches all exceptions. This would allow an attacker to bruteforce his/her way to successful exploitation as the vprintproxy.exe would stay alive even through access violations.
“Disconnect” the Virtual Printer, or remove it entirely in the VM settings, this will stop vprintproxy.exe from running.
1.0: initial version
1.1: added the arbitrary zero memory within the TrueType font checksum
1.2: added the integer underflows in the custom EMR processing
3/5/2015: initial report sent to security@vmware.com
3/6/2015: VMware Security Response Center acknowledges the receipt of the report
3/12/2015: updated report sent
3/17/2015: VSRC sends the expected timeframe for fixes to be released
3/17/2015: updated report sent
3/18/2015: additional bugs sent to VSRC
4/10/2015: VMware communicates expected date for joint disclosure (6/9)
4/21/2015: VMware assigns 5 CVEs to the issues (CVE-2015-2336 to 2340)
6/9/2015: VMware releases Workstation 11.1.1 for Windows and VMSA-2015-0004
The provided exploit achieves code execution in the vprintproxy.exe process running on the Host, triggering the JPEG2000 stack overflow by sending a crafted EMFSPOOL through COM1 in the Guest, which doesn’t require administrative privileges in the Guest.
Past the crafting of the EMFSPOOL and contained EMF and JPEG2000, the only difficulty was to create a ROP chain based on iconv.dll, as this DLL is fairly inconvenient for this purpose.
The exploit assumes iconv.dll version 1.9.0.1 and TPview.dll version 8.8.856.1, but since exceptions are caught by the JPEG2000 parser, additional targets can be supported through multiple tries.
from ctypes import * |
[2] [MS-EMFSPOOL]: Enhanced Metafile Spool Format
[3] [MS-EMF]: Enhanced Metafile Format