【问题标题】:Buffer overflow issue: array is shorter than it should be?缓冲区溢出问题:数组比应有的短?
【发布时间】:2013-12-09 12:34:10
【问题描述】:

我现在正在我的系统编程课上做一个处理缓冲区溢出的练习。由于我无法正确格式化问题陈述,我将对其进行解释。我们有一个大小为 512 个字符的缓冲区。调用名为 getbufn 的函数分配此缓冲区,然后调用 Gets() 函数来接收输入。输入以十六进制值的形式出现在由空格分隔的文本文档中,该文本文档通过另一个提供的程序运行以产生输入。一旦通过gets将输入输入到缓冲区中,getbufn设置eax = 1并返回一个测试函数来检查堆栈是否已损坏。

现在我已经让这个工作了。在最后一个问题中,缓冲区大小为 32,并且设置了堆栈。现在堆栈可以移动了。调用 getbufn 的代码首先在堆栈上分配一个随机数量的存储空间,因此如果您在两次连续执行 getbufn 期间对 %ebp 的值进行采样,您会发现它们的差异高达 ±240。所以我们需要使用 NOP sled 来让我们的代码工作。

首先,这里是getbufn函数:

80491e8:       55                      push   %ebp
80491e9:       89 e5                   mov    %esp,%ebp
80491eb:       81 ec 18 02 00 00       sub    $0x218,%esp
80491f1:       8d 85 f8 fd ff ff       lea    -0x208(%ebp),%eax
80491f7:       89 04 24                mov    %eax,(%esp)
80491fa:       e8 db fa ff ff          call   8048cda <Gets>
80491ff:       b8 01 00 00 00          mov    $0x1,%eax
8049204:       c9                      leave  
8049205:       c3                      ret    
8049206:       90                      nop
8049207:       90                      nop

我发现了一些东西。当在地址 0x8049205 调用 ret 时,esp = 0x556832F4。所以我知道退货地址在那里。在 lea 之后的 mov 指令中,ebp 总是等于 0x556832F0(所以我不知道我的 prof 移动 240 是什么意思),而 eax 总是等于 0x556830e8。对我来说,这意味着我的数组从 0x556830e8 开始,到 0x556832E8 结束。然后要获得返回地址,我应该多写 12 个字节才能到达 0x556832F4。那么最后 4 个字节应该是 NOP sled 中间的地址。

所以现在我拥有的是 ~500 NOP OPS,然后是缓冲区末尾的代码 - 这使得总大小为 512 以填充数组。然后我有 12 个字节的十六进制与缓冲区溢出之前这些地址的堆栈中最初的内容相匹配。然后,当返回指令在 getbufn 结束时执行时,我还有 4 个字节指向 NOP 雪橇中间的地址。由于某种原因,这不起作用。如果我在我的数组和返回地址之间放置 5 个字节的垃圾,我就会发现堆栈已损坏。如果我在我的数组和返回值之间放置 6 个字节的垃圾,我会遇到分段错误。在我的计算中,我认为我需要 12 个字节才能从数组到返回地址,所以我在这里做错了什么?

【问题讨论】:

  • 提供您的 C 代码示例。 (假设您正在生成 C 作为 post 标记它。)问题可能会更明显。

标签: c stack buffer overflow


【解决方案1】:

这听起来很像 Bryant 和 O'Hallaron 的 CS:APP 缓冲区溢出实验室,听起来也像是最后一关。

让我给你一些指点:

  1. 堆栈仍然是可执行的。
  2. 您知道缓冲区约为 512 字节,(可能更多用于对齐,当我执行此分配时,它是 540 字节)
  3. 您知道$ebp 的差异不会超过 +/- 240 个字节。
  4. 您知道将调用一个函数来验证堆栈

因此,了解所有这些后,您可以执行以下操作:

  1. 将 shell 代码放入该 512 字节的缓冲区中。
  2. 一些 NOPS 可让您跳转到缓冲区中的某个随机点(由于 +/- 240 ASLR,这很重要)
  3. 在该缓冲区中,您可以有一些 shell 代码读取 $esp 并将 512 字节(或缓冲区的实际大小)添加到 $esp,这将为您提供已保存 @ 的值987654324@你覆盖了。然后,您可以进行一些计算,并将垃圾 ebp 替换为您刚刚计算的正确值。
  4. 回到你需要去的地方。

进一步解释一些事情。为什么我们需要缓冲区中的 NOP (\x90)?由于基地址随机化 +/- 240 字节并且缓冲区大小为 512 字节,因此您可以进行计算并确定性地始终返回到缓冲区中的某个位置。当您返回缓冲区中的某个位置时,它会触发 NOPS (\x90) 并滑入您的 shell 代码。

如果您还有其他问题,请随时提出。

【讨论】:

  • 我想我对阅读 ebp 部分有点困惑。我实际上是如何跳转到我的 shell 脚本的?目前,我只是在最后用 NOP 和我的代码填充我的缓冲区,然后将 getbufn 的 ret 地址更改为应该在缓冲区中的随机地址。我在缓冲区中的代码应该将 eax 更改为我的 cookie 值,将原始返回地址重写为上面找到的 esp 位置,将原始返回地址压入堆栈并执行返回指令。我不完全理解 -+ 240 是如何生效的。
  • @SeanK +/- 240 发挥作用,因为在之前的关卡中,您可以查看程序集并确定缓冲区的确切位置,然后您可以将返回地址放入缓冲区。但是由于它现在有所不同,因此您必须通过这 240 个字节来“猜测”它会在哪里。所以这就是为什么他们给了你一个巨大的缓冲区来玩,所以当你猜到你会进入 shellcode 时。所以应该是这样的
  • 你写出你的shell代码看起来像这样[nop sled------- mov ebp esp+512;移动 eax cookie; ret finish_level_addr;此处的垃圾覆盖已保存的 ebp,然后将返回地址放入缓冲区 no-op sled] 您可以通过在 gdb 中运行几次并查看每次缓冲区开始的位置来计算返回的位置。您会看到它从某个地址开始,相差 240 个字节。然后,您可以在这些地址之间进行选择,您很有可能会跳入 nop 雪橇
  • 我想我现在真的很接近了,但我仍然找不到 ebp 从运行到运行的变化。 lea 指令后数组的起始地址应该在 eax 中吗?到目前为止,我已经在 gdb 中多次运行该程序,并且 eax 始终指向 0x556830e8。我实际上无法找到 240 偏移发生的位置,这让我感到困惑。在 Gets() 运行后检查 ebp 也总是返回相同的地址。我不记得了,但这意味着数组也在同一个位置结束,对吗?
  • @SeanK 在 gdb 运行期间执行 ir ebp ,它将显示 ebp 是什么。您应该看到它为运行而运行。是的,它应该将地址加载到 eax 中。
猜你喜欢
  • 1970-01-01
  • 2013-07-19
  • 2019-06-20
  • 2022-01-03
  • 2019-08-15
  • 1970-01-01
  • 2015-12-16
  • 1970-01-01
  • 2010-11-11
相关资源
最近更新 更多