feat: RemoteOp trait, RemoteShellcode struct
This commit is contained in:
parent
7029a048af
commit
4e4aceb092
4 changed files with 91 additions and 37 deletions
5
src/needle/injector.rs
Normal file
5
src/needle/injector.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
use nix::{Result, unistd::Pid};
|
||||||
|
|
||||||
|
pub trait RemoteOperation {
|
||||||
|
fn inject(&mut self, pid: Pid, syscall: usize) -> Result<u64>;
|
||||||
|
}
|
|
@ -1,10 +1,14 @@
|
||||||
mod syscalls;
|
mod syscalls;
|
||||||
|
mod rce;
|
||||||
mod operations;
|
mod operations;
|
||||||
|
mod injector;
|
||||||
|
|
||||||
|
use injector::RemoteOperation;
|
||||||
use nix::{Result, {sys::{ptrace, wait::waitpid}, unistd::Pid}};
|
use nix::{Result, {sys::{ptrace, wait::waitpid}, unistd::Pid}};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use operations::step_to_syscall;
|
use operations::step_to_syscall;
|
||||||
use syscalls::{RemoteString, RemoteWrite, RemoteSyscall};
|
use rce::{RemoteString, RemoteShellcode};
|
||||||
|
use syscalls::RemoteWrite;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
|
@ -20,8 +24,10 @@ struct NeedleArgs {
|
||||||
pub fn nasty_stuff(pid: Pid, _word_size: usize) -> Result<()> {
|
pub fn nasty_stuff(pid: Pid, _word_size: usize) -> Result<()> {
|
||||||
let original_registers = ptrace::getregs(pid)?;
|
let original_registers = ptrace::getregs(pid)?;
|
||||||
let syscall_addr = step_to_syscall(pid)?;
|
let syscall_addr = step_to_syscall(pid)?;
|
||||||
let msg = RemoteString::new(pid, syscall_addr, "injected!\n\0".into())?;
|
let mut msg = RemoteString::new("injected!\n\0".into());
|
||||||
RemoteWrite::args(1, msg).syscall(pid, syscall_addr)?;
|
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)?;
|
ptrace::setregs(pid, original_registers)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
54
src/needle/rce.rs
Normal file
54
src/needle/rce.rs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RemoteShellcode<'a> {
|
||||||
|
code: &'a [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RemoteShellcode<'a> {
|
||||||
|
pub fn new(code: &'a [u8]) -> Self {
|
||||||
|
RemoteShellcode { code }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemoteOperation for RemoteShellcode<'_> {
|
||||||
|
fn inject(&mut self, pid: Pid, syscall: usize) -> Result<u64> {
|
||||||
|
let original_regs = ptrace::getregs(pid)?;
|
||||||
|
let ptr = RemoteMMap::args(
|
||||||
|
0, self.code.len(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0
|
||||||
|
).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
|
||||||
|
let mut regs = original_regs.clone();
|
||||||
|
regs.rip = ptr;
|
||||||
|
ptrace::setregs(pid, regs)?;
|
||||||
|
ptrace::cont(pid, None)?;
|
||||||
|
waitpid(pid, None)?;
|
||||||
|
ptrace::setregs(pid, original_regs)?;
|
||||||
|
Ok(ptr)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,36 +1,10 @@
|
||||||
use nix::{libc::{user_regs_struct, MAP_PRIVATE, MAP_ANON, PROT_READ, PROT_WRITE}, Result, sys::{ptrace, wait::waitpid}, unistd::Pid};
|
use nix::{libc::user_regs_struct, Result, sys::{ptrace, wait::waitpid}, unistd::Pid};
|
||||||
|
|
||||||
use crate::operations::write_buffer;
|
use crate::{rce::RemoteString, injector::RemoteOperation};
|
||||||
|
|
||||||
pub struct RemoteString {
|
|
||||||
pub ptr: usize,
|
|
||||||
pub txt: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RemoteString {
|
|
||||||
pub fn new(pid: Pid, syscall: usize, txt: String) -> Result<Self> {
|
|
||||||
let ptr = RemoteMMap::args(
|
|
||||||
0, txt.len(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0xFFFFFFFFFFFFFFFF, 0
|
|
||||||
).syscall(pid, syscall)? as usize;
|
|
||||||
write_buffer(pid, ptr, txt.as_bytes(), 32)?; // TODO don't hardcode word size
|
|
||||||
Ok(RemoteString { ptr, txt })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait RemoteSyscall {
|
pub trait RemoteSyscall {
|
||||||
fn registers(&self, regs: &mut user_regs_struct);
|
fn registers(&self, regs: &mut user_regs_struct);
|
||||||
|
|
||||||
fn syscall(&self, pid: Pid, addr: usize) -> Result<u64> {
|
|
||||||
let mut regs = ptrace::getregs(pid)?;
|
|
||||||
regs.rip = addr as u64;
|
|
||||||
self.registers(&mut regs);
|
|
||||||
ptrace::setregs(pid, regs)?;
|
|
||||||
ptrace::step(pid, None)?;
|
|
||||||
waitpid(pid, None)?;
|
|
||||||
regs = ptrace::getregs(pid)?;
|
|
||||||
Ok(regs.rax)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare_registers(regs: &mut user_regs_struct, rax: u64, rdi: u64, rsi: u64, rdx: u64, r10: u64, r8: u64, r9: u64) {
|
fn prepare_registers(regs: &mut user_regs_struct, rax: u64, rdi: u64, rsi: u64, rdx: u64, r10: u64, r8: u64, r9: u64) {
|
||||||
regs.rax = rax;
|
regs.rax = rax;
|
||||||
regs.rdi = rdi;
|
regs.rdi = rdi;
|
||||||
|
@ -42,24 +16,39 @@ pub trait RemoteSyscall {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> RemoteOperation for T where T: RemoteSyscall {
|
||||||
|
fn inject(&mut self, pid: Pid, syscall: usize) -> Result<u64> {
|
||||||
|
let mut regs = ptrace::getregs(pid)?;
|
||||||
|
regs.rip = syscall as u64;
|
||||||
|
self.registers(&mut regs);
|
||||||
|
ptrace::setregs(pid, regs)?;
|
||||||
|
ptrace::step(pid, None)?;
|
||||||
|
waitpid(pid, None)?;
|
||||||
|
regs = ptrace::getregs(pid)?;
|
||||||
|
Ok(regs.rax)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct RemoteMMap {
|
pub struct RemoteMMap {
|
||||||
addr: u64,
|
addr: u64,
|
||||||
len: usize,
|
len: usize,
|
||||||
prot: i32,
|
prot: i32,
|
||||||
flags: i32,
|
flags: i32,
|
||||||
fd: u64,
|
fd: i64,
|
||||||
off: u64,
|
off: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl RemoteMMap {
|
impl RemoteMMap {
|
||||||
pub fn args(addr: u64, len: usize, prot: i32, flags: i32, fd: u64, off: u64) -> Self {
|
pub fn args(addr: u64, len: usize, prot: i32, flags: i32, fd: i64, off: u64) -> Self {
|
||||||
RemoteMMap { addr, len, prot, flags, fd, off }
|
RemoteMMap { addr, len, prot, flags, fd, off }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RemoteSyscall for RemoteMMap {
|
impl RemoteSyscall for RemoteMMap {
|
||||||
fn registers(&self, regs: &mut user_regs_struct) {
|
fn registers(&self, regs: &mut user_regs_struct) {
|
||||||
Self::prepare_registers(regs, 9, self.addr, self.len as u64, self.prot as u64, self.flags as u64, self.fd, self.off);
|
Self::prepare_registers(regs, 9, self.addr, self.len as u64, self.prot as u64, self.flags as u64, self.fd as u64, self.off);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,8 +66,8 @@ impl RemoteOpen {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RemoteSyscall for RemoteOpen {
|
impl RemoteSyscall for RemoteOpen {
|
||||||
fn registers(&self, regs: &mut user_regs_struct) {
|
fn registers(&self, regs: &mut user_regs_struct) { // TODO handle this unwrap
|
||||||
Self::prepare_registers(regs, 2, self.filename.ptr as u64, self.flags, self.mode, 0, 0, 0);
|
Self::prepare_registers(regs, 2, self.filename.ptr.unwrap() as u64, self.flags, self.mode, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +84,7 @@ impl RemoteWrite {
|
||||||
|
|
||||||
impl RemoteSyscall for RemoteWrite {
|
impl RemoteSyscall for RemoteWrite {
|
||||||
fn registers(&self, regs: &mut user_regs_struct) {
|
fn registers(&self, regs: &mut user_regs_struct) {
|
||||||
Self::prepare_registers(regs, 1, self.fd, self.buf.ptr as u64, self.buf.txt.len() as u64, 0, 0, 0);
|
Self::prepare_registers(regs, 1, self.fd, self.buf.ptr.unwrap() as u64, self.buf.txt.len() as u64, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue