首先在将题目下载之后还是例行的检查文件的属性和保护措施:
这里说明目标是一个x86架构下64位的小端ELF文件,同时与前两道题不同的是开了栈不可执行的保护(也就是NX),也就说明这道题ret2shellcode就不行(虽然没怎么用过)
然后我们打开ida看看这个程序:
主程序没什么好看的,这里是必进func函数的,主要功能应该还是func函数里实现
点进func函数,可以看到一个gets函数,就是本题的溢出点,之后细看一下该函数进行了一次判断,比较成功则执行system函数
在这里就有大体的三种思路:
1、常规的在func函数返回时ret到system函数,可以返回到这里调用system(“cat /flag”),也可以构造ROP链拿shell,显然前者简单,后者没必要,在后面具体操作会说明
2、第二种是一种突发奇想,既然是比较,那我直接修改源文件让你比较失败则执行就可以了,但是只针对线下破解,线上当然不行,后面具体操作会说明
3、既然你要比较v2,v2作为局部变量也在栈中,直接通过溢出把11.28125写到栈里也可以过,这种方式本人懒惰,交于读者
具体操作:
0、为保真实性,在根目录下放了一个flag:
1、开始动态调试:
我们将断点下在func函数上,也就是
b *0x400676
然后“n”到gets函数,随便输点什么看栈空间
可见ret在df18,我们输入的“aaaaaaa”在dee0
所以我们的垃圾数据就是56个
这里我们在溢出了垃圾数据后的ret地方不可以直接填system函数的地址,system函数也是需要参数,所以我们跳到system(“cat /flag”)的地方:
形成exp.py如下:
from pwn import *
#io = gdb.debug('./ciscn_2019_n_1','break *0x400676')
io = process('./ciscn 2019_n_1')
sys = 0x4006be
payload = b'a'* 56 + p64(sys)
print(payload)
io.sendline(payload)
io.interactive()
成功:
2、在本地破解:
该函数的逻辑是比较成功则执行system,在汇编上体现为下面的“jnz”上
所以我们只需要取个反:比较失败则执行system
Edit->keypatch->patcher
Edit->Patch program -> apply patches to inputc file
更改后如下:
直接执行,随便输入:
成功