0.前言&回顾
简单的栈转移,但是我不清楚为什么给的system我用不了……(可能只是因为我菜)(据学长说是因为system函数执行时有栈方面的对齐要求,我简单了解了一下似乎是有某字节倍数的要求才能正常调用,具体的我目前也不是很了解,以后补充。),所以我用的还是execv。此题和之前ret2csu的有些类似,只是需要进行栈转移。
我们知道,leave的实质是mov rsp,rbp;pop rbp。而ret的实质是pop rip。
1.栈转移的原因及方法
1-1.原因
由于程序中存在栈溢出漏洞,但可以溢出的长度又受到限制,不足以让我们完成整个rop。这时候就需要把栈转移到长度足够的可以操作的段上。(例如.bss)把事先写好的rop注入到我们需要转移到段上,这样就可以继续达成我们的目的。
1-2.方法
我们知道,栈是由rbp和rsp决定的,尤其是后者。可以说,rsp在哪,栈就在哪。因此,我们只需要想办法把rsp指针转移到我们需要的地方即可。而想要改变rsp的值,可以先通过改变rbp的值,再把rbp的值传递给rsp就可以达到栈转移到目的。
主要有两种方式:
1 | pop rbp;ret+target stack addr+leave;ret |
2.例子
本题用到的ELF文件:点击下载
简单重复的略过。
IDA中可以观察到存在栈溢出漏洞,但read读取的字节不够我们完成rop,这时候需要进行栈溢出。
注意到global_buf这段缓冲区的长度足够。
因此我们的目标就是用我们需要的rop去填充这段缓冲区,再把栈转移到这段缓冲区上,程序就会执行我们事先写好的rop。
用ropper可以找到leave;ret这个gadget。如图:
程序中有 __libc_csu_init() 函数,如图。因此这里我采用的是通用gadget的方法。(当然不止可以构建这一种rop就是)
在got段中可以找到execv的地址。
思路拟好后,脚本就好写了。这里提供一种脚本写法:
1 | from pwn import * |
解释一下,因为本程序中不存在“/bin/sh”这个字符串,因此需要自己写入缓冲区中。又因为在执行leave时会有一个pop rbp的过程,因此先将“/bin/sh”读入缓冲区,这样它就会被pop进rbp中,此时rsp就会指向下一个区域。这样 既可以读入“/bin/sh”,还把这段字符串放在了栈之外,使之不会受到影响。 可谓是一举两得。
运行该脚本即可取得shell。