用gdb调试ret2syscall
题目本身并不难,但是坑还是有的,我们重点关注gdb的使用
eg ctfshow pwn71(32位ret2sycall)
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
本题是静态编译,函数很多,自然想到ret2syscall。在v4存在明显栈溢出漏洞
这里的坑是ida给的这个0x64的偏移实际上是不准的,需要我们用gdb算一下
用gdb计算偏移量
我们先不需要写exp,直接gdb程序即可

先用cyclic 200生成一堆垃圾数,复制下来,或者自己手动打一堆aaaaaaa……也可以
在gets函数前随便找个地方下断点,然后按r,走到gets输入的地方,把那一堆垃圾数据粘贴并发送过去
然后用这个指令计算偏移
cyclic -l <EIP/RIP的值>

得到偏移量为112
灵活使用gadget
下一步是用ROPgetgad查找pop寄存器,但是我们不可能每次都正好找到完美符合条件的

这题我们是没法找到单独的pop ecx的,只有一段和ebx连在一起的gadget,不过也可以用,把二者合起来就是了
exp如下
1 | from pwn import * |
用gdb观察程序流程

可以看到栈上已经被覆盖了参数
我们重点看汇编窗口
可以看到四个寄存器已经按照我们payload写的顺序那样,依次被执行对应的操作,
这里的payload的顺序不重要,因为int80会聪明的自己按照顺序去寻找对应的寄存器,所以只需要保证寄存器的内容正确即可

我们走到int80,输入i r查看所有寄存器,发现每个寄存器都完美的执行了我们想要的操作
我们也可以在main函数ret的时候用下面的指令查看
x/10wx $esp
意思是查看(x)栈顶指针($esp)位置开始的 10 个(10)单位的数据,每个单位是 4 字节(w),并用十六进制(x)显示出来

我们继续按c走完,成功得到shell
使用gdb的注意事项
1.gets函数是在接收到换行符才会停止输入,所以我们必须用sendline去发payload,如果用send会导致发送完payload后程序还在等待我们输入,直接卡死
2.我们通过exp去打开gdb时要按c走到断点,千万不能按r,因为程序已经运行了,如果再按一遍r相当于重开了一个新的程序
3.我们手动输入时,一值n到gets,这时候gdb窗口会换行,这就在提示我们需要输入了,但我们千万不要在gdb窗口输入,而应该去程序执行的窗口输入,否则gdb会卡死






