mythic-c2
Mythic C2 agent protocol library for Rust — message encoding/decoding, AES-256-CBC-HMAC encryption, RSA encrypted key exchange, and a transport abstraction layer.
Cargo features
| Feature | Description |
|---|---|
httpx (default) |
HTTP/HTTPS with URL-safe base64 query parameters |
http |
Plain HTTP/HTTPS transport |
dns |
DNS-over-HTTPS transport |
websocket |
WebSocket transport |
github |
GitHub Issues/Comments transport |
rustls (default) |
TLS via rustls |
native-tls |
TLS via native-tls |
rsa-staging |
RSA encrypted key exchange |
httpx and rustls are enabled by default. Multiple transports can be
compiled into the same binary and selected at runtime via the C2Profiles
enum.
Quick Start
use ;
use Uuid;
// Implement C2Transport for your channel, or use a built-in transport.
let payload_uuid = parse_str.unwrap;
let mut c2 = HttpC2 ;
// 1. Checkin
let agent = easy_checkin
.unwrap;
// 2. Poll for tasks
let tasks = agent.get_tasking.unwrap;
for t in &tasks.tasks
Built-in transports
The library can deserialize Mythic payload-builder configurations directly:
use C2Profiles;
let builder_json = r#"{
"c2_profiles": [
{ "httpx": {
"callback_host": "https://example.com",
"callback_port": 443,
"get_uri": "index",
"post_uri": "data",
"query_path_name": "id"
}}
]
}"#;
let profiles: C2Profiles = from_str.unwrap;
for p in profiles
Each transport implements C2Transport and can be used directly without the
config enum:
use ;
let cfg = HttpConfig ;
let transport = new.unwrap;
Three API Levels
MythicAgent facade — high-level checkin / get_tasking / post_response:
let mut c2 = HttpC2 ;
let agent = easy_checkin?;
let tasks = agent.get_tasking?;
agent.post_response?;
Free functions — full control over every step:
let crypto = from_base64_key?;
let iv = c2.random_iv?;
let pkt = encode_message?;
let = ?;
Raw types — use serde_json directly on any message struct:
let req = new;
let json = to_vec?;
C2Transport Trait
Implement for any transport (HTTP, DNS, WebSocket, etc.). Three methods
required; get_aes_psk, random_iv, and encrypted_exchange_check
have sensible defaults:
use ;
// Encrypted transports MUST override random_iv with a CSPRNG.
// fn random_iv(&self) -> Result<[u8; 16], MythicError> { getrandom::getrandom(&mut iv)?; Ok(iv) }
get_aes_psk() and encrypted_exchange_check() default to None / false — override
only when needed.
Three Communication Scenarios
| Scenario | C2 config | Flow |
|---|---|---|
| Plaintext | get_aes_psk = None |
checkin → get_tasking → post_response |
| Static key | get_aes_psk = Some(key) |
AES-256-CBC-HMAC encrypted versions of the above |
| RSA EKE | get_aes_psk = None, encrypted_exchange_check = true |
RSA staging → checkin (requires rsa-staging feature) |
See examples/mythic_facade.rs for the full agent lifecycle.
Wire Format
Base64( UUID(36) + [ IV(16) + ciphertext + HMAC-SHA256(32) ] )
- Plaintext: the encrypted portion is replaced with the raw JSON bytes.
- Encrypted: AES-256-CBC with PKCS7 padding, encrypt-then-MAC with HMAC-SHA256.
- UUID: hyphenated UUIDv4 string (36 ASCII characters).
Feature Status
| Feature | Status |
|---|---|
| Plaintext comms | Complete |
| Static AES-256-CBC-HMAC | Complete |
| RSA staging key exchange | Complete (behind rsa-staging) |
| Translation-container staging | Types defined |
| Checkin / get_tasking / post_response | Complete |
| HTTP / HTTPX transport | Complete |
| DNS transport | Complete (DoH) |
| WebSocket transport | Complete |
| GitHub transport | Complete |
| File download (agent→mythic) | Types defined |
| File upload (mythic→agent) | Types defined |
| P2P / delegate messages | Types defined |
| SOCKS / RPFWD / interactive | Types defined |
| Hooking features (file browser, credentials, keylogs, etc.) | Types defined |
License
GPL-3.0-only