feat: PoC write on target stdout and resume
This commit is contained in:
parent
67cd814c99
commit
2a9ce2e8c7
2 changed files with 47 additions and 18 deletions
57
src/main.rs
57
src/main.rs
|
@ -1,9 +1,9 @@
|
||||||
mod syscalls;
|
mod syscalls;
|
||||||
|
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use nix::{Result, {sys::{ptrace, wait::waitpid}, unistd::Pid}};
|
use nix::{Result, {sys::{ptrace, wait::waitpid}, unistd::Pid}, libc::{PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON}};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use syscalls::prepare_exit;
|
use syscalls::{prepare_mmap, prepare_write};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
|
@ -16,19 +16,42 @@ struct NeedleArgs {
|
||||||
word: u32,
|
word: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_buffer(pid: Pid, addr: usize, payload: &[u8], word:u32) -> Result<()> {
|
pub fn send_str(pid: Pid, syscall_addr: u64, data: &str) -> Result<usize> {
|
||||||
let mut buffer = payload.to_vec();
|
let mut regs = ptrace::getregs(pid)?;
|
||||||
|
regs.rip = syscall_addr;
|
||||||
|
prepare_mmap(&mut regs, 0, data.len(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0xFFFFFFFFFFFFFFFF, 0);
|
||||||
|
ptrace::setregs(pid, regs)?;
|
||||||
|
ptrace::step(pid, None)?;
|
||||||
|
waitpid(pid, None)?;
|
||||||
|
let zone_addr = ptrace::getregs(pid)?.rax as usize;
|
||||||
|
write_buffer(pid, zone_addr, data.as_bytes(), 32)?; // TODO word size!
|
||||||
|
Ok(zone_addr)
|
||||||
|
}
|
||||||
|
|
||||||
while buffer.len() % word as usize != 0 {
|
pub fn read_buffer(pid: Pid, addr: usize, size: usize, word: u32) -> Result<Vec<u8>> {
|
||||||
buffer.push(0); // pad with zeros because we copy chunks of size 'word'
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in (0..buffer.len()).step_by(word as usize) {
|
Ok(out)
|
||||||
unsafe {
|
}
|
||||||
let offset = (addr + i) as *mut c_void;
|
|
||||||
let data = (buffer.as_ptr().add(i)) as *mut c_void;
|
pub fn write_buffer(pid: Pid, addr: usize, payload: &[u8], word:u32) -> Result<()> {
|
||||||
ptrace::write(pid, offset, data)?;
|
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(())
|
Ok(())
|
||||||
|
@ -40,6 +63,7 @@ pub fn pwn(pid: Pid, _word_size: usize) -> Result<()> {
|
||||||
let mut insn_addr;
|
let mut insn_addr;
|
||||||
let mut curr_instr;
|
let mut curr_instr;
|
||||||
|
|
||||||
|
// seek to syscall
|
||||||
loop {
|
loop {
|
||||||
prev_regs = ptrace::getregs(pid)?;
|
prev_regs = ptrace::getregs(pid)?;
|
||||||
insn_addr = prev_regs.rip;
|
insn_addr = prev_regs.rip;
|
||||||
|
@ -64,19 +88,24 @@ pub fn pwn(pid: Pid, _word_size: usize) -> Result<()> {
|
||||||
// ptrace::write(pid, insn_addr, syscall_insn.as_slice().as_ptr() as *mut c_void)?;
|
// ptrace::write(pid, insn_addr, syscall_insn.as_slice().as_ptr() as *mut c_void)?;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
let msg = send_str(pid, insn_addr, "injected!\n\0")?;
|
||||||
|
|
||||||
let mut call_regs = prev_regs.clone();
|
let mut call_regs = prev_regs.clone();
|
||||||
|
|
||||||
// call_regs.rip = insn_addr;
|
call_regs.rip = insn_addr;
|
||||||
prepare_exit(&mut call_regs, 69);
|
|
||||||
|
prepare_write(&mut call_regs, 1, msg, 10);
|
||||||
ptrace::setregs(pid, call_regs)?;
|
ptrace::setregs(pid, call_regs)?;
|
||||||
ptrace::step(pid, None)?;
|
ptrace::step(pid, None)?;
|
||||||
waitpid(pid, None)?;
|
waitpid(pid, None)?;
|
||||||
|
// println!("Written payload to stdout on tracee");
|
||||||
|
|
||||||
// restore code and registers
|
// restore code and registers
|
||||||
// unsafe {
|
// unsafe {
|
||||||
// ptrace::write(pid, insn_addr, prev_instr.as_ptr() as *mut c_void)?;
|
// ptrace::write(pid, insn_addr, prev_instr.as_ptr() as *mut c_void)?;
|
||||||
// }
|
// }
|
||||||
// ptrace::setregs(pid, prev_regs)?;
|
|
||||||
|
ptrace::setregs(pid, prev_regs)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ fn prepare_for_syscall(regs: &mut user_regs_struct, rax: u64, rdi: u64, rsi: u64
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn prepare_mmap(regs: &mut user_regs_struct, addr: u64, len: u64, prot: u64, flags: u64, fd: u64, off: u64) {
|
pub fn prepare_mmap(regs: &mut user_regs_struct, addr: u64, len: usize, prot: i32, flags: i32, fd: u64, off: u64) {
|
||||||
prepare_for_syscall(regs, 9, addr, len, prot, flags, fd, off);
|
prepare_for_syscall(regs, 9, addr, len as u64, prot as u64, flags as u64, fd, off);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -21,8 +21,8 @@ pub fn prepare_open(regs: &mut user_regs_struct, filename: &str, flags: u64, mod
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn prepare_write(regs: &mut user_regs_struct, fd: u64, buf: &str, count: usize) {
|
pub fn prepare_write(regs: &mut user_regs_struct, fd: u64, buf: usize, count: usize) {
|
||||||
prepare_for_syscall(regs, 1, fd, buf.as_ptr() as u64, count as u64, 0, 0, 0);
|
prepare_for_syscall(regs, 1, fd, buf as u64, count as u64, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
|
Loading…
Reference in a new issue