BBUCTF-ciscn_2019_es_2(一道题浅析栈迁移)
在遇到栈迁移前,我其实对栈的理解处于一个十分粗浅的境界,仿佛一片未经开垦的荒地。作一篇以记录我的理解过程。
在之前的学习,我们可以通过栈迁移来让函数返回到我们想要去的地址进而达到我们的目的,但是,如果我们覆盖的空间有限,甚至除了垃圾数据我们只能填入函数地址和返回地址时,就可以采取栈迁移这一手法。
附上我觉得容易理解且讲解清楚的链接https://bbs.pediy.com/thread-258030.htm
https://bbs.pediy.com/thread-266927.htm
栈迁移主要用的就是利用 leave;ret; 这样的 gadgets。leave相当于 move exp,ebp(把ebp赋给esp);pop ebp(将栈顶的值弹到ebp上而且esp=esp+4);ret相当于pop eip(将esp指向的地址存放的值赋值给eip并且执行)。程序调用完成 call 返回的时候就会有这样的指令mov esp,ebp;pop ebp;ret 如果之前我们通过栈溢出将ebp改成了我们想要迁移的地址即bss段,这时执行完pop ebp;之后就会使得ebp指向bss段的地址。之后执行ret指令也就是pop eip;如果我们之前把这里的返回地址改成leave_ret这个gadget的话那么他又会执行上面我说的这些过程leave指令会导致esp指向bss段也就是刚刚ebp所指的地址。然后ebp会被改成指向新的一个给定的地址,同时esp也会指向target function(一般为system函数,因为要取得控制权嘛)
再执行 ret 指令,这时候程序就会执行 target function。总的来说,我们用了很短的长度,可以成功构造一个完整长度的rop。
回到题目
check一下

ida查看,emmvul函数有点东西

s的长度时0x28,但是两次read可以进去0x30,但是实在是长度太短了,只够我们覆盖ebp和返回地址的值。存在system函数,但是参数不是/bin/sh,我们也无法栈溢出更改返回地址的同时填入参数,现在就试试栈迁移的舞台了。
1.找到ebp和buf在栈上的位置
printf函数在输出的时候遇到’\0‘会停止,如果我们将参数s全部填满,这样就没法在末尾补上’\0‘,那样就会将ebp连带着输出
之后我们输入bbbb,然后看一下栈的情况,找到偏移
2.构造payload劫持栈
找一下leave指令

栈的执行情况



第二次执行后ebp里面是aaaa,esp指向system的地址,成功执行system函数。多说一句那个ebp-0x28那里的意思是在那个位置写入/bin/sh
我们写入的payload完成了他的使命!
附上payload和运行结果

多说一句废话,我现在还不会调试还有救吗?

浙公网安备 33010602011771号