【发布时间】: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 示例相同的操作。
nixcrate(您已经使用过)应该为您需要的所有原语提供安全或大部分安全的包装器,例如pipe()和fork()。 -
顺便说一句,每当我看到
let _nbytes = write(fd, &code)时,我都会在内心深处死去。write()返回它实际写了多少,它可能比要求的少!不属于循环的write()几乎可以肯定是一个等待发生的错误。