rustcommand-history

Rust Command Line History In Reverse Shell


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


Solution

  • 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(());
    }