chore: reordered needle again

This commit is contained in:
əlemi 2023-03-27 17:45:49 +02:00
parent 4e4aceb092
commit 29c9a403f4
6 changed files with 106 additions and 110 deletions

View file

@ -1,28 +1,6 @@
use nix::{unistd::Pid, Result, libc::{PROT_READ, MAP_PRIVATE, MAP_ANON, PROT_WRITE}, sys::{ptrace, wait::waitpid}};
use crate::{syscalls::RemoteMMap, operations::write_buffer, injector::RemoteOperation};
pub struct RemoteString {
pub ptr: Option<usize>,
pub txt: String,
}
impl RemoteString {
pub fn new(txt: String) -> Self {
RemoteString { ptr: None, txt }
}
}
impl RemoteOperation for RemoteString {
fn inject(&mut self, pid: Pid, syscall: usize) -> Result<u64> {
let ptr = RemoteMMap::args(
0, self.txt.len(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0
).inject(pid, syscall)?;
write_buffer(pid, ptr as usize, self.txt.as_bytes(), 32)?; // TODO don't hardcode word size
self.ptr = Some(ptr as usize);
Ok(ptr)
}
}
use crate::{syscalls::RemoteMMap, senders::write_buffer, injector::RemoteOperation};
pub struct RemoteShellcode<'a> {
code: &'a [u8],
@ -42,7 +20,7 @@ impl RemoteOperation for RemoteShellcode<'_> {
).inject(pid, syscall)?;
let mut shellcode = self.code.to_vec();
shellcode.push(0xCC); // is this the debugger trap?
write_buffer(pid, ptr as usize, shellcode.as_slice(), 32)?; // TODO don't hardcode word size
write_buffer(pid, ptr as usize, shellcode.as_slice())?;
let mut regs = original_regs.clone();
regs.rip = ptr;
ptrace::setregs(pid, regs)?;

View file

@ -1,5 +1,28 @@
use nix::{Result, unistd::Pid};
use std::ffi::c_void;
use nix::{Result, unistd::Pid, sys::{ptrace, wait::waitpid}};
pub trait RemoteOperation {
fn inject(&mut self, pid: Pid, syscall: usize) -> Result<u64>;
}
pub fn step_to_syscall(pid: Pid) -> Result<usize> {
let mut registers;
let mut addr;
let mut instructions;
// seek to syscall
loop {
registers = ptrace::getregs(pid)?;
addr = registers.rip as usize;
instructions = ptrace::read(pid, addr as *mut c_void)?;
// println!("@ 0x{:X} [{:x}]", insn_addr, curr_instr);
if instructions & 0xFFFF == 0x050F {
return Ok(addr);
}
ptrace::step(pid, None)?;
waitpid(pid, None)?;
}
}

View file

@ -1,13 +1,14 @@
mod syscalls;
mod rce;
mod operations;
mod executors;
mod senders;
mod injector;
use injector::RemoteOperation;
use injector::{RemoteOperation, step_to_syscall};
use nix::{Result, {sys::{ptrace, wait::waitpid}, unistd::Pid}};
use clap::Parser;
use operations::step_to_syscall;
use rce::{RemoteString, RemoteShellcode};
use executors::RemoteShellcode;
use senders::RemoteString;
use syscalls::RemoteWrite;
#[derive(Parser, Debug)]
@ -15,45 +16,33 @@ use syscalls::RemoteWrite;
struct NeedleArgs {
/// target process pid
pid: i32,
/// word size on OS (check with $ getconf WORD_BIT)
#[arg(long, default_value_t = 32)]
word: u32,
}
pub fn nasty_stuff(pid: Pid, _word_size: usize) -> Result<()> {
let original_registers = ptrace::getregs(pid)?;
pub fn nasty_stuff(pid: Pid) -> Result<()> {
let syscall_addr = step_to_syscall(pid)?;
let mut msg = RemoteString::new("injected!\n\0".into());
msg.inject(pid, syscall_addr)?;
RemoteWrite::args(1, msg).inject(pid, syscall_addr)?;
RemoteShellcode::new(&[0u8]).inject(pid, syscall_addr)?;
ptrace::setregs(pid, original_registers)?;
Ok(())
}
fn main() {
fn main() -> Result<()> {
let args = NeedleArgs::parse();
let pid = Pid::from_raw(args.pid);
if let Err(e) = ptrace::attach(pid) {
eprintln!("Could not attach to process : {}", e);
return;
}
if let Err(e) = waitpid(pid, None) {
eprintln!("Failed waiting for process to stop : {}", e);
}
ptrace::attach(pid)?;
waitpid(pid, None)?;
println!("Attached to process #{}", args.pid);
if let Err(e) = nasty_stuff(pid, args.word as usize) {
eprintln!("Could not pwn : {}", e);
}
let regs = ptrace::getregs(pid)?;
nasty_stuff(pid)?;
ptrace::setregs(pid, regs)?;
if let Err(e) = ptrace::detach(pid, None) {
eprintln!("Could not resume process : {}", e);
} else {
println!("Released process #{}", args.pid);
}
ptrace::detach(pid, None)?;
println!("Released process #{}", args.pid);
Ok(())
}

View file

@ -1,54 +0,0 @@
use std::ffi::c_void;
use nix::{Result, unistd::Pid, sys::{ptrace, wait::waitpid}};
#[allow(unused)]
pub fn read_buffer(pid: Pid, addr: usize, size: usize, word: u32) -> Result<Vec<u8>> {
let mut out = vec![];
for i in (0..size).step_by((word/8) as usize) {
let data = ptrace::read(pid, (addr + i) as *mut c_void)?;
for j in 0..(word/8) as usize {
out.push(((data >> (j * 8)) & 0xFF) as u8);
}
}
Ok(out)
}
pub fn write_buffer(pid: Pid, addr: usize, payload: &[u8], word:u32) -> Result<()> {
let step = word / 8;
let mut at = addr;
for chunk in payload.chunks(step as usize) {
let mut buf : u64 = 0;
for (i, c) in chunk.iter().enumerate() {
buf |= (*c as u64) << (i * 8);
}
unsafe { ptrace::write(pid, at as *mut c_void, buf as *mut c_void)?; }
at += step as usize;
}
Ok(())
}
pub fn step_to_syscall(pid: Pid) -> Result<usize> {
let mut registers;
let mut addr;
let mut instructions;
// seek to syscall
loop {
registers = ptrace::getregs(pid)?;
addr = registers.rip as usize;
instructions = ptrace::read(pid, addr as *mut c_void)?;
// println!("@ 0x{:X} [{:x}]", insn_addr, curr_instr);
if instructions & 0xFFFF == 0x050F {
return Ok(addr);
}
ptrace::step(pid, None)?;
waitpid(pid, None)?;
}
}

60
src/needle/senders.rs Normal file
View file

@ -0,0 +1,60 @@
use std::ffi::c_void;
use nix::{Result, unistd::Pid, sys::ptrace, libc::{PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON}};
use crate::{injector::RemoteOperation, syscalls::RemoteMMap};
const WORD_SIZE : usize = 32;
#[allow(unused)]
pub fn read_buffer(pid: Pid, addr: usize, size: usize) -> Result<Vec<u8>> {
let mut out = vec![];
for i in (0..size).step_by(WORD_SIZE/8) {
let data = ptrace::read(pid, (addr + i) as *mut c_void)?;
for j in 0..WORD_SIZE/8 {
out.push(((data >> (j * 8)) & 0xFF) as u8);
}
}
Ok(out)
}
pub fn write_buffer(pid: Pid, addr: usize, payload: &[u8]) -> Result<()> {
let step = WORD_SIZE / 8;
let mut at = addr;
for chunk in payload.chunks(step as usize) {
let mut buf : u64 = 0;
for (i, c) in chunk.iter().enumerate() {
buf |= (*c as u64) << (i * 8);
}
unsafe { ptrace::write(pid, at as *mut c_void, buf as *mut c_void)?; }
at += step as usize;
}
Ok(())
}
pub struct RemoteString {
pub ptr: Option<usize>,
pub txt: String,
}
impl RemoteString {
pub fn new(txt: String) -> Self {
RemoteString { ptr: None, txt }
}
}
impl RemoteOperation for RemoteString {
fn inject(&mut self, pid: Pid, syscall: usize) -> Result<u64> {
let ptr = RemoteMMap::args(
0, self.txt.len(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0
).inject(pid, syscall)?;
write_buffer(pid, ptr as usize, self.txt.as_bytes())?;
self.ptr = Some(ptr as usize);
Ok(ptr)
}
}

View file

@ -1,6 +1,6 @@
use nix::{libc::user_regs_struct, Result, sys::{ptrace, wait::waitpid}, unistd::Pid};
use crate::{rce::RemoteString, injector::RemoteOperation};
use crate::{injector::RemoteOperation, senders::RemoteString};
pub trait RemoteSyscall {
fn registers(&self, regs: &mut user_regs_struct);
@ -73,7 +73,7 @@ impl RemoteSyscall for RemoteOpen {
pub struct RemoteWrite {
fd: u64,
buf: RemoteString, // TODO make remote slice or remote bytes
buf: RemoteString,
}
impl RemoteWrite {