Level0
首先是test函数和getbuf函数以及smoke函数的c代码如下:
Level0 就很简单,就是本来test函数调用getbuf函数,调用完以后还返回test函数,现在我们要做的是调用getbuf函数后,通过输入我们的exploit,使得调用完以后不返回test函数了而是执行smoke函数。
这里的实现就很简单,只需要输入超出缓冲区大小的字符串来覆盖到getbuf的返回地址那块地方,将返回地址用smoke函数的入口地址来覆盖就ok了。
那么就通过反汇编,结合栈的结构来看一下具体getbuf的返回地址在哪里(这里的具体分析可以去看我的那个关于函数调用的栈结构过程的文章):
这里getbuf的栈中而esp是开辟了0x28,换成10进制就是40个字节,但是push ebp占了4个字节,那么getbuf的栈空间一共是44个字节。
我们把test调用getbuf后的栈结构图画出来,(具体分布可以看我的那个关于函数调用的栈结构过程的文章)这里绿色是调用test函数的函数的栈,黄色是test的栈,蓝色是getbuf的栈,返回地址是输入调用者的栈的结构的。
在这里就可以看到返回地址在保存的ebp上面4个字节,所以我们用40个0来填充满buf,然后再4个0覆盖掉保存的ebp的内容,也就是44个0覆盖掉所有的蓝色,再向上然后紧接着在用smoke的入口地址来覆盖返回地址。
在这里首先是getbuf栈执行leave后:
紧接着是执行ret,正常的ret就是下一条执行指令的地址,这里我们把他换成了smoke的入口函数,那么就是去执行smoke了。
这里看到smoke的入口地址,最后是0x0a,我们前面的注意事项中已经分析了,0x0a是换行\n的ASCII值,所以不可以输入,那么我们就输入0x8048e0b来代替。
本来执行smoke,smoke又会和getbuf一样重新建立一个栈,但是这里我们只需要我们去执行smoke,执行完以后不需要他进一步的返回到哪里做哪些事情,多以本来push ebp(test的ebp,但是在getbuf那个时候我们已经把保存在getbuf栈中的原test函数的ebp给破坏了,所以也不能恢复到test了)所以这里有没有这个push ebp已经不重要了,因为无法还原现场了。所以我们的solution应该是:
我们用40个0来填充满buf,然后再4个0覆盖掉保存的ebp的内容,然后紧接着在用smoke的入口地址来覆盖返回地址。
记下来我们用:./hex2raw <level0.txt |./bufbomb -u syq 进行一下验证
接下来我们用图来看一下执行smoke函数的栈过程,这里首先是假如0x0a对输入没有影响的情况,也就是会push ebp。这里尤其要注意,这里不是用的call指令,而是直接执行的,所以会和getbuf的栈有所不同,不会系统自动push返回地址。此处蓝色代表smok的栈结构,区别就是没有push返回地址。而且保存的ebp也是被我们破坏了的。
然后是考虑到0x0a不行,我们换成了smoke函数入口的下一句的地址,也就是不进行push ebp。