最近我正在研究x86 buffer overflows +来自https://www.ret2rop.com/2018/08/return-to-libc.html的ret2libc攻击,我注意到顺序如下:
bytes to fill buffer + address of system + return address for system/address of exit + address of "/bin/sh"
我不明白为什么传递给系统的return address ( PC/EIP在调用和执行系统代码之后返回到系统)位于堆栈中/bin/sh的地址之前。从我所读到的内容来看,返回地址应该直接在/bin/sh/ system参数之后,但是在使用ret2libc攻击时,我看到的每个示例都遵循这个溢出顺序。在过程/函数返回的方式/它们返回的位置上,我缺少什么东西吗?为什么返回地址在/bin/sh之前而不是在buffer-overflow有效负载之后?
发布于 2020-11-26 07:58:05
这是因为在x86上,堆栈向下增长(朝向较低的地址),但是缓冲区向上填充(向更高的地址):
当写入缓冲区时,您正在敲击上面堆栈帧的返回地址,位于较高的地址。
然后,ret指令将弹出堆栈中的返回地址,并在system开始时继续执行。然后,system将将其参数从堆栈中弹出,返回时,从堆栈中弹出下一个函数的地址,即当您遍历链时堆栈缩小,堆栈指针变大。
/bin/sh地址可以写在堆栈上的原因是gcc在x86_32 linux上使用的呼叫约定,它非常接近undefined (参见图3-15)。相反,在x86_64上,第一个参数是在寄存器(rdi、rsi、rcx)中传递的,因此在返回到system之前,您需要一个pop rdi; ret小工具。
high addresses
+----------------+
| |
| arguments |
| |
+----------------+
esp -> | return address |
+----------------+
| |
| locals |
| |
+----------------+
low addresses把这些加到一个有效载荷上,我们得到:
high addresses
+----------------+ -+
| arg0 | |
+----------------+ | stack frame of system
| return address | exit |
+----------------+ -+
esp -> | return address | system |
+----------------+ |
| | ^ | stack frame of victim
| buffer | | overflow |
| | + |
+ . . . . . . . .+ :
low addresses被覆盖的缓冲区是受害者函数中的本地缓冲区,其返回地址被覆盖。ret指令将将堆栈中的返回地址弹出到eip中,因此在system中将继续执行。
此时,堆栈看起来如下所示,在esp下面的空间可供system用于其局部变量(实际上,图并不完全正确,因为system推送locals,堆栈指针当然会减少):
high addresses
+----------------+ -+
| arg0 | |
+----------------+ | stack frame of system
esp -> | return address | exit |
+----------------+ |
| | |
| locals | |
| | |
+ . . . . . . . .+ :
low addresses要访问参数,system将使用[reg+displacement]寻址模式来访问[esp+4]。在执行结束时,它将调用ret,后者将在exit中继续执行。
https://security.stackexchange.com/questions/241332
复制相似问题