Inline-Execute-PE: Execute unmanaged Windows executables in CobaltStrike Beacons
Inline-Execute-PE is a suite of Beacon Object Files (BOF’s) and an accompanying Aggressor script for CobaltStrike that enables Operators to load unmanaged Windows executables into Beacon memory and execute them, retrieving the output and rendering it in the Beacon console.
This enables Operators to use many third-party tools (Mimikatz, Dsquery, Sysinternals tools, etc) without needing to drop them to disk, reformat them to position independent code using a tool like Donut, or create a new process to run them.
These executables are mapped into Beacon memory so that they can be run repeatedly without needing to send them over the network, allocate new memory, and create a new conhost.exe process each time.
Executables loaded into Beacons are accessible and able to be run by all CobaltStrike Clients connected to the CobaltStrike Team Server.
Inline-Execute-PE was designed around x64 Beacons and x64 Windows C or C++ executables compiled using Mingw or Visual Studio. This project does not support x86 executables or x64 executables written in a different language or compiled using a different compiler.
Inline-Execute-PE comprises 3 target-facing commands which run BOF’s, and 3 internal commands that manipulate the project data structure:
peload is the beginning of Inline-Execute-PE. This command is used to load a PE into Beacon memory. It performs the following major actions:
- Sends the specified PE over the network to Beacon
- Creates a structure in Beacon memory to hold various pointers and handles required by Inline-Execute-PE throughout it’s lifecycle
- Allocates memory in Beacon and writes PE to it with RW protection
- XOR encrypts PE in memory using a user-specified key
- Allocates another chunk of memory and copies the XOR encrypted PE to it. This is necessary in order to be able to “revert” the PE for subsequent executions
- Spawns a conhost.exe child process under Beacon in order to initialize stdin/stdout/stderr
- Redirects stdout and stderr to an anonymous pipe so that PE output may be captured
perun is the second step in Inline-Execute-PE. It performs the following major actions:
- Sends command line arguments over the network to Beacon
- XOR decrypts PE in memory
- Fixes the PE’s Import Address Table, hooking certain API’s related to command line arguments and exiting processes
- Changes PE memory protection to RWX
- Run’s PE in it’s own thread
- Captures output from PE and returns it to CobaltStrike
- Reverts PE memory protection to RW
- Overwrites the PE in memory with the XOR’d copy that was made during peload
peunload is called to remove the PE from Beacon memory when an Operator is done with it or wishes to load a different PE. It performs the following major actions:
- Closes handles and file pointers created during peload
- Terminates the conhost.exe process created during peload
- Zeroes out and then frees both copies of the PE in memory
- Tries to unload any DLL’s loaded by the PE into the Beacon process (optional)
petable is used to display information regarding all PE’s currently loaded into Beacons.
Each CobaltStrike Client has their own petable; Inline-Execute-PE goes to great lengths to ensure the synchronicity of its data between all connected CobaltStrike Clients so that PE’s may be used by all Operators. For more on this, see “Design Considerations and Commentary”.
peconfig is used to configure options pertaining to how Inline-Execute-PE functions. The two current options that may be altered are:
- Timeout. This dictates how long perun will wait for the PE to complete execution before terminating it. This exists as a safeguard in the event that incorrect arguments are given to a PE that causes it to never return/finish execution. This setting is 60 seconds by default but may be modified to accommodate longer-running PE’s.
- UnloadLibraries. This option controls whether peunload will try to free DLL’s from the Beacon process that were loaded by the PE. This is set to TRUE by default. Some PE’s cause issues when DLL’s are unloaded from the Beacon process and can cause Beacon to crash, in which case it is better to leave all DLL’s loaded by the PE in the Beacon process. This has been observed when using powershell.exe (perhaps due to it loading the .Net CLR into the Beacon process).
pebroadcast can be used to manually broadcast the contents of a Client’s petable to all other connected CobaltStrike Clients.
Every other CobaltStrike Client will update their petable with the data broadcasted. This shouldn’t ever really be necessary, but the feature exists just in case.
Copyright (C) 2023 Octoberfest7