Documentation Index
Fetch the complete documentation index at: https://docs.specterops.io/llms.txt
Use this file to discover all available pages before exploring further.
Artifacts Generated: Process Inject
Summary
Theassembly_inject function injects a .NET assembly loader into a remote process and executes a registered .NET assembly within that process context. This capability enables operators to execute .NET assemblies in the memory space of other processes, providing stealth and the security context benefits of the target process for post-exploitation activities. The command leverages Apollo’s configurable injection techniques and establishes inter-process communication through named pipes.
- Needs Admin: False (but injection into certain processes may require elevated privileges)
- Version: 3
- Author: @djhohnstein
Arguments
- pid (Number) - Process ID of the target process to inject into
- assembly_name (ChooseOne) - Name of the .NET assembly registered with
register_filecommand (e.g., Seatbelt.exe) - assembly_arguments (String, optional) - Command-line arguments to pass to the assembly during execution
Arguments (Positional or Popup)
Usage
Example 1: Basic Assembly Injection
Command:Example 2: Assembly Without Arguments
Command:Example 3: Injection Failure - Process Not Running
Command:Example 4: Assembly Not Registered
Command:Example 5: Injection Failure - Access Denied
Command:Detailed Summary
Theassembly_inject function implements a sophisticated approach to in-memory .NET assembly execution within remote processes, operating through a multi-stage workflow that combines process injection, inter-process communication, and assembly loading:
1. Parameter Validation and Preprocessing
The function begins with comprehensive validation of all input parameters:- Assembly Registration Verification: Checks that the specified assembly name exists in the agent’s file store using
_agent.GetFileManager().GetFileFromStore()which retrieves DPAPI-encrypted AES256 cached assemblies - Process Validation: Verifies the target process ID corresponds to a running process using
System.Diagnostics.Process.GetProcessById()with exception handling for non-existent PIDs - Parameter Completeness Check: Ensures all required parameters (PID, assembly name, pipe name, loader stub ID) are provided through the
AssemblyInjectParametersstructure - Assembly Arguments Processing: Handles optional assembly arguments, defaulting to empty string if not provided
2. Injection Preparation and Stub Generation
The Python command handler prepares the necessary injection components:- ExecuteAssembly.exe Compilation: If not already present, the handler compiles the ExecuteAssembly.exe loader stub from source using
dotnet buildwith release configuration - Donut Shellcode Generation: Uses the Donut framework to convert ExecuteAssembly.exe into position-independent shellcode with the pipe name as a parameter:
donut.create(file=EXEECUTE_ASSEMBLY_PATH, params=taskData.args.get_arg("pipe_name")) - Named Pipe Generation: Creates a unique named pipe identifier using
uuid4()for secure inter-process communication - File Registration: Registers the generated shellcode with Mythic’s file management system for download by the agent
3. Process Injection Execution
The core injection operation uses Apollo’s injection management system:- CreateRemoteThread: Standard remote thread creation injection
- QueueUserAPC (Early Bird): Asynchronous Procedure Call injection into process threads
- Syscall_x64.NtCreateThreadEx: Direct syscall-based thread creation for enhanced evasion
- Technique Selection: Uses the currently configured injection technique via
get_injection_techniques/set_injection_technique - Shellcode Injection: Injects the Donut-generated shellcode containing the ExecuteAssembly loader
- Execution Trigger: Initiates execution of the injected payload within the target process
- Artifact Generation: Creates a process injection artifact using
Artifact.ProcessInject()for tracking and reporting
4. Inter-Process Communication Setup
The function establishes secure communication with the injected ExecuteAssembly loader:- Named Pipe Client Creation: Instantiates an
AsyncNamedPipeClientconnecting to “127.0.0.1” with the generated pipe name - Event Handler Registration: Configures handlers for:
ConnectionEstablished: Starts sender and message flushing threadsMessageReceived: Processes assembly output messagesDisconnect: Handles cleanup and completion signaling
- Connection Establishment: Attempts to connect to the named pipe with a 10-second timeout using
client.Connect(10000) - Threading Model: Uses separate threads for data transmission (
_sendAction) and message processing (_flushMessages)
5. Assembly Data Transmission
Once communication is established, the function transmits the assembly and arguments:- Data Serialization: Uses
JsonSerializerto convert command arguments into IPC format - Data Chunking: Breaks large assemblies into manageable chunks using
SerializeIPCMessage() - Asynchronous Transmission: Sends data chunks asynchronously through the named pipe using
BeginWrite() - Flow Control: Uses
AutoResetEventsignaling to coordinate data transmission between threads
6. Assembly Execution and Output Handling
The injected ExecuteAssembly loader executes the assembly and streams output back:- Assembly Loading: The injected loader receives assembly bytes and loads them into the target process memory using
Assembly.Load() - Execution Context: Executes the assembly within the security and privilege context of the target process
- Output Streaming: Captures all console output from the assembly and streams it back through the named pipe
- Real-time Processing: Processes and displays output in real-time as it’s received from the injected process
7. Message Processing and Output Management
The function implements thread-safe message handling:- Thread-Safe Collection: Uses
ThreadSafeList<string>to safely collect output from multiple threads - Periodic Flushing: The
_flushMessagesthread regularly flushes collected output to the task response queue with 1-second intervals - UTF-8 Decoding: Properly decodes received message data from UTF-8 encoding
- Message Aggregation: Combines multiple message fragments into coherent output blocks
8. Connection Lifecycle Management
The function carefully manages the entire communication lifecycle:- Connection Monitoring: Continuously monitors pipe connection status using
ps.IsConnectedand cancellation tokens - Graceful Shutdown: Handles disconnection events through
Client_Disconnectwhich closes pipes and sets completion events - Resource Disposal: Properly closes pipe connections and disposes of resources via
e.Pipe.Close() - Completion Signaling: Uses
AutoResetEventobjects (_complete) to coordinate completion between threads
9. Error Handling and Recovery
Comprehensive error handling covers multiple failure scenarios:- Process Validation Failures: Reports when target processes are not running or accessible with specific error messages
- Assembly Registration Issues: Identifies when assemblies are not registered with clear “have you registered it?” messaging
- Injection Failures: Handles and reports injection technique failures with process-specific error information
- Communication Failures: Manages named pipe connection failures with timeout handling
- Assembly Execution Errors: Captures and reports errors from assembly execution within the target process
10. Artifact Generation and Tracking
The function integrates with Mythic’s artifact tracking system:- Process Injection Artifacts: Automatically generates artifacts documenting the injection event using
Artifact.ProcessInject() - Technique Documentation: Records the specific injection technique used for the operation
- Timeline Integration: Ensures artifacts are properly timestamped and associated with the task
- Audit Trail: Provides complete audit trail of injection activities for post-operation analysis
MITRE ATT&CK Mapping
- T1055 - Process Injection
- T1055.002 - Portable Executable Injection
- T1055.004 - Asynchronous Procedure Call
Technical Deep Dive
ExecuteAssembly Loader Architecture
The ExecuteAssembly.exe loader implements a streamlined approach to in-process assembly execution:Donut Shellcode Generation
- Position Independence: Generates position-independent code that can execute from any memory location
- Parameter Embedding: Embeds the named pipe name directly into the shellcode for communication
- Self-Extraction: The shellcode automatically extracts and initializes the ExecuteAssembly loader
- Minimal Footprint: Optimized shellcode size for stealthy injection
Named Pipe Communication Protocol
The communication protocol implements a structured approach to data exchange:- Binary Data Support: Efficiently transfers large assembly binaries through
ByteData - Chunked Transmission: Breaks large data into manageable chunks via
SerializeIPCMessage() - Flow Control: Implements proper flow control using
AutoResetEventsignaling - Error Recovery: Handles partial transmission failures and connection issues
Injection Technique Integration
Apollo’s injection management system provides flexibility in technique selection:Supported Injection Techniques
Based on Apollo’s actual implementation, the following techniques are available:-
CreateRemoteThread
- Standard Windows API for remote thread creation
- Widely supported across Windows versions
- Good compatibility with most target processes
-
QueueUserAPC (Early Bird)
- Asynchronous Procedure Call injection
- Targets threads in alertable wait states
- Effective for evading some detection mechanisms
-
Syscall_x64.NtCreateThreadEx
- Direct syscall-based thread creation
- Enhanced evasion through syscall usage
- Bypasses some API hooking mechanisms
Dynamic Technique Selection
- Configuration-Based: Uses the technique set via
set_injection_technique - Consistent Application: All post-exploitation jobs use the same configured technique
- Runtime Switching: Techniques can be changed between operations
File Caching and Security
Apollo implements secure file caching for assemblies:DPAPI Encryption
- DPAPI Protection: Files are encrypted using Windows DPAPI (Data Protection API)
- AES256 Encryption: Additional AES256 encryption layer for enhanced security
- User-Specific: DPAPI ensures files are only accessible to the current user context
- Memory-Only: Assembly execution occurs entirely in memory without disk writes
Cache Management
- Persistent Storage: Assemblies remain cached across agent restarts
- Efficient Retrieval: Fast retrieval through file manager interface
- Size Limitations: No size limitations on cached assemblies
- Cleanup: Cached files are properly cleaned up during agent termination
Threading and Concurrency
The implementation uses sophisticated threading for optimal performance:Asynchronous Operations
- Sender Thread: Dedicated thread for data transmission (
_sendAction) - Receiver Thread: Automatic message processing through event handlers
- Flush Thread: Periodic output flushing (
_flushMessages) - Non-Blocking I/O: All pipe operations use asynchronous patterns
Synchronization Mechanisms
- AutoResetEvent: Coordinates thread communication and completion
- ConcurrentQueue: Thread-safe queuing for message transmission
- ThreadSafeList: Secure collection of assembly output messages
- Cancellation Tokens: Proper cancellation support for long-running operations
APIs Used and Their Purposes
| API | Purpose | DLL | Documentation |
|---|---|---|---|
System.Diagnostics.Process.GetProcessById | Validates target process existence | System.dll | Process.GetProcessById |
IAgent.GetFileManager().GetFileFromStore() | Retrieves DPAPI-encrypted cached assemblies | Apollo Agent | Internal Apollo API |
IAgent.GetInjectionManager().CreateInstance() | Creates injection instance using current technique | Apollo Agent | Internal Apollo API |
AsyncNamedPipeClient.Connect() | Establishes named pipe communication | Apollo Agent | Internal Apollo IPC API |
Assembly.Load() | Loads .NET assembly from byte array | mscorlib.dll | Assembly.Load |
Encoding.UTF8.GetString() | Decodes UTF-8 byte data to strings | mscorlib.dll | Encoding.GetString |
AutoResetEvent.WaitOne() | Thread synchronization and signaling | mscorlib.dll | AutoResetEvent.WaitOne |
ConcurrentQueue<T>.TryDequeue() | Thread-safe queue operations | System.Collections.Concurrent.dll | ConcurrentQueue |
PipeStream.BeginWrite() | Asynchronous named pipe write operations | System.Core.dll | PipeStream.BeginWrite |
Security Considerations
Process Selection Strategy
- Target Process Choice: Select processes with appropriate privileges and stability (e.g., explorer.exe, svchost.exe)
- Process Integrity: Avoid injecting into critical system processes that may cause system instability
- User Context: Consider the security context of the target process for operation success
- Detection Avoidance: Choose processes that are less likely to be monitored by security tools
Assembly Security
- DPAPI Protection: Assemblies are protected using DPAPI encryption while cached
- Memory-Only Execution: Assembly execution occurs entirely in memory without disk writes
- Dependency Management: Verify all assembly dependencies are available in the target process
- Version Compatibility: Ensure assembly .NET Framework version compatibility with target process
Communication Security
- Pipe Name Randomization: Named pipes use UUID4 for cryptographically random names
- Local Communication: Named pipes are bound to localhost (127.0.0.1) only
- No Authentication: Named pipes do not implement additional authentication mechanisms
- Data Integrity: No additional encryption is applied to pipe communications
Injection Technique Security
- Technique Diversity: Multiple injection techniques available to evade detection
- Syscall Evasion: Syscall_x64.NtCreateThreadEx provides enhanced evasion capabilities
- API Hooking Bypass: Direct syscalls can bypass some API monitoring solutions
- Process Compatibility: Different techniques have varying compatibility with target processes
Audit Trail Considerations
Process injection activities may generate various audit events:- Event 4688: Process creation events for spawned processes
- Event 4656: Object access events for process handles
- Sysmon Events: Modern detection solutions may generate additional events for injection activities
- ETW Tracing: Enhanced logging may capture injection-related activities
Limitations
- Assembly Dependencies: Assemblies with external dependencies may fail to load in the target process
- Architecture Compatibility: x86/x64 architecture mismatches between agent and target process will cause failures
- Process Permissions: Insufficient privileges may prevent injection into certain processes (e.g., SYSTEM processes)
- Injection Technique Compatibility: Not all injection techniques work reliably with all process types
- Assembly Registration: Assemblies must be pre-registered using
register_filecommand before use - Named Pipe Limits: Windows has limits on concurrent named pipe connections
- Memory Constraints: Extremely large assemblies may cause memory pressure in target processes
- Framework Limitations: Target processes must have compatible .NET Framework versions loaded
Troubleshooting
Common Issues and Solutions
| Issue | Possible Causes | Solutions |
|---|---|---|
| ”Process not running” | Invalid PID, process terminated | Verify PID with ps command, check process status |
| ”Assembly not loaded” | Assembly not registered | Use register_file to register assembly first |
| ”Failed to inject” | Insufficient privileges, incompatible process | Try different target process, run getprivs, check process architecture |
| ”Named pipe connection failed” | Injection successful but communication failed | Verify injection technique compatibility, check process stability |
| ”Assembly execution failed” | Missing dependencies, version mismatch | Verify assembly dependencies and .NET Framework compatibility |
| ”Operation timed out” | Injection or communication timeout | Check target process health, try different injection technique |
Debugging Steps
- Verify Process Status: Use
pscommand to confirm target process is running and note its architecture - Check Assembly Registration: Use
register_fileto ensure assembly is properly cached - Test Injection Technique: Use
get_injection_techniquesto verify current technique and try alternatives withset_injection_technique - Monitor System Resources: Check memory usage and process stability during operation
- Review Injection Compatibility: Test with different target processes to identify compatibility issues
- Validate Assembly: Test assembly execution with
inline_assemblyfirst to verify it works correctly
Injection Technique Troubleshooting
- CreateRemoteThread: Most compatible but easily detected
- QueueUserAPC: Requires target process threads in alertable wait states
- Syscall_x64.NtCreateThreadEx: Best evasion but may have compatibility issues with some processes