栈迁移
仅供个人学习参考
背景及原理
我们在栈溢出时,有时候会碰到可供写入的字节数不够,比如只溢出到retaddr后面一点点,不够我们构造payload,这个时候可以考虑使用栈溢出
栈帧
先回顾一下栈帧的概念,栈帧也叫过程活动记录,是编译器用来实现函数调用过程的一种数据结构。C语言中,每个栈帧对应着一个未运行完的函数。从逻辑上讲,栈帧就是一个函数执行的环境:函数调用框架、函数参数、函数的局部变量、函数执行完后返回到哪里等等。栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低地址)
栈溢出实现关键在于对ebp和esp的控制,也就是说,我们劫持esp和ebp,构造出一个新的栈帧,让系统执行这个栈帧。对于ebp来说,我们可以通过修改previous of ebp 这个位置的内容来控制,对于esp,则有leave这个指令,leave等同于mov esp ebp和pop ebp (可以通过ROPgadget来找)
例题
以ciscn_2019_es_2这题为例
可以看到在vul函数中,我们利用read可以读入的数据只有0x30,显然不够构造一次完整的payload,所以我们考虑栈迁移
第一次read用于泄露old ebp的地址,第二次来构造栈迁移
exp如下:
1 | from pwn import * |
第二次的payload前面的’aaaa’是因为执行leave后(其中的pop ebp)会导致esp的值增长一个字长,如下图
执行完leave指令(我们填入的leave)后的情况:
ebp里面是aaaa,esp指向system的地址,成功执行system函数
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.