2025-10-21 15:40:52 +00:00
2025-04-02 16:45:10 +02:00
2025-04-02 16:45:10 +02:00
2025-10-21 17:39:53 +02:00
2025-04-07 10:49:56 +00:00
2025-04-07 10:49:56 +00:00
2025-10-21 15:40:52 +00: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
  • 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.


🛠️ 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

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 ps

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.


⚙️ 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)

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

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

🔧 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
│   ├── 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
│   ├── socks.py                 # SOCKS proxy command
│   └── builder.py               # Payload builder
├── translator/                  # Mythic ↔ Agent translation
│   ├── translator.py            # Main translator
│   ├── commands_from_c2.py      # Mythic JSON → Binary
│   └── commands_from_implant.py # Binary → Mythic JSON
└── browser_scripts/             # Mythic UI enhancements
    ├── ls.js                    # Directory listing formatter
    └── ps.js                    # Process list formatter

Adding New Commands

  1. 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):
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);
    
    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)

📚 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%