chore: reordered needle again
This commit is contained in:
parent
4e4aceb092
commit
29c9a403f4
6 changed files with 106 additions and 110 deletions
|
@ -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)?;
|
|
@ -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)?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
|
||||
ptrace::detach(pid, None)?;
|
||||
|
||||
if let Err(e) = ptrace::detach(pid, None) {
|
||||
eprintln!("Could not resume process : {}", e);
|
||||
} else {
|
||||
println!("Released process #{}", args.pid);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -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
60
src/needle/senders.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue