Rust Command Line History In Reverse Shell

448 views Asked by At

I have this code to listen on a port and get a reverse shell

fn pipe_thread<R, W>(mut r: R, mut w: W) -> std::thread::JoinHandle<()>
where
    R: std::io::Read + Send + 'static,
    W: std::io::Write + Send + 'static,
{
    std::thread::spawn(move || {
        let mut buffer = [0; 1024];
        loop {
            let len = r.read(&mut buffer).unwrap();
            if len == 0 {
                println!("Connection lost");
                std::process::exit(0x0100);
            }
            w.write(&buffer[..len]).unwrap();
            w.flush().unwrap();
        }
    })
}

fn listen() -> std::io::Result<()> {
    let listener = std::net::TcpListener::bind(format!("{}:{}", "0.0.0.0", "55100"))?;
    println!("Started listener");

    let (stream, _) = listener.accept()?;
    let t1 = pipe_thread(std::io::stdin(), stream.try_clone()?);
    println!("Connection recieved");
    let t2 = pipe_thread(stream, std::io::stdout());
    t1.join().unwrap();
    t2.join().unwrap();

    return Ok(());
}

How would I implement rustyline in this code so if I press the up arrow inside the shell it will put the recent command as input

Basically like if I would run the program with rlwrap but have it built in inside the application

1

There are 1 answers

14
C. Lang On BEST ANSWER

Try this:

Include this in your Cargo.toml

[dependencies]
rustyline = "8.2.0"

Main.rs

use rustyline::error::ReadlineError;
use rustyline::Cmd;
use rustyline::Editor;
use rustyline::KeyEvent;
use std::io::Write;

fn pipe_thread<R, W>(mut r: R, mut w: W) -> std::thread::JoinHandle<()>
where
    R: std::io::Read + Send + 'static,
    W: std::io::Write + Send + 'static,
{
    std::thread::spawn(move || {
        let mut buffer = [0; 1024];
        loop {
            let len = r.read(&mut buffer).unwrap();
            if len == 0 {
                println!("Connection lost");
                std::process::exit(0x0100);
            }
            w.write(&buffer[..len]).unwrap();
            w.flush().unwrap();
        }
    })
}

fn main() -> std::io::Result<()> {
    let listener = std::net::TcpListener::bind(format!("{}:{}", "0.0.0.0", "55100"))?;
    println!("Started listener");

    let (mut stream, _) = listener.accept()?;
    println!("Connection recieved");
    let t = pipe_thread(stream.try_clone().unwrap(), std::io::stdout());

    let mut rl = Editor::<()>::new();
    rl.bind_sequence(KeyEvent::ctrl('R'), Cmd::HistorySearchBackward);
    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(command) => {
                rl.add_history_entry(command.as_str());

                println!("{}", command);

                // Clone command to increase its lifetime
                let command = command.clone() + "\n";

                // Send a TCP message
                stream
                    .write(command.as_bytes())
                    .expect("Faild to send TCP.");
            }
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break;
            }
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }

    return Ok(());
}