2025-10-30 17:26:33 +01:00
2025-04-02 16:45:10 +02:00
2025-04-02 16:45:10 +02:00
2025-04-07 10:49:56 +00:00
2025-04-07 10:49:56 +00:00
2025-10-30 17:26:33 +01:00

Cazalla - Mythic C2 Agent

A Windows implant written in C for the Mythic C2 Framework

License Mythic Platform


📋 Table of Contents


🎯 Overview

Cazalla is a lightweight Windows implant written in C, designed to work seamlessly with the Mythic C2 Framework. It provides essential post-exploitation capabilities including file system manipulation, process enumeration, command execution, and SOCKS proxy functionality.

This project was inspired by the article How to build your own Mythic agent in C and has been extended with additional features and improvements.

Developed by: Kaseya OFSTeam


Features

  • Lightweight & Portable: Minimal dependencies, compiled with MinGW for Windows targets
  • Full Mythic Integration: Native support for Mythic's translator pattern and RPC system
  • Channel Encryption: Optional AES-256-CBC encryption with HMAC-SHA256 for secure communication
  • Process Browser Support: Integrated with Mythic's Process Browser for unified process management across multiple callbacks
  • SOCKS Proxy: Route traffic through the implant with built-in SOCKS5 support
  • Dynamic Sleep: Automatically adjusts beacon interval based on proxy activity
  • Custom Binary Protocol: Efficient binary communication with base64 encoding
  • Modular Commands: Easy to extend with new capabilities

📦 Installation

Prerequisites

  1. Mythic Server (v3.x or later) installed and running
  2. Clone this repository

Install Cazalla on Mythic

cd ~/Mythic
./mythic-cli install github https://github.com/<your-org>/Cazalla

Or install from local directory:

./mythic-cli install folder /path/to/Cazalla

Build the Agent

Cazalla can be built directly from the Mythic UI:

  1. Navigate to PayloadsCreate Payload
  2. Select Cazalla as the payload type
  3. Configure build parameters (C2 profile, sleep interval, etc.)
  4. Click Build

The agent will be cross-compiled for Windows using MinGW in a Docker container.


🔨 Customizing Cazalla

If you've forked Cazalla or made local changes and want to use your customized version, you need to configure Mythic to use local builds instead of remote images.

Making Changes Work

By default, Mythic may use pre-built remote images for faster deployment. However, if you've made local changes to the agent code, translator, or any Python files, you need to configure Mythic to use your local build context.

Configure Build Variables

After installing Cazalla, Mythic will add these variables to your ~/Mythic/.env file:

# Use local build context instead of remote image
CAZALLA_USE_BUILD_CONTEXT="true"

# Use direct mount instead of Docker volume (recommended for development)
CAZALLA_USE_VOLUME="false"

# Optional: Remote image URL (only used if USE_BUILD_CONTEXT is false)
CAZALLA_REMOTE_IMAGE="ghcr.io/your-org/cazalla:v1.0.0"

Variables Explanation

  • CAZALLA_USE_BUILD_CONTEXT:

    • Set to "true" to build from your local Dockerfile and include your local changes
    • Set to "false" (default) to use the pre-built remote image
    • Important: You must set this to "true" if you've modified any files!
  • CAZALLA_USE_VOLUME:

    • Set to "false" (default) to mount the local folder directly into the container
    • Set to "true" to use a Docker volume instead
    • Direct mount is better for development as changes are immediately visible
  • CAZALLA_REMOTE_IMAGE (optional):

    • Specifies a pre-built remote image URL
    • Only used when CAZALLA_USE_BUILD_CONTEXT="false"

Apply Changes

After modifying these variables, rebuild the container:

cd ~/Mythic
sudo ./mythic-cli build cazalla

Verifying Your Changes

  1. Make your code changes
  2. Set CAZALLA_USE_BUILD_CONTEXT="true" in ~/Mythic/.env
  3. Run sudo ./mythic-cli build cazalla
  4. Check logs: sudo docker logs cazalla_translator

If changes still don't appear:

  • Verify the Dockerfile copies your modified files (see line 39: COPY ./ /Mythic/cazalla/)
  • Check that file paths in the Dockerfile match your directory structure
  • Ensure you're editing files in the correct location (inside Payload_Type/cazalla/)

Example: Customizing Agent Code

# 1. Edit agent C code
vim Payload_Type/cazalla/cazalla/agent_code/cazalla/comandos.c

# 2. Ensure build context is enabled
echo 'CAZALLA_USE_BUILD_CONTEXT="true"' >> ~/Mythic/.env

# 3. Rebuild the container
cd ~/Mythic
sudo ./mythic-cli build cazalla

# 4. Rebuild a payload from the UI
# Your changes will now be included in the compiled agent

For more information, see the Mythic documentation on customizing public agents.


🛠️ Supported Commands

File System Operations

Command Description Example
ls List directory contents ls C:\Users
cd Change working directory cd C:\Windows\System32
pwd Print current directory pwd
cp Copy files cp source.txt dest.txt
mkdir Create directory mkdir C:\temp\new_folder
rm Delete file or directory rm C:\temp\file.txt
cat Read file contents (with automatic credential detection) cat C:\path\to\file.txt
download Download file from target to Mythic server download C:\path\to\file.txt
upload Upload file from Mythic server to target upload <file> C:\path\to\destination.txt

Execution & Control

Command Description Example
shell Execute shell command shell whoami
sleep Adjust beacon interval sleep {"seconds":30,"jitter":0}
exit Terminate the implant exit

System Information

Command Description Example
ps List running processes with Process Browser support ps
screenshot Capture full-screen screenshot (Mythic screenshot UI) screenshot
keylog_start Start keystroke logging keylog_start
keylog_stop Stop keystroke logging keylog_stop

Note: The ps command integrates with Mythic's Process Browser, allowing unified process management across multiple callbacks. Process lists are automatically synchronized and viewable from the Process Browser UI.

Network Operations

Command Description Example
socks Start/stop SOCKS proxy socks {"action":"start","port":7002}

🌐 SOCKS Proxy Support

Cazalla includes full SOCKS5 proxy support, allowing you to route traffic through the implant to reach internal network resources.

How It Works

  1. Mythic opens a SOCKS port on the server (default: 7002)
  2. Client connects to Mythic's SOCKS port (e.g., via proxychains)
  3. Mythic forwards SOCKS traffic to the agent with a unique server_id per connection
  4. Agent establishes the actual connection to the target host
  5. Bidirectional relay between client ↔ Mythic ↔ Agent ↔ Target

Commands

# Start SOCKS proxy on port 7002
socks {"action":"start","port":7002}

# Stop SOCKS proxy
socks {"action":"stop","port":7002}

Using the Proxy

After starting SOCKS, configure your tools to use the proxy:

With proxychains

# Edit /etc/proxychains.conf
[ProxyList]
socks5 <mythic_server_ip> 7002

# Use with any tool
proxychains curl https://internal-server.local
proxychains nmap -sT 192.168.1.0/24

With curl

curl --socks5 <mythic_server_ip>:7002 https://internal-server.local

With Firefox/Browser

Configure SOCKS proxy in browser settings:

  • SOCKS Host: <mythic_server_ip>
  • Port: 7002
  • SOCKS v5: Enabled

Mythic Configuration for SOCKS

To expose SOCKS ports externally (not just localhost), edit ~/Mythic/.env:

# Allow SOCKS ports to bind on 0.0.0.0 (all interfaces)
MYTHIC_SERVER_DYNAMIC_PORTS_BIND_LOCALHOST_ONLY="false"

# Define dynamic port range for SOCKS
MYTHIC_SERVER_DYNAMIC_PORTS="7000-7010"

# Optional: Use host networking for direct port exposure
MYTHIC_DOCKER_NETWORKING="host"

After editing, restart Mythic:

cd ~/Mythic
sudo ./mythic-cli restart

Verify the port is open:

sudo netstat -tlnp | grep 7002
# Should show: tcp  0.0.0.0:7002  0.0.0.0:*  LISTEN

Performance Considerations

  • Latency: Proxy speed depends on beacon interval. SOCKS mode automatically reduces sleep to 100ms for responsive connections.
  • Throughput: Suitable for interactive sessions and moderate data transfer. Not optimized for large file transfers.
  • Concurrent Connections: Supports multiple simultaneous SOCKS connections with independent server_id tracking.

Technical Details

Binary Protocol (0xF5 SOCKS Block)

Agent and translator communicate SOCKS data using a custom binary block:

[0xF5] [ext_len:4] [server_id:4] [exit:4] [b64_len:4] [base64_data:N]
  • 0xF5: SOCKS block marker
  • ext_len: Total extension length (remaining bytes)
  • server_id: Unique connection ID from Mythic
  • exit: 1 if connection should close, 0 otherwise
  • b64_len: Length of base64-encoded payload
  • base64_data: Base64-encoded raw bytes

Agent Implementation

  • File: socks_manager.c / socks_manager.h
  • Commands: 0x60 (START_SOCKS), 0x61 (STOP_SOCKS)
  • Thread Model: One reader thread per active connection
  • Socket Timeout: 60 seconds for idle connections

📡 Communication Protocol

Cazalla uses a custom binary protocol for efficient communication with Mythic.

Message Structure

Agent → Mythic

[UUID:36] [Action:1] [Body:N]
  • UUID: 36-byte agent identifier (ASCII)
  • Action: 1-byte action code (e.g., 0x80 for GET_TASKING, 0x81 for POST_RESPONSE)
  • Body: Variable-length payload

Mythic → Agent

[Action:1] [Body:N]
  • Action: 1-byte action code
  • Body: Variable-length payload (tasks, SOCKS data, etc.)

Action Codes

Code Direction Description
0x80 Agent → Mythic GET_TASKING (request new tasks)
0x81 Agent → Mythic POST_RESPONSE (send task output)
0xF5 Bidirectional SOCKS data block

Task Structure

Tasks sent to the agent include:

[TaskUUID:36] [CommandID:1] [Parameters:N]

Example command IDs:

  • 0x01: Shell command
  • 0x10: List directory
  • 0x60: Start SOCKS
  • 0x61: Stop SOCKS

Encoding

All binary data is base64-encoded for transport over HTTP/HTTPS.

Channel Encryption (Optional)

When encryption is enabled via the AESPSK build parameter:

  • Encryption Format: [IV:16 bytes][AES-256-CBC Ciphertext][HMAC-SHA256:32 bytes]
  • Agent Side: Encrypts all outgoing messages before base64 encoding
  • Translator Side: Decrypts all incoming messages after base64 decoding
  • Key Management: 256-bit AES key embedded at build time, unique per payload

This provides end-to-end encryption independent of the transport layer (HTTP/HTTPS).


⚙️ Configuration

Agent Build Parameters

When building from Mythic UI:

  • Callback Host: C2 server address
  • Callback Port: C2 server port (default: 443)
  • User Agent: HTTP User-Agent string
  • Sleep: Initial beacon interval in seconds (default: 10)
  • Jitter: Random delay percentage (0-100)
  • Encryption: Channel encryption settings (optional)
    • AESPSK: Enable AES-256-CBC encryption with HMAC-SHA256
    • When enabled, all agent ↔ Mythic communication is encrypted end-to-end
    • The encryption key is automatically generated by Mythic and embedded in the payload

Compile-Time Options

Edit Config.h before building:

#define INITIAL_SLEEP_MS 10000  // Default sleep: 10 seconds
#define SOCKS_ACTIVE_SLEEP_MS 100  // Sleep when SOCKS active: 100ms
#define SOCKS_TIMEOUT_SEC 60  // Socket read timeout

Channel Encryption

Cazalla supports optional AES-256-CBC encryption with HMAC-SHA256 for secure agent-to-Mythic communication. This provides an additional layer of security beyond HTTPS.

How It Works

  1. Mythic generates a random 256-bit AES key during payload creation
  2. Key is embedded in the agent binary at build time
  3. All messages are encrypted using AES-256-CBC mode with a random IV per message
  4. HMAC-SHA256 is calculated over the IV + ciphertext for integrity verification
  5. Format: [IV:16 bytes][Ciphertext:N bytes][HMAC:32 bytes]

Enabling Encryption

Encryption is enabled automatically when building with the AESPSK parameter in Mythic's UI:

  1. Navigate to PayloadsCreate Payload
  2. Select Cazalla as the payload type
  3. In the build parameters, configure AESPSK:
    • Set crypto_type to aes256_hmac
    • Mythic will automatically generate an enc_key
  4. Click Build

The encryption key is unique per payload and is shared between the agent and translator.

Encryption Status

You can verify encryption is enabled by checking the build output:

  • Look for: ✓ Encryption ENABLED: crypto_type=aes256_hmac, enc_key present
  • The translator logs will show encryption/decryption operations

Security Considerations

  • Key Management: Each payload has a unique encryption key managed by Mythic
  • IV Randomization: A new random IV is generated for each encrypted message
  • HMAC Verification: All encrypted messages include HMAC for integrity validation
  • Defense in Depth: Encryption works alongside HTTPS for layered security

Debug Mode

Enable verbose logging by defining DEBUG_SOCKS during compilation:

CFLAGS="-DDEBUG_SOCKS" make

This enables:

  • [MAINDBG]: Main loop and sleep adjustments
  • [CMDDBG]: Command parsing
  • [SOCKSDBG]: Connection lifecycle
  • [SLEEPDBG]: Dynamic sleep changes

📊 Process Browser Integration

Cazalla's ps command fully integrates with Mythic's Process Browser feature, providing unified process management across multiple callbacks on the same host.

Features

  • Unified Process Lists: All process listings from different callbacks on the same host are aggregated
  • Process Hierarchy: View process parent-child relationships when parent process IDs are available
  • Rich Process Data: Includes process name, PID, PPID, architecture, user account, and session ID
  • Automatic Synchronization: Process lists are automatically synchronized with Mythic's Process Browser UI

Process Browser UI

Access the Process Browser in Mythic:

  1. Navigate to a callback in the Mythic UI
  2. Click the PROCESSES tab (next to the CALLBACK tab)
  3. View all processes from all callbacks on that host
  4. Use the UI buttons for additional actions (inject, kill, etc.) if implemented

Implementation Details

The ps command implements the process_browser:list supported UI feature:

  • Process data is automatically converted to Mythic's Process Browser JSON format
  • The translator detects process list responses and formats them accordingly
  • Process information includes:
    • process_id: Process identifier (required)
    • name: Process name (required)
    • parent_process_id: Parent process ID (optional)
    • architecture: Process architecture (x64/x86)
    • user: User account running the process
    • session_id: Windows session ID

For more information, see the Mythic Process Browser documentation.


🎨 Artifacts Support

Cazalla automatically reports artifacts created during command execution, allowing Mythic to track artifacts like process creation, file writes, and other system modifications.

Features

  • Automatic Artifact Detection: Shell commands automatically report Process Create artifacts
  • Process Create Tracking: Every shell command execution creates an artifact showing the command line
  • Artifact Management: Artifacts appear in Mythic's Artifacts page (click the fingerprint icon)
  • Extensible: Easy to add artifact reporting for other commands (File Write, Network Connection, etc.)
  • API Call: Reported for:
    • screenshot - GDI Screen Capture (GetDC, CreateCompatibleDC, CreateCompatibleBitmap, BitBlt, GetDIBits)
    • keylog_start - Keyboard Hook (GetAsyncKeyState, GetForegroundWindow, GetWindowTextA, GetUserNameA)

How It Works

  1. Agent Execution: When a command like shell whoami is executed, the agent:

    • Executes the command via _popen()
    • Captures the output
    • Includes the command string in the response payload
  2. Translator Detection: The translator detects the command in the response:

    • Looks for the artifact marker (0xFF) in the response
    • Extracts the command string
    • Creates a Process Create artifact entry
  3. Mythic Integration: The artifact is automatically:

    • Added to the response JSON
    • Tracked in Mythic's Artifacts page
    • Associated with the task and callback

Example Artifact Response

When you execute shell whoami, the response includes:

{
    "task_id": "...",
    "user_output": "CETP-WIN11-01\\localuser",
    "artifacts": [
        {
            "base_artifact": "Process Create",
            "artifact": "whoami",
            "needs_cleanup": false,
            "resolved": false
        }
    ]
}

Viewing Artifacts

  1. Navigate to your callback in the Mythic UI
  2. Click the Artifacts icon (fingerprint) in the top navigation
  3. View all artifacts created by all commands across all callbacks
  4. Filter by artifact type, needs cleanup, resolved status, etc.

Supported Artifact Types

Currently supported:

  • Process Create: Automatically reported for all shell commands
  • File Write: Automatically reported for:
    • cp (copy) - reports destination file path
    • mkdir (create directory) - reports created directory path
    • upload - reports destination file path when uploading files
  • File Delete: Automatically reported for:
    • rm (delete) - reports deleted file/directory path
  • File Read: Automatically reported for:
    • download - reports file path when downloading files
  • API Call: Reported for:
    • screenshot - GDI Screen Capture (GetDC, CreateCompatibleDC, CreateCompatibleBitmap, BitBlt, GetDIBits)
    • keylog_start - Keyboard Hook (GetAsyncKeyState, GetForegroundWindow, GetWindowTextA, GetUserNameA)

Note: The following commands don't require artifacts as they are read-only or don't modify system state:

  • ls, cd, pwd - read-only file system operations
  • ps - already integrated with Process Browser
  • sleep, exit - don't modify system state
  • cat - read-only file operation (doesn't create artifacts, but may report credentials)

Future support can be added for:

  • Network Connection: When network operations occur (e.g., for socks proxy connections)
  • Registry Modification: When registry keys are modified (e.g., reg_set, reg_delete)
  • Process Inject: When processes are injected into (e.g., inject command)

Implementation Details

The artifact system uses:

  • Agent Side Helper (paquete.c): addArtifact() function to easily add artifacts to any command response
  • Agent Side (command handlers): Call addArtifact(paquete, "Artifact Type", "artifact value") after adding response output
  • Translator Side (commands_from_implant.py): Automatically detects, parses, and creates artifact JSON for all artifact types
  • Helper Function: create_artifact() in the translator provides a clean API for creating artifacts

Extending Artifacts for Other Commands

To add artifact support to other commands, use the addArtifact() helper function:

  1. Include the header in your C file:

    #include "paquete.h"
    
  2. Add artifact in your command handler:

    // After adding the response output
    addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
    
    // Add artifact using the helper function
    addArtifact(respuestaTarea, "Artifact Type", "artifact value");
    
  3. The translator automatically detects and creates the artifact - no changes needed!

Example implementations:

  • shell: Process Create artifact with command
  • cp: File Write artifact with destination path
  • mkdir: File Write artifact with directory path
  • upload: File Write artifact with destination file path
  • rm: File Delete artifact with deleted path
  • download: File Read artifact with downloaded file path
  • screenshot: API Call artifact for screen capture APIs
  • keylog_start: API Call artifact for keyboard hook APIs

Best Practices for New Commands

When developing new commands, always consider artifact and credential reporting:

Artifacts

Commands that SHOULD report artifacts:

  • Any command that creates, modifies, or deletes files (cp, mkdir, rm, upload, download)
  • Any command that executes processes (shell, execute, inject)
  • Any command that modifies registry (reg_set, reg_delete)
  • Any command that creates network connections (socks, custom network commands)
  • Any command that modifies system configuration

Commands that DON'T need artifacts:

  • Read-only operations (ls, cd, pwd, cat, read) - these don't modify system state
  • Information gathering commands (ps, whoami, hostname) - unless they create processes
  • Commands that only change local state (sleep, exit)

Rule of thumb: If the command modifies system state or creates forensic evidence, it should report an artifact.

Credentials

Commands that SHOULD report credentials:

  • Commands that extract credentials from system memory (LSASS dumps, SAM, etc.)
  • Commands that read configuration files containing credentials (cat, file readers)
  • Commands that extract authentication data (certificates, keys, tickets, cookies)
  • Commands that parse credential databases (browsers, password managers, etc.)
  • Commands that intercept authentication traffic
  • Any command that discovers passwords, hashes, or other authentication material

Note on cat/file reading commands: While read-only operations don't need artifacts, they SHOULD analyze content and report discovered credentials using addCredential(). The cat command is a perfect example - it automatically detects and reports:

  • Format username:password (e.g., marcos:password123)
  • Format dominio\usuario:password (e.g., test\marcos:password, extracts realm="test", account="marcos")
  • Format usuario@dominio:password (e.g., marcos@tes.com:password, extracts realm="tes.com", account="marcos")
  • Passwords in format password=value or password:value
  • HTTP URLs with embedded credentials: http://user:pass@host
  • NTLM hashes (format aad3b435b51404ee:hash or :32hexchars)

How to add credentials in your command:

// After discovering credentials, add them to the response
addCredential(respuestaTarea, "plaintext", "DOMAIN", "password123", "username");
addCredential(respuestaTarea, "hash", "", "aad3b435b51404ee...", "Administrator");

// For domain accounts with formato dominio\usuario:
// Extract domain as realm, username as account
addCredential(respuestaTarea, "plaintext", "DOMAIN", "password", "username");

// For format usuario@dominio, extract domain as realm:
addCredential(respuestaTarea, "plaintext", "tes.com", "password", "marcos");

For more information, see the Mythic Artifacts documentation.


🔑 Credentials Support

Cazalla supports reporting discovered credentials to Mythic's credential store, allowing you to track and manage credentials discovered during operations.

Features

  • Automatic Credential Detection: Commands can report discovered credentials using the addCredential() helper
  • Multiple Credential Types: Supports plaintext, hash, certificate, key, ticket, and cookie
  • Credential Management: Credentials appear in Mythic's Credentials page (click the key icon)
  • Associated with Tasks: Credentials are linked to the task and callback that discovered them

How It Works

  1. Agent Execution: When a command discovers credentials (e.g., dumping LSASS, extracting hashes), it:

    • Calls addCredential() with the credential details
    • Includes credential data in the response payload
  2. Translator Detection: The translator detects credentials in the response:

    • Looks for the credential marker (0xFE) in the response
    • Extracts credential type, realm, credential value, and account
    • Creates credential entries in the JSON response
  3. Mythic Integration: Credentials are automatically:

    • Added to the response JSON
    • Tracked in Mythic's Credentials page
    • Associated with the task and callback

Example Credential Response

When you execute a command that discovers credentials, the response includes:

{
    "task_id": "...",
    "user_output": "Credentials extracted successfully",
    "credentials": [
        {
            "credential_type": "plaintext",
            "realm": "spooky.local",
            "credential": "SuperS3Cr37",
            "account": "itsafeature"
        },
        {
            "credential_type": "hash",
            "realm": "",
            "credential": "aad3b435b51404eeaad3b435b51404ee:...",
            "account": "Administrator"
        }
    ]
}

Supported Credential Types

According to Mythic Credentials documentation, the following types are supported:

  • plaintext: Plain text passwords
  • hash: Password hashes (NTLM, SHA1, etc.)
  • certificate: Certificates
  • key: Cryptographic keys
  • ticket: Kerberos tickets
  • cookie: Web cookies/session tokens

Viewing Credentials

  1. Navigate to your callback in the Mythic UI
  2. Click the CREDENTIALS icon (key) in the top navigation
  3. View all credentials discovered by all commands across all callbacks
  4. Filter by credential type, realm, account, etc.

Implementation Details

The credential system uses:

  • Agent Side Helper (paquete.c): addCredential() function to easily add credentials to any command response
  • Agent Side (command handlers): Call addCredential(paquete, "credential_type", "realm", "credential", "account") after adding response output
  • Translator Side (commands_from_implant.py): Automatically detects, parses, and creates credential JSON
  • Format: [0xFE marker][type_len:4][type][realm_len:4][realm][credential_len:4][credential][account_len:4][account]

Using Credentials in Commands

To add credential reporting to a command:

// After extracting credentials, add them to the response
addCredential(respuestaTarea, "plaintext", "DOMAIN", "password123", "username");
addCredential(respuestaTarea, "hash", "", "aad3b435b51404ee...", "Administrator");

// For local accounts, realm can be empty string
addCredential(respuestaTarea, "hash", "", "ntlm_hash_here", "LOCALUSER");

Example use cases:

  • LSASS dumping tools → hash credentials
  • Credential extraction commands → plaintext or hash credentials
  • Certificate extraction → certificate credentials
  • Kerberos ticket extraction → ticket credentials
  • Browser credential extraction → plaintext or cookie credentials
  • cat command → Automatically detects and reports credentials found in file contents:
    • Passwords in format password=value or password:value
    • HTTP URLs with embedded credentials: http://user:pass@host
    • NTLM hashes (format aad3b435b51404ee:hash or :32hexchars)
    • Extracts usernames when found in the same line

Note: Commands that only READ files (like cat) should NOT add artifacts since they don't modify system state. However, they CAN analyze content and report discovered credentials using addCredential().

Example for cat command:

// Read file contents
// ... read file code ...

// If credentials are discovered in the file content, report them:
if (found_password) {
    addCredential(respuestaTarea, "plaintext", "", "password123", "username");
}

// Do NOT add artifacts for read-only operations:
// addArtifact(respuestaTarea, "File Write", file_path);  // ❌ WRONG - file wasn't written

For more information, see the Mythic Credentials documentation.


📥 File Downloads Support

Cazalla supports downloading files from the target to the Mythic server using chunked transfers, following Mythic's File Downloads specification.

Features

  • Chunked File Transfers: Large files are automatically split into chunks (512KB default) for efficient transfer
  • Automatic Registration: Files are automatically registered with Mythic before transfer
  • Progress Tracking: Mythic tracks download progress (chunks received/total chunks)
  • File Read Artifacts: Automatically reports File Read artifacts when files are downloaded
  • Full Path Tracking: Reports full file paths for proper tracking in Mythic's file browser

How It Works

  1. Command Execution: When you execute download C:\path\to\file.txt, the agent:

    • Opens the file for reading
    • Calculates file size and number of chunks needed
    • Sends a registration message to Mythic with file metadata (total_chunks, full_path, chunk_size)
    • Receives a file_id from Mythic
    • Reads and sends file data in chunks (base64-encoded)
    • Reports a File Read artifact when complete
  2. Mythic Integration: The download is automatically:

    • Registered in Mythic's file browser
    • Tracked with progress (chunks received/total)
    • Available for download from the Mythic UI once all chunks are received

Using the Download Command

# Download a file from the target
download C:\Users\localuser\Downloads\file.txt

# Downloads are chunked automatically - Mythic will show progress:
# "0 / 5 Chunks Received" → "5 / 5 Chunks Received" (complete)

Download Process

  1. Registration: Agent sends file metadata to Mythic

    • full_path: Full path to the file
    • total_chunks: Number of chunks needed
    • chunk_size: Size of each chunk (512KB default)
  2. File ID: Mythic responds with a unique file_id for this download

  3. Chunk Transfer: Agent sends each chunk sequentially:

    • Chunk number (1-based)
    • file_id to associate with registration
    • Base64-encoded chunk data
  4. Completion: Once all chunks are received, the file appears in Mythic's file browser

Example Download Flow

Agent: [download] Registrando descarga: C:\Users\file.txt (1024000 bytes, 2 chunks)
Mythic: Response with file_id: "uuid-here"
Agent: [download] Enviando chunk 1/2 (512000 bytes)
Agent: [download] Enviando chunk 2/2 (512000 bytes)
Agent: [download] Descarga completada: C:\Users\file.txt (1024000 bytes)
Mythic: File available in file browser

Implementation Details

The download system uses:

  • Chunk Size: 512KB per chunk (configurable in code)
  • File Size Limit: Supports files up to 2GB (can be extended)
  • Base64 Encoding: Chunk data is base64-encoded before transmission
  • Artifact Reporting: Automatically reports "File Read" artifact with file path

Error Handling

The download command handles various error scenarios:

  • File Not Found: Returns error message if file cannot be opened
  • File Too Large: Returns error if file exceeds 2GB limit
  • Empty Files: Properly handles empty files (0 bytes)
  • Access Denied: Returns Windows error code if access is denied

Viewing Downloaded Files

  1. Navigate to your callback in the Mythic UI
  2. Click the Files icon (file browser) in the top navigation
  3. View all downloaded files with their metadata
  4. Download files to your local system

For more information, see the Mythic File Downloads documentation.


📤 File Uploads Support

Cazalla supports uploading files from the Mythic server to the target using chunked transfers, following Mythic's File Upload specification.

Features

  • Chunked File Transfers: Large files are automatically split into chunks (512KB default) for efficient transfer
  • Automatic Path Normalization: Automatically handles path formatting (normalizes double backslashes)
  • Smart Path Handling: Automatically appends filename when path is a directory
  • Progress Tracking: Mythic tracks upload progress (chunks sent/total chunks)
  • File Write Artifacts: Automatically reports File Write artifacts when files are uploaded

How It Works

  1. Command Execution: When you execute upload <file> C:\path\to\destination.txt, the agent:

    • Receives the file_id and destination path from Mythic
    • Normalizes the destination path (handles double backslashes, directories, etc.)
    • Creates the destination file
    • Requests file chunks from Mythic sequentially
    • Receives base64-encoded chunk data from Mythic
    • Decodes and writes chunks to the destination file
    • Reports a File Write artifact when complete
  2. Mythic Integration: The upload is automatically:

    • Tracked with progress in Mythic's UI
    • Registered as a File Write artifact
    • Visible in Mythic's Artifacts page

Using the Upload Command

# Upload a file to the target
# Select file from Mythic UI file selector, then specify destination path
upload <file> C:\Users\localuser\Downloads\file.txt

# Uploads are chunked automatically - Mythic will show progress

Upload Process

  1. Request: Agent sends upload request to Mythic for each chunk:

    • file_id: Unique identifier for the file to upload
    • chunk_num: Automatically incremented (1, 2, 3, ...)
    • chunk_size: Size requested per chunk (512KB default)
    • full_path: Destination path on the target
  2. Response: Mythic responds with chunk data:

    • total_chunks: Total number of chunks for the file
    • chunk_num: Current chunk number
    • chunk_data: Base64-encoded chunk data
  3. Writing: Agent decodes and writes each chunk sequentially

  4. Completion: Once all chunks are received and written, the file is complete

Example Upload Flow

Mythic: Task created with file_id and path
Agent: [upload] Iniciando upload: C:\Users\file.txt (2 chunks)
Agent: [upload] Solicitando chunk  requesting chunk 1
Mythic: Response with chunk 1/2 (512KB base64 data)
Agent: [upload] Chunk 1/2 escrito: 512000 bytes
Agent: [upload] Solicitando chunk  requesting chunk 2
Mythic: Response with chunk 2/2 (512KB base64 data)
Agent: [upload] Chunk 2/2 escrito: 512000 bytes
Agent: [upload] Upload completado: C:\Users\file.txt (1024000 bytes)
Mythic: File Write artifact created

Path Handling

The upload command includes smart path handling:

  • Normalization: Automatically normalizes double backslashes (C:\\\\UsersC:\Users)
  • Directory Detection: If the path is a directory, automatically appends the filename from Mythic
  • Full Path Resolution: Uses GetFullPathName to resolve relative paths to absolute paths
  • Error Handling: Clear error messages for invalid paths, access denied, or directory issues

Implementation Details

The upload system uses:

  • Chunk Size: 512KB per chunk (configurable in code)
  • Base64 Decoding: Chunk data is automatically decoded from base64 before writing
  • Sequential Requests: Agent requests chunks one at a time (1, 2, 3, ...)
  • Artifact Reporting: Automatically reports "File Write" artifact with file path

Error Handling

The upload command handles various error scenarios:

  • Invalid Path: Returns error if path is invalid or malformed
  • Directory as Path: Detects and reports error if path is a directory without filename
  • Access Denied: Returns Windows error code if file cannot be created/written
  • Path Not Found: Returns error if parent directory does not exist

Viewing Upload Artifacts

  1. Navigate to your callback in the Mythic UI
  2. Click the Artifacts icon (fingerprint) in the top navigation
  3. Filter by "File Write" artifact type
  4. View all files that were uploaded, including file paths and timestamps

For more information, see the Mythic File Upload documentation.


⌨️ Keylogging Support

Cazalla supports capturing keystrokes from the target system and reporting them to Mythic's Keylogs feature, following Mythic's Keylog specification.

Features

  • Window-Aware Keylogging: Captures keystrokes along with the active window title
  • User Context: Includes the username in each keylog entry
  • Process-Agnostic: Works with any application (Notepad, browsers, terminals, etc.)
  • Automatic Buffering: Buffers keystrokes and sends them periodically (every 3 seconds or 128 bytes)
  • Background Thread: Runs as a separate thread, allowing other commands to execute while keylogging
  • API Call Artifacts: Automatically reports API Call artifacts when keylogging starts

How It Works

  1. Start Keylogging: When you execute keylog_start, the agent:

    • Starts a background thread that monitors keyboard input
    • Uses GetAsyncKeyState to detect key presses
    • Captures the active window title using GetForegroundWindow and GetWindowTextA
    • Captures the current username using GetUserNameA
    • Buffers keystrokes and sends them every 3 seconds or when buffer reaches 128 bytes
  2. Keylog Transmission: The keylogger periodically sends captured keystrokes:

    • Each transmission includes: user, window title, and captured keystrokes
    • Format follows Mythic's keylog specification
    • Keylogs appear in Mythic's Keylogs UI automatically
  3. Stop Keylogging: When you execute keylog_stop, the agent:

    • Stops the background keylogging thread
    • Sends a final acknowledgment response

Using the Keylog Commands

# Start keylogging
keylog_start

# Stop keylogging
keylog_stop

Keylog Process

  1. Start: Agent creates a background thread that:

    • Polls keyboard state every 20ms
    • Detects key presses using GetAsyncKeyState
    • Captures printable ASCII characters and special keys (Backspace, Tab, Enter)
    • Gets the active window title and username on each send cycle
  2. Buffer & Send: Keystrokes are buffered and sent when:

    • Buffer reaches 128 bytes, OR
    • 3 seconds have passed since last send (if buffer has data)
  3. Format: Each keylog entry contains:

    • user: Current Windows username (e.g., "localuser")
    • window_title: Title of the active window (e.g., "*hello, this is a test - Notepad")
    • keystrokes: Actual captured keystrokes
  4. Stop: Background thread is terminated gracefully

Example Keylog Flow

Agent: [keylog] Started
# User types in Notepad...
Agent: [KEYLOG] Detectado keylog para user='localuser', window='*hello, this is a test - Notepad'
Mythic: Keylog appears in Keylogs tab
# More typing...
Agent: [KEYLOG] Detectado keylog para user='localuser', window='*hello, this is a test - Notepad'
Mythic: Additional keystrokes added to keylog entry
Agent: [keylog] Stopped

Universal Process Support

The keylogger works with any Windows application because it:

  • Uses GetForegroundWindow() to get the currently active window
  • Captures keystrokes system-wide using GetAsyncKeyState
  • Doesn't require injection into specific processes

This means it works for:

  • Text editors (Notepad, VS Code, etc.)
  • Browsers (Chrome, Firefox, Edge)
  • Terminal windows (cmd.exe, PowerShell)
  • Any application that receives keyboard input
  • Secure input fields (though characters may appear as visible in the buffer)

Implementation Details

The keylogging system uses:

  • Polling Method: GetAsyncKeyState to detect key presses (low-level approach)
  • Window Detection: GetForegroundWindow + GetWindowTextA to identify active windows
  • User Detection: GetUserNameA to get current Windows username
  • Thread Safety: Runs in a separate thread, allowing concurrent command execution
  • Buffer Management: 2048-byte buffer to store keystrokes before transmission
  • Artifact Reporting: Automatically reports "API Call" artifact when keylogging starts

Error Handling

The keylog commands handle various scenarios:

  • Already Running: If keylogger is already active, keylog_start returns success without creating duplicate threads
  • Not Running: If keylogger is not running, keylog_stop returns success (no-op)
  • Thread Cleanup: Thread is properly terminated and handles are closed when stopping

Viewing Keylogs

  1. Navigate to your callback in the Mythic UI
  2. Click the KEYLOGS tab in the top navigation
  3. View all captured keystrokes grouped by:
    • Task and callback
    • User and host
    • Window title
    • Timestamp
  4. Use "View Window Together" to see all keystrokes from a specific window session
  5. Filter keylogs by user, window, or time range

Artifact Support

The keylog_start command automatically reports an API Call artifact:

  • Type: API Call
  • Value: "Keyboard Hook: GetAsyncKeyState, GetForegroundWindow, GetWindowTextA, GetUserNameA"
  • Purpose: Tracks that keylogging APIs were used on the system

This artifact appears in Mythic's Artifacts page when keylogging is started.

For more information, see the Mythic Keylog documentation.


🔧 Development

Project Structure

Cazalla/
├── agent_code/cazalla/          # C source code
│   ├── main.c                   # Entry point
│   ├── cazalla.c/h              # Main loop
│   ├── comandos.c/h             # Command handlers
│   ├── paquete.c/h              # Packet creation
│   ├── transporte.c/h           # HTTP transport (WinHTTP)
│   ├── socks_manager.c/h        # SOCKS proxy logic
│   ├── procesos.c/h             # Process listing (with Process Browser support)
│   ├── crypto.c/h               # AES-256-CBC encryption with HMAC-SHA256
│   ├── checkin.c/h              # Initial check-in
│   └── Makefile                 # Build configuration
├── agent_functions/             # Python command definitions
│   ├── ls.py, cd.py, pwd.py     # File system commands
│   ├── shell.py, sleep.py       # Execution control
│   ├── ps.py                    # Process listing (Process Browser enabled)
│   ├── socks.py                 # SOCKS proxy command
│   └── builder.py               # Payload builder (with encryption support)
├── translator/                  # Mythic ↔ Agent translation
│   ├── translator.py            # Main translator (with encryption support)
│   ├── commands_from_c2.py      # Mythic JSON → Binary
│   └── commands_from_implant.py  # Binary → Mythic JSON (Process Browser parser)
└── browser_scripts/             # Mythic UI enhancements
    ├── ls.js                    # Directory listing formatter
    └── ps.js                    # Process list formatter

Adding New Commands

Important: When developing new commands, always consider:

  1. Artifact reporting: Commands that modify system state (create processes, write files, modify registry, create network connections, etc.) should include artifact reporting using the addArtifact() helper function. See Artifacts Support for details.

  2. Credential reporting: Commands that discover or extract credentials (passwords, hashes, certificates, keys, tickets, cookies) should report them using the addCredential() helper function. Commands that read files should analyze content for credentials and report any found. See Credentials Support for details and examples.

  3. Define command in Python (agent_functions/my_command.py):

from mythic_container.MythicCommandBase import *

class MyCommandArguments(TaskArguments):
    def __init__(self, command_line, **kwargs):
        super().__init__(command_line, **kwargs)
        self.args = [
            CommandParameter(name="arg1", type=ParameterType.String)
        ]

class MyCommandCommand(CommandBase):
    cmd = "my_command"
    needs_admin = False
    help_cmd = "my_command <arg1>"
    description = "Does something useful"
    version = 1
    argument_class = MyCommandArguments

    async def create_go_tasking(self, taskData: PTTaskMessageAllData):
        response = PTTaskCreateTaskingMessageResponse(
            TaskID=taskData.Task.ID,
            Success=True,
        )
        return response

    async def process_response(self, task: PTTaskMessageAllData, response: any):
        resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
        return resp
  1. Add to translator (translator/commands_from_c2.py):
elif task_command == "my_command":
    task_data.append(0x99)  # Command ID
    arg1 = task.get("parameters", {}).get("arg1", "")
    task_data += len(arg1).to_bytes(4, 'big')
    task_data += arg1.encode('utf-8')
  1. Implement handler in C (comandos.c):

Remember to add artifacts if the command modifies system state! After adding the response output, use addArtifact() to report the action:

BOOL myCommandHandler(PAnalizador argumentos) {
    SIZE_T tamanoUuid = 36;
    PCHAR taskUuid = getString(argumentos, &tamanoUuid);
    
    SIZE_T arg1Size = 0;
    PCHAR arg1 = getString(argumentos, &arg1Size);
    
    // Do something with arg1
    
    // Send response
    PPaquete respuesta = nuevoPaquete(POST_RESPONSE, TRUE);
    addString(respuesta, taskUuid, FALSE);
    PackageAddFormatPrintf(respuesta, "Command executed: %s\n", arg1);
    
    // IMPORTANT: Add artifact if this command modifies system state
    // Examples:
    // - If creating/modifying files: addArtifact(respuesta, "File Write", file_path);
    // - If creating processes: addArtifact(respuesta, "Process Create", command);
    // - If modifying registry: addArtifact(respuesta, "Registry Write", reg_key);
    // - If creating network connections: addArtifact(respuesta, "Network Connection", connection_info);
    
    // IMPORTANT: Add credentials if this command discovers or extracts credentials
    // Examples:
    // - Plaintext password: addCredential(respuesta, "plaintext", "DOMAIN", "password123", "username");
    // - Hash: addCredential(respuesta, "hash", "", "aad3b435b51404ee...", "Administrator");
    // - Domain account (dominio\usuario): addCredential(respuesta, "plaintext", "DOMAIN", "password", "username");
    // - Format usuario@dominio: addCredential(respuesta, "plaintext", "domain.com", "password", "username");
    // - Certificate: addCredential(respuesta, "certificate", "", "cert_data", "account_name");
    // - For file reading commands, analyze content and report found credentials (see cat command example)
    
    Analizador* resp = mandarPaquete(respuesta);
    liberarPaquete(respuesta);
    if (resp) liberarAnalizador(resp);
    
    return TRUE;
}
  1. Register in command dispatcher (comandos.c):
case 0x99:  // MY_COMMAND
    myCommandHandler(argumentos);
    break;

🐛 Troubleshooting

Agent Won't Check In

  • Verify C2 profile settings (host, port, endpoint)
  • Check network connectivity from target to C2 server
  • Review Mythic logs: sudo docker logs mythic_server
  • Enable debug logging in agent and rebuild

SOCKS Proxy Not Working

Port not accessible:

# Check if port is open
sudo netstat -tlnp | grep 7002

# Ensure Mythic config allows external binding
grep DYNAMIC_PORTS_BIND_LOCALHOST_ONLY ~/Mythic/.env
# Should be "false" for external access

Proxy times out:

  • Verify agent is active and not sleeping
  • Check translator logs: sudo docker logs cazalla_translator
  • Ensure server_id validation in socks_manager.c allows Mythic's IDs

Data not flowing:

  • Enable DEBUG_SOCKS and rebuild agent
  • Check for 0xF5 block in agent logs
  • Verify translator is encoding/decoding SOCKS blocks correctly

Compilation Errors

inet_pton not found (MinGW):

  • Use inet_addr instead (Windows-native)
  • Already fixed in current version

Missing headers:

# Install MinGW dependencies in Docker
apt-get update && apt-get install -y mingw-w64

Task Stays in "Processing" State

Commands like exit, socks start/stop:

  • Ensure handler sends POST_RESPONSE with task UUID
  • Mark task as completed in create_go_tasking or process_response
  • For exit, mark completed immediately (agent terminates)

Process Browser Not Showing Processes

Processes not appearing in Process Browser:

  • Verify ps command executed successfully (check callback output)
  • Check translator logs: sudo docker logs cazalla_translator | grep PROCESS_BROWSER
  • Ensure supported_ui_features = ["process_browser:list"] is set in ps.py
  • Verify processes are being parsed correctly (translator should show "Parseados X procesos")
  • Rebuild translator if changes were made: sudo ./mythic-cli build cazalla

Processes showing as "UNKNOWN - MISSING DATA":

  • This usually indicates processes that couldn't be accessed (protected/system processes)
  • Check if the issue persists after rebuilding the agent
  • Some processes may legitimately lack certain information (e.g., system processes)

Encryption Issues

Encryption not working:

  • Verify AESPSK parameter is configured in build parameters
  • Check build output for: ✓ Encryption ENABLED
  • Review translator logs for encryption/decryption errors: sudo docker logs cazalla_translator | grep CRYPTO
  • Ensure encryption key is present in both agent and translator (auto-configured by Mythic)

"HMAC verification failed" errors:

  • Usually indicates key mismatch between agent and translator
  • Rebuild the payload to regenerate the encryption key
  • Check that both agent and translator are using the same payload UUID

📚 References


📄 License

Cazalla is licensed under the BSD 3-Clause License. See LICENSE.md for details.


👥 Credits

Developed by: Kaseya OFSTeam

Special thanks to:

  • The Mythic C2 team for the excellent framework
  • The SNCF Red Team for the foundational C agent tutorial
  • The open-source security community

Made with and 💻 by the Kaseya OFSTeam

S
Description
No description provided
Readme 3.5 MiB
Languages
C 96.4%
Python 3.5%