VMware High-Bandwidth Backdoor ROM Overwrite Privilege Elevation

VMware High-Bandwidth Backdoor ROM Overwrite Privilege Elevation

Derek Soeder

Reported: December 5, 2011
Published: March 30, 2012

VMware, Inc.

The following VMware product versions are known to be affected:
VMware Server 1.0.10 and earlier
VMware Server 2.0.2 and earlier
VMware Workstation 7.0.0
VMware Workstation 7.1.1 and earlier
VMware ESXi 3.5.0 Update 5
VMware ESXi 4.0.0 Update 4 Build 504850 and earlier
VMware ESXi 4.1.0 Build 320137 (ESXi410-201011401-BG) and earlier
Other related versions not tested but assumed to be affected

The following guest operating systems are known to enable exploitation:
Windows NT 4.0
Windows 2000
Windows XP (32-bit)
Windows Server 2003 (32-bit)

The following VMware product versions are not affected:
VMware Workstation 7.1.2 and later
VMware ESXi 4.0.0 Update 4 with patch ESXi400-201203401-SG
VMware ESXi 4.1.0 Update 1 Build 348481 (ESXi410-201101201-SG) and later
VMware ESXi 5.0.0

The following guest operating systems do not appear to permit exploitation:
Windows XP (64-bit)
Windows Server 2003 (64-bit)
Windows Vista (32-bit and 64-bit)
Windows Server 2008 (32-bit and 64-bit)
Windows 7 (32-bit and 64-bit)
Windows Server 2008 R2


The vulnerability described in this document can be exploited by
unprivileged code running on certain guest operating systems in a
VMware virtual machine in order to execute arbitrary code with kernel

The VMware backdoor interface consists of a number of operations
issued via I/O instructions executed in the guest with a command
number in CX and data or "magic" values in a number of other
registers. Command 0x1E / 30 (BDOOR_CMD_MESSAGE) and its subcommands
(MESSAGE_TYPE_*) allow messages to be exchanged between the guest and
host. Since the regular backdoor would only allow for the exchange of
no more than one machine word of data per I/O instruction, a
"high-bandwidth" backdoor exists on port 0x5659 (BDOORHB_PORT) to
permit bulk transmission of data from and to the guest via the REP
OUTSB and REP INSB instructions respectively. If the direction flag
is clear, the host performs the transfer by memcpy'ing directly from
or to its mapping of guest memory, after performing any applicable
address translations and memory access checks.

One special case that the host fails to consider, however, is when a
REP INSB is targeting memory that would normally be emulated as
read-only. If the guest operating system allows an unprivileged user
to address a writable view of read-only memory, the user can exploit
this vulnerability to modify the ROM's contents whereas he otherwise
could not. To then parlay this ability into a successful attack
requires causing privileged code that trusts the ROM to act on the
altered contents in an exploitable way.

Only 32-bit editions of Windows prior to Vista allow an unprivileged
user to map a PAGE_READWRITE view of the BIOS ROM by launching a
Virtual DOS Machine (NTVDM.EXE). On 32-bit Windows Vista and Windows
Server 2008, NT!VdmpInitialize is hard-coded to map physical addresses
0xC0000 through 0xFFFFF at the corresponding virtual addresses as
PAGE_READONLY, while 32-bit Windows 7 allocates writable virtual
memory at 0xC0000 and copies in the contents of the BIOS ROM, and VDM
support does not exist at all in 64-bit editions of Windows.
(Presumably, ROM was originally mapped as writable so that 16-bit code
that tried for any reason to write to ROM could do so and have it
silently fail while still causing the expected side effects like
updating the flags. One wonders what prompted the change on Vista.)

Although this vulnerability allows modification of the in-guest BIOS
ROM, there seem to be few opportunities to get Windows to execute
modified BIOS code. One possible attack involves putting the modified
code in place and initiating or waiting for a soft reboot, after which
the planted code would execute and could mount a BootRoot-style attack
to alter the guest kernel as it loads. Another possibility is to
modify BIOS code and wait for some other user to run a 16-bit program
that changes the video mode or makes an exotic BIOS call unhandled by
NTVDM, but this is obviously flimsy. The third and best possibility,
discussed below, is to cause the kernel to change the video mode,
which will execute an INT 10h instruction from one of two Virtual-8086
mode environments, either of which can be escaped to infiltrate the

As the author mentioned in the advisory for CVE-2007-1206 (which
allowed modification of the Interrupt Vector Table rather than the
BIOS code it references), HAL.DLL will issue an INT 10h to prepare for
hibernation or a blue-screen, both of which could be considered "local
denial-of-service" conditions. However, the author has since found
that requesting full-screen text mode or switching to a VGA display
mode will also cause the INT 10h handler to be executed, although by
NTOSKRNL.EXE rather than HAL. Rough reverse call trees for both are
depicted below:

^ HAL!HalpBiosDisplayReset (via NT!HalPrivateDispatchTable)
. ^ BOOTVID!VidResetDisplay
. . ^ NT!VidResetDisplay
. . . ^ NT!InbvResetDisplay
. . . . ^ NT!KeBugCheck2
. . . . . ^ (blue-screen)
. . . . ^ HAL!InbvResetDisplay
. . . . . ^ HAL!HalHandleNMI
. . . . . . ^ NT!KiTrap02
. . . . . . . ^ (catastrophe)
. . . . ^ NT!PopSaveHiberContext (via DPC)
. . . . . ^ NT!PopInvokeSystemStateHandler
. . . . . . ^ NT!PopShutdownSystem
. . . . . . . ^ NT!PopGracefulShutdown
. . . . . . . . ^ NT!NtSetSystemPowerState
. . . . . . . . . ^ NT!NtShutdownSystem
. . . . . . ^ NT!PopSleepSystem
. . . . . . . ^ NT!NtSetSystemPowerState
. . . . . . . . ^ NT!NtShutdownSystem

^ VIDEOPRT!Ke386CallBios
. ^ VIDEOPRT!VideoPortInt10
. . ^ VGA!VgaSetMode
. . . ^ VGA!VgaStartIO
. . . . ^ VIDEOPRT!pVideoPortDispatch
. . . . . ^ NT!IofCallDriver
. . . . . . ^ WIN32K!GreDeviceIoControl
. . . . . . . ^ WIN32K!EngDeviceIoControl
. . . . . . . . ^ (...)
. . . . . . . . . ^ WIN32K!DrvChangeDisplaySettings
. . . . . . . . . . ^ WIN32K!xxxUserChangeDisplaySettings
. . . . . . . . . . . ^ WIN32K!NtUserChangeDisplaySettings
. . . . . . . . . . . . ^ USER32!NtUserChangeDisplaySettings
. . . . . . . . . . . . . ^ USER32!ChangeDisplaySettings*
. . . . . . . . ^ (...)
. . . . . . . . . ^ WIN32K!xxxbFullscreenSwitch
. . . . . . . . . . ^ WIN32K!xxxConsoleControl
. . . . . . . . . . . ^ WIN32K!NtUserConsoleControl
. . . . . . . . . . . . ^ WINSRV!NtUserConsoleControl
. . . . . . . . . . . . . ^ WINSRV!ChangeDispSettings
. . . . . . . . . . . . . . ^ WINSRV!HandleSysKeyEvent
. . . . . . . . . . . . . . . ^ WINSRV!ConsoleWindowProc
. . . . . . . . . . . . . . . . ^ (...)
. . . . . . . . . . . . . . . . . ^ NTDLL!CsrClientCallServer
. . . . . . . . . . . . . . . . . . ^ KERNEL32!SetConsoleDisplayMode
. . ^ VIDEOPRT!VpInt10CallBios
. . . ^ VGA!GetVideoMemoryBaseAddress
. . . . ^ VGA!VgaSetMode
. . . . . ^ (...)

As suggested above, unprivileged code can cause execution of the BIOS
INT 10h handler from either HAL or NTOSKRNL, the former through a
blue-screen or shutdown (such as hibernation), and the latter by
changing the video mode, which requires console access. Assuming that
malicious code has access to the console, and assuming that the video
driver does not prevent it (as the VMware Tools video driver in some
cases does), the malicious code could call ChangeDisplaySettings[Ex]
or SetConsoleDisplayMode to force a video mode change without needing
SeShutdownPrivilege or an independent blue-screen flaw. The following
paragraphs cover exploitation in both the HAL and NTOSKRNL cases,
starting from the assumption that an attacker has already modified the
BIOS's INT 10h handler code.

To infiltrate the kernel when invoked via HAL!HalpBiosCall, the
malicious INT 10h handler code can simply modify the pages of memory
containing HAL!HalpRealModeStart, the V86-mode stack, and
HAL!HalpRealModeEnd, which HAL!HalpBiosDisplayReset maps with write
permissions at virtual address 0x20000. Once execution returns to
HAL!HalpRealModeEnd following attempted execution of the C4h/C4h
sequence, the attacker will be executing code in the familiar Windows
kernel environment, albeit with some cleanup necessary. Malicious
code might detect the HAL case by observing if SS = 0x2000.

Infiltrating the kernel from the NT!Ke386CallBios environment, on the
other hand, is a little more indirect. NTOSKRNL issues an INT 10h
from a proper VDM with no interesting kernel code targets, but the VDM
TIB is accessible to V86-mode code (at address 0x12000). The
malicious INT 10h handler can modify the kernel stack pointer stored
in 'CONTEXT.Esi', just as described in Tavis Ormandy's CVE-2010-0232
advisory ("Microsoft Windows NT #GP Trap Handler Allows Users to
Switch Kernel Stack"), in order to hijack execution after the cleanup
code at NT!Ki386BiosCallReturnAddress completes. Malicious code might
detect the NTOSKRNL case by checking for SS = 0x1000.

Of course, none of this matters without the ability to meaningfully
modify BIOS code. Malicious code in the guest can only modify ROM
through the high-bandwidth backdoor REP INSB instruction, meaning it
can only overwrite ROM with bytes it can read from the host. Although
VMware Server 1.0 permits the guest to read host stack memory beyond
the end of any host-to-guest message, which allows reading of (and
therefore overwriting with) arbitrary bytes by first "seeding" the
buffer with a long REP OUTSB, a more version-independent approach is
to first use the "info-set" command to store an arbitrary low-byte
string in the VMDb "guestinfo" database, and then use "info-get" to
read the string from the host and overwrite the desired portion of
guest ROM.

The author's proof-of-concept exploit uses this technique to implement
a six-stage approach, comprising: (1) the replacement INT 10h handler,
a tiny, low-byte arithmetic / PUSH / Jcc sequence that computes the
offset of the next stage, pushes it, and branches to a nearby RET,
RETF, or IRET; (2) a larger, low-byte sequence stored over the 8x8
graphics font table (hopefully in video BIOS ROM pointed to by the INT
1Fh vector) that computes the bytes of the next stage, pushes them
onto the stack, and branches to a nearby RETF or IRET; (3) a small,
base-64-like decoder that decodes and executes the next stage, which
was also stored in the font table; (4) a loader that reads the
subsequent stages into RAM from the "guestinfo" database via the
VMware backdoor interface, decodes them, and executes the next stage;
(5) the main V86-mode payload, which prepares the next stage to
execute in ring 0 using the appropriate, aforementioned HAL or
NTOSKRNL infiltration technique; and (6) the main kernel payload,
which creates an interrupt gate for convenient kernel access and
cleans up the environment so that execution can resume without
crashing. The Win32 portion of the exploit can then use the interrupt
gate as needed.

With ring-0 privileges, the payload can restore the original contents
of BIOS ROM (assuming it preserved them) by making ROM writable via
PCI configuration space. In the eight bytes of PCI configuration
space starting at address 0x80000058, bit 0 and bit 4 each indicate
whether or not a segment of BIOS ROM is mapped, and bits 1 and 5
determine whether or not those segments are writable. Setting the
writable bits for all mapped segments, then, allows the ROM to be
directly overwritten with arbitrary bytes, as opposed to being
overwritten indirectly and only with low bytes through re-exploitation
of the vulnerability.

Another ramification of exploitation requiring rectification is the
unavoidable change in video mode. Before it invokes the INT 10h
handler, the kernel has already changed the display mode and
consequently blacked out the screen, so programming the malicious
handler to return without executing the original handler doesn't help
and could actually make it more difficult to properly restore the
display. One easy means of recovering from the mode change is to
inject code into session 0's WINLOGON.EXE process that enumerates
desktops and calls "ChangeDisplaySettings(NULL, CDS_RESET)" while
attached to each, although some amount of display flickering is
nevertheless inevitable.


* Disable NTVDM in the guest operating system

Disabling Virtual DOS Machine (NTVDM) support in the guest should deny
an unprivileged user the ability to obtain a writable mapping of ROM
on affected versions of Windows, thereby preventing exploitation of
the vulnerability. To disable NTVDM, follow the guidance presented in
one of the following Microsoft Knowledge Base Articles:


Or, manually set the "VDMDisallowed" registry value, which is
mentioned on the following page: (Note that this registry value is
not recognized by all versions of Windows.)


Be aware that disabling NTVDM will break 32-bit applications that rely
on DOS functionality, in addition to 16-bit applications.

* Run untrusted programs in a Remote Desktop session, and do not allow
the guest to power down or restart

The most likely exploitation scenarios require that the attack code be
able to trigger a kernel BIOS call, which is most easily accomplished
by changing the guest's video mode. Running suspect code in a Remote
Desktop session--as opposed to a console session--prevents the code
from changing the video mode, thereby reducing the likelihood of
successful elevation to kernel privileges. (Of course, make sure that
dangerous Remote Desktop features, such as local drive sharing, are
disabled when running untrusted code in this way.)

Another feasible exploitation scenario involves overwriting the BIOS
and then causing a shutdown, a restart, or hibernation. Run untrusted
code in the guest as an unprivileged user without shutdown privileges,
and force the virtual machine to power down afterwards; do not allow
the guest to gracefully power down or restart, as that might give
modified code an opportunity to execute.

Because this workaround does not prevent modification of BIOS ROM,
malicious code could still attempt to exploit the vulnerability by
causing a blue-screen or planting code for other users' VDMs to

* Disable the "info-get" and "info-set" commands

Exploitation depends on the attacker being able to overwrite ROM with
the contents of backdoor command responses, which the "info-set" and
"info-get" commands facilitate by allowing the attacker to store and
retrieve arbitrary data. These commands can be disabled in a specific
guest by adding the following lines to the virtual machine's .vmx
configuration file:

isolation.tools.getInfo.disable = "TRUE"
isolation.tools.setInfo.disable = "TRUE"

Note that the second line also disables the "SetGuestInfo" command.
It is not known if disabling these commands disrupts any guest
monitoring or other VMware Tools functionality.

* Restrict access to the VMware backdoor interface

Adding the following line to the virtual machine's .vmx configuration
file will prevent unprivileged code (code with CPL > IOPL) from
accessing the VMware backdoor interface, rendering the vulnerability
unexploitable for the sake of privilege elevation:

monitor_control.restrict_backdoor = "TRUE"

With this setting in place, an unprivileged attempt to execute a
VMware backdoor port I/O instruction will result in a privileged
instruction exception. Note that this setting crashes the user-mode
portion of VMware Tools, and thus disrupts certain features such as
guest-host copy-and-paste and drag-and-drop.

This document discloses a guest privilege elevation vulnerability
arising from fairly arcane behavior of VMware's backdoor interface,
and makes a case for its exploitability by presenting at a high level
the steps performed by the author's own functioning proof of concept.

It is not known if other machine virtualization software is
susceptible to similar issues regarding incomplete emulation of
read-only memory.