diff --git a/Cargo.toml b/Cargo.toml index 5eff1b7..3235281 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,10 +5,11 @@ edition = "2021" [lib] name = "tetanus" +crate-type = ["cdylib"] path = "src/lib.rs" [[bin]] -name = "rustyneedle" +name = "needle" path = "src/main.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/lib.rs b/src/lib.rs index ec258d6..2c06f4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ #[ctor::ctor] fn constructor() { - println!("Hello world!"); + println!("Infected!"); } diff --git a/src/main.rs b/src/main.rs index 7c53734..de1b3f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ +mod syscalls; + use std::ffi::c_void; -use nix::{sys::ptrace, unistd::Pid, errno::Errno}; +use nix::{Result, {sys::{ptrace, wait::waitpid}, unistd::Pid}}; use clap::Parser; +use syscalls::prepare_exit; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -13,7 +16,7 @@ struct NeedleArgs { word: u32, } -pub fn write_buffer(pid: Pid, addr: usize, payload: &[u8], word:u32) -> Result<(), Errno> { +pub fn write_buffer(pid: Pid, addr: usize, payload: &[u8], word:u32) -> Result<()> { let mut buffer = payload.to_vec(); while buffer.len() % word as usize != 0 { @@ -31,6 +34,53 @@ pub fn write_buffer(pid: Pid, addr: usize, payload: &[u8], word:u32) -> Result<( Ok(()) } +pub fn pwn(pid: Pid, _word_size: usize) -> Result<()> { + + let mut prev_regs; + let mut insn_addr; + let mut curr_instr; + + loop { + prev_regs = ptrace::getregs(pid)?; + insn_addr = prev_regs.rip; + curr_instr = ptrace::read(pid, insn_addr as *mut c_void)?; + // println!("@ 0x{:X} [{:x}]", insn_addr, curr_instr); + + if curr_instr & 0xFFFF == 0x050F { + // println!("found syscall!"); + break; + } + + ptrace::step(pid, None)?; + waitpid(pid, None)?; + } + + // // Put syscall opcodes + // let mut syscall_insn = vec![0x00u8; word_size/8]; + // syscall_insn[0] = 0x05; // it's two! + // syscall_insn[1] = 0x0F; + + // unsafe { + // ptrace::write(pid, insn_addr, syscall_insn.as_slice().as_ptr() as *mut c_void)?; + // } + + let mut call_regs = prev_regs.clone(); + + // call_regs.rip = insn_addr; + prepare_exit(&mut call_regs, 69); + ptrace::setregs(pid, call_regs)?; + ptrace::step(pid, None)?; + waitpid(pid, None)?; + + // restore code and registers + // unsafe { + // ptrace::write(pid, insn_addr, prev_instr.as_ptr() as *mut c_void)?; + // } + // ptrace::setregs(pid, prev_regs)?; + + Ok(()) +} + fn main() { let args = NeedleArgs::parse(); let pid = Pid::from_raw(args.pid); @@ -40,15 +90,17 @@ fn main() { return; } - println!("Attached to process #{}", args.pid); - - let shellcode = [42; 20]; - - if let Err(e) = write_buffer(pid, 0x66666, &shellcode, args.word) { - eprintln!("Failed writing shellcode into process memory space: {}", e); + if let Err(e) = waitpid(pid, None) { + eprintln!("Failed waiting for process to stop : {}", e); } - if let Err(e) = ptrace::cont(pid, None) { + println!("Attached to process #{}", args.pid); + + if let Err(e) = pwn(pid, args.word as usize) { + eprintln!("Could not pwn : {}", e); + } + + if let Err(e) = ptrace::detach(pid, None) { eprintln!("Could not resume process : {}", e); } else { println!("Released process #{}", args.pid); diff --git a/src/syscalls.rs b/src/syscalls.rs new file mode 100644 index 0000000..0124450 --- /dev/null +++ b/src/syscalls.rs @@ -0,0 +1,31 @@ +use nix::libc::user_regs_struct; + +fn prepare_for_syscall(regs: &mut user_regs_struct, rax: u64, rdi: u64, rsi: u64, rdx: u64, r10: u64, r8: u64, r9: u64) { + regs.rax = rax; + regs.rdi = rdi; + regs.rsi = rsi; + regs.rdx = rdx; + regs.r10 = r10; + regs.r8 = r8; + regs.r9 = r9; +} + +#[allow(unused)] +pub fn prepare_mmap(regs: &mut user_regs_struct, addr: u64, len: u64, prot: u64, flags: u64, fd: u64, off: u64) { + prepare_for_syscall(regs, 9, addr, len, prot, flags, fd, off); +} + +#[allow(unused)] +pub fn prepare_open(regs: &mut user_regs_struct, filename: &str, flags: u64, mode: u64) { + prepare_for_syscall(regs, 2, filename.as_ptr() as u64, flags, mode, 0, 0, 0); +} + +#[allow(unused)] +pub fn prepare_write(regs: &mut user_regs_struct, fd: u64, buf: &str, count: usize) { + prepare_for_syscall(regs, 1, fd, buf.as_ptr() as u64, count as u64, 0, 0, 0); +} + +#[allow(unused)] +pub fn prepare_exit(regs: &mut user_regs_struct, error_code: i64) { + prepare_for_syscall(regs, 60, error_code as u64, 0, 0, 0, 0, 0); +}