堆溢出的危险

dangers of heap overflows?

本文关键字:危险 溢出      更新时间:2023-10-16

我有一个关于堆溢出的问题。

我知道,如果堆栈变量超过了它的缓冲区,它可能会覆盖EIP和ESP值,例如,使程序跳转到编码器不希望它跳转的地方

据我所知,这似乎是因为向后的小端存储(例如,数组中的字符从最后到第一"向后"存储)

另一方面,如果您将该数组放入堆中,堆会随着堆栈的增长而增长,并且您会使其溢出,那么它会将随机垃圾写入空内存空间吗
(除非你在solaris上,据我所知,solaris有一个big-endian系统,旁注)
这基本上会是一个危险吗,因为它只会写入"空白">
所以没有目标跳转到代码不是为之设计的地址和区域
我弄错了吗

为了说明我的问题:
我正在编写一个程序,其中用户在通过命令行执行时要传递一个字符串参数和一个标志,我想知道当使用malloc函数将该字符串参数放入堆中时,用户是否可以使用该字符串参数执行破解

如果另一方面将该数组放入堆中,堆会随着堆栈的增长而增长,并且会使其溢出,那么它会将随机垃圾写入空内存空间吗?

您正在做几个假设:

  1. 您假设堆位于主内存段的末尾。不一定。

  2. 您假设堆中的对象位于堆的末尾。这不一定。(事实上,它通常不是所以…)

以下是一个无论堆如何实现都可能导致问题的示例:

char *a = malloc(100);
char *b = malloc(100);
char *c = malloc(100);
for (int i = 0; i < 200; i++) {
b[i] = 'Z';
}

写超过b的末尾可能会践踏ac。。。或者堆中的某个其他对象,或者空闲列表。

根据你践踏的对象,你可能会覆盖函数指针,或者你可能会造成其他损坏,导致分段错误、不可预测的行为等等。这些东西可能被用于代码注入,导致代码以其他方式故障,从安全角度来看是有害的。。。或者只是通过崩溃目标应用程序/服务来实现拒绝服务攻击。

堆溢出可能导致代码执行的方式多种多样:

  • 最明显的是,您溢出到另一个包含函数指针的对象中,并覆盖其中一个
  • 稍微不那么明显——您溢出到的对象本身不包含函数指针,但它包含将用于写入的指针,您可以覆盖其中一个指针以指向函数指针,以便后续写入覆盖函数指针
  • 利用堆记账结构——通过覆盖堆分配器本身用来跟踪已分配/空闲块的大小和状态的数据,可以欺骗它覆盖内存中其他有价值的东西
  • 等等

有关一些高级技术,请参阅:

http://packetstormsecurity.com/files/view/40638/MallocMaleficarum.txt

即使您无法覆盖返回地址,您对攻击者修改您的其余数据有何感受?这不应该让你激动。

一般来说,要回答您的问题:让用户在不检查数据大小的情况下将复制到的任何位置是一个非常糟糕的主意。你绝对不应该那样做,尤其是故意的。

如果用户没有恶意,他们可能会覆盖有用的数据或导致页面错误,从而使您的程序崩溃。如果你的用户是恶意的,你可能会让他们劫持你的系统。两者都是极不可取的。

持久性与缓冲区溢出无关。大端序机器和小端序机器一样容易受到攻击。唯一的区别是恶意数据的字节顺序。

您可能考虑的不是堆栈的生长方向,而是独立于endianness的方向。在它长大的情况下,您将无法劫持声明缓冲区的函数的返回地址。但是,如果将该缓冲区地址传递给任何其他函数,而该函数却发生溢出,则攻击者可能会更改该函数的返回地址。例如,如果调用scanfmemcpy或任何其他函数来修改缓冲区(假设编译器没有内联它们),就会出现这种情况。

烟囱通常向下生长。在这种情况下,攻击者可以使用溢出劫持声明它的函数的返回地址

换言之,无论是堆栈配置还是端序都不能提供针对堆栈缓冲区溢出的有意义的保护。

至于堆:

另一方面,如果你把这个数组放进堆中,堆会随着堆栈的增长而增长,并且你会溢出它,那么它会把随机垃圾写入空内存空间吗?

答案几乎总是这取决于,但可能不是。glibc中malloc的32位实现将记账结构保留在缓冲区的末尾(或者至少习惯于)。当分配为freed时,通过用正确的咒语溢出到记账结构上,可以使free在任意位置写入四个任意字节。这是很大的力量。这种利用在夺旗比赛中经常出现,而且非常容易利用。