mythic-c2 0.1.0

Mythic C2 agent protocol library — message encoding, AES-256-CBC-HMAC crypto, and transport abstraction
Documentation

mythic-c2

Mythic C2 agent protocol library for Rust — message encoding/decoding, AES-256-CBC-HMAC encryption, and a transport abstraction layer.

#![no_std] compatible with alloc, suitable for embedded agent binaries.

Quick Start

use mythic::{Mythic, Aes256HmacCrypto, CheckinInfo};
use uuid::Uuid;

let agent_uuid = Uuid::parse_str("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee").unwrap();
let crypto = Aes256HmacCrypto::new([0xAB; 32], [0xCD; 16]);
let mut mythic = Mythic::with_crypto(agent_uuid, crypto);

// Build a checkin packet — ready to send
let pkt = mythic.build_checkin(CheckinInfo {
    os: Some("linux".into()),
    host: Some("web01".into()),
    user: Some("root".into()),
    pid: Some(1337),
    ips: vec!["10.0.0.1".into()],
    ..Default::default()
}).unwrap();
// → Base64( UUID + AES256( JSON({ "action": "checkin", ... }) ) )

Two API Levels

Mythic facade — holds UUID and crypto, one call per operation:

let mythic = Mythic::with_crypto(uuid, crypto);
let pkt = mythic.build_checkin(info)?;
let (_, resp) = mythic.parse_checkin(&reply)?;
mythic.set_agent_uuid(resp.id);  // switch to callback UUID

Free functions — full control over every step:

let req = ReqCheckin::new(uuid, info);
let pkt = encode_message(&req, uuid, &crypto)?;
let (_, resp) = decode_message::<RespCheckin>(&reply, Some(uuid), &crypto)?;

C2Transport Trait

Implement C2Transport for any transport (HTTP, DNS, WebSocket, etc.):

use mythic::C2Transport;

struct HttpTransport;

impl C2Transport for HttpTransport {
    type Error = Box<dyn std::error::Error>;

    fn checkin(&self, pkt: &str) -> Result<String, Self::Error> {
        ureq::get("https://server/agent_message").query("q", pkt).call()?.into_string().map_err(Into::into)
    }
    fn get_tasking(&self, pkt: &str)       -> Result<String, Self::Error> { self.checkin(pkt) }
    fn post_response(&self, pkt: &str)     -> Result<String, Self::Error> { self.checkin(pkt) }
}

Then use combined methods:

let (uuid, resp) = mythic.checkin(info, &transport)?;

Three Communication Scenarios

Scenario Init Checkin
Plaintext Mythic::new(uuid) build_checkin() — no encryption
Static key Mythic::with_crypto(uuid, key) build_checkin() — AES encrypted
RSA EKE Mythic::with_crypto(uuid, aes_psk) → staging → set_crypto(…) build_checkin() — negotiated key

See examples/mythic_facade.rs for the full agent lifecycle.

License

GPL-3.0-only