栈溢出简介
函数中的存储在栈中的局部变量数组边界检查不严格发生越界写,造成用户输入覆盖到缓冲区外的数据内容,
由于栈中同时存在着与函数调用参数的相关信息,栈溢出可以导致控制流劫持
基础栈溢出(hello world in pwn)
多数情况下我们需要让程序执行这一段代码般来说,在CTF中的PWN,
system("/bin/sh"");
也就是说在远程机器上开一个命令行终端
这样我们就可以通过命令行来控制目标机器
通常来说,CTF比赛中只需要开启命令行后读flag(cat flag)
ret2text
Return to text,控制程序的返回地址到原本程序中的函数(代码)。
例如程序中有类似function:
- system(‘/bin/sh’)
- execve(‘/bin/sh’,NULL,NULL)
就可以跳转到这个function,function的地址可以通过objdump或者ida来查找。
理想情况下,程序中有一段代码能直接满足我们的需求,
我们只需要将执行流劫持到这一段代码即可
例子
main函数调用b,b函数调用a。
缓冲区溢出发生在a函数中。
buf的长度为80,但是却读入了200长度。
分析程序运行至a时的栈帧
栈中存放buf和返回地址等等信息。
buf的长度为80,紧邻b函数的rbp指针和返回地址,
栈地址从高地址向低地址生长。
我们读入一段数据是从低地址向高地址读入。
这里我们读入'X’*80 +'A’*8 +'B’*8
可以看到,原本存储b函数的rbp地址内容已经被覆盖成了'AAAAAAAA‘
返回地址已经被覆盖为了'BBBBBBBB’
这时候,如果程序返回,程序会返回一个异常错误。
因为'BBBBBBBB’这个字符串,翻译到16进制:0x4242424242424242,这个地址在内存中不是一个合法的代码地址。
我们变换一下思路,这次我们输入的数据是:X’*80 +'A’*8 + target addr
target addrs是我们想要让程序跳转到的地方,
这时候,程序的执行流就被我们控制了
rbp
那么RBP我们就不管了吗?
是的,一般情况下,RBP的值我们不需要构造。
RBP是程序用来定位栈中的局部变量地址的。
除非涉及到RBP寄存器传递参数,一般的ROP不要管RBP.
具体情况具体分析。
总结
栈溢出的原理就是栈中存储的局部变量数组发生溢出,覆盖了栈中的其他数据将返回地址覆盖为我们期望的目标地址,即可劫持控制流
例题
int4个字节 4x20=80个字节
编写脚本