【问题标题】:Capture output of fexecve on memfd_create fd在 memfd_create fd 上捕获 fexecve 的输出
【发布时间】:2022-01-06 00:26:56
【问题描述】:

这段代码应该创建一个memfd(匿名文件),将shellcode复制为Vec<u8>,然后 最后使用fexecve()执行。

// A method that takes a u8 vector and copies it to a memfd_create file, then executes using fexecve()

use std::ffi::{CStr, CString};
use nix::sys::memfd::{memfd_create, MemFdCreateFlag};
use nix::unistd::fexecve;
use nix::unistd::write;

fn fileless_exec(code: Vec<u8>) {
    
    // Name using CStr 
    let name = CStr::from_bytes_with_nul(b"memfd\0").unwrap();

    // Create a new memfd file.
    let fd = memfd_create(&name, MemFdCreateFlag::MFD_CLOEXEC).unwrap();

    // Write to the file
    let _nbytes = write(fd, &code);

    // args for fexecve
    let arg1 = CStr::from_bytes_with_nul(b"memfd\0").unwrap();

    // enviroment variables
    let env = CString::new("").unwrap();

    // fexecve
    let _ = match fexecve(fd, &[&arg1], &[&env]) {
        Ok(_) => {
            println!("Success!");
        },
        Err(e) => {
            println!("Error: {}", e);
        }
    };
}

fn main() {

    // Read the file `hello_world` into a vector of bytes.
    let code = std::fs::read("/tmp/hello_world").unwrap();
    fileless_exec(code);
}

(hello_world 只是一个简单的 C hello world 示例)。

二进制文件正常执行并写入标准输出。我如何将输出捕获为 Rust 中的 String?我已经看到 this 示例在 C 中执行此操作,这最终是我要在这里实现的目标。

这里的重点是使用它的 fd 执行一个文件并捕获它的输出。输入可能来自任何地方(不像hello_world 可执行文件那样总是来自磁盘):来自网络端点、其他进程等。

我知道这段代码不是“Rust”-y。

【问题讨论】:

  • 它应该与您从任何其他进程捕获输出几乎相同。请记住,使用fexecve 不是强制性的;您可以将 /dev/fd/NNN 传递给需要字符串文件名的 API。
  • 您可以执行与 C 示例相同的操作。 nix crate(您已经使用过)应该为您需要的所有原语提供安全或大部分安全的包装器,例如 pipe()fork()
  • 顺便说一句,每当我看到let _nbytes = write(fd, &amp;code) 时,我都会在内心深处死去。 write() 返回它实际写了多少,它可能比要求的少!不属于循环的write() 几乎可以肯定是一个等待发生的错误。

标签: memory rust unistd.h


【解决方案1】:

所以遵循一些非常糟糕的做法,我能够做到这一点:

// A method that takes a u8 vector and copies it to a memfd_create file.

use std::ffi::{CStr, CString};
use nix::sys::memfd::{memfd_create, MemFdCreateFlag};
use nix::unistd::{read, write, fexecve, dup2, close, fork};


fn fileless_exec(code: Vec<u8>, fd_name: &[u8], stdout: &mut String) {
    
    // Name using CStr 
    let name = CStr::from_bytes_with_nul(fd_name).unwrap();

    // Create a new memfd file.
    let fd = memfd_create(&name, MemFdCreateFlag::MFD_CLOEXEC).unwrap();

    // Write to the file
    let _nbytes = write(fd, &code);

    // args for fexecve
    let arg1 = CStr::from_bytes_with_nul(fd_name).unwrap();

    // enviroment variables
    let env = CString::new("").unwrap();

    // to capture the output we need to use a pipe
    let pipe = nix::unistd::pipe().unwrap();

    unsafe {
        let mut output = [0u8; 1024];
        
        // fork and exec
        let pid = fork().unwrap();

        if pid.is_child() {
            
            // dup the read end of the pipe to stdout
            dup2(pipe.1, nix::libc::STDOUT_FILENO).unwrap();
            
            // close the write end of the pipe
            close(pipe.0).unwrap();

            // close the read end of the pipe
            close(pipe.1).unwrap();

            // fexecve
            fexecve(fd, &[&arg1], &[&env]).unwrap();
        } else {

            // close the read end of the pipe
            close(pipe.1).unwrap();

            // write to the pipe
            let _nbytes = read(pipe.0, &mut output);

            // close the write end of the pipe
            close(pipe.0).unwrap();

            // convert output to a string
            *stdout = String::from_utf8(output.to_vec()).unwrap();
        }
    }
}

fn main() {

    // Read the file `/bin/ls` into a vector of bytes.
    let code = std::fs::read("/bin/ls").unwrap();
    let mut output = String::new();
    

    fileless_exec(code, b"anonymous\0", &mut output);

    print!("File output: {}", output);
}

这暂时有效...感谢您的回答

【讨论】:

  • 我没有看到任何不良做法(除了不检查write() 的结果,已经提到过)。但是有一个错误:您有一个read(),它不适用于在多次写入中写入输出的程序,或者那些输出大于管道缓冲区的程序。您可以使用File::from_raw_fd()pipe.0 创建一个File,然后使用File::read_to_end() 将其读到最后。
猜你喜欢
  • 2020-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-09
  • 2012-10-18
  • 1970-01-01
相关资源
最近更新 更多