XCTF-stack2-WP

Posted on Nov 4, 2020

这道题确实是给我整吐了。其实思路非常简单,就是通过数组越界来达到栈溢出,并且这样可以跨越canary,然后就可以控制程序的执行流程。

然后我们可以看到

这里有一个叫hackme的函数,这么嚣张,点进去看一下

呦呵直接给bash,那我就hack你吧。

然后再看一下主函数

发现这里有个数组越界,可以进行溢出。

然后我们算一下偏移,这里的偏移不能直接用0x70+4来算,为什么不能呢,是因为这个程序的栈帧生成方式是非常规的,我们来看一下

这是本程序的入口
这是一般程序的入口

会发现esp和0FFFFFFF0h的与操作的位置是不一样的

这是本程序的出口
这是一般程序的出口

所以我们可以发现他的栈帧生成是动过手脚的。

那么我们可以考虑在调试的时候算出偏移。首先我们看一下ida中的代码

发现他是先读入一个临时变量,再存到数组里面的。

对应的就是这两条语句。那么明显,v7就是cl(注意v13是char数组),那么eax就是数组v13的首地址了。

再到gdb里面下好断点(我下了两个,一个在mov [eax],cl上,另一个在ret上)然后在第一次输入数字后,可以看到

我们就得到了EAX的值,也就是数组的首地址。

类似的方法,我们可以获得retrun的地址

其实也不是很类似

然后相减就获得了正确的偏移0x84。

这个时候我很高兴的写好了exp,把返回地址变成了hackhere的地址,然后发现报错了,在主机上找不到bash,真是会玩。

那么我们只好自己调用system函数了,这里就出现了一个卡了我一个多小时的问题,

我一直尝试通过这里的地址调用system,结果程序总是没法进入那里。让我百思不得其解。(这大概只能体现我蠢,函数的真实地址应当是通过got表的到的。)于是我又补了一下got,plt表和延迟绑定机制的知识。在这里我只解释与题目有关的部分。

一方面,由于动态链接往往会装载大量的函数,处理这些函数的重定位并生成got表会在程序执行前花费大量的时间,所以ELF使用了延迟绑定机制。在函数被调用前都不进行绑定。那么如果先前没有执行过system的话,实际上system函数是可以说不存在的,那当然是无法调用的;另一方面,extern段,只是说明从外部会调用这些函数,并不是说这里就是函数的地址了。

所以我们只能通过调用代码段中的system来获得sh

接下来就是找sh的位置了,在ida里面shift+F12,找不到,到ROPgadaget中找一下

诶找不到

那我们就退一步吧,之前我还确实不知道可以直接用sh调出sh的哈哈哈

最好的exp就是这样了