16

在我们第一次关于安全性的 CS 讲座中,我们讨论了 C 的问题,即不检查所谓的缓冲区长度以及可以利用此漏洞的不同方式的一些示例。

在这种情况下,它看起来像是恶意读取操作的情况,应用程序只是读取了许多字节的内存

  1. 我断言 Heartbleed 错误是 C 缓冲区长度检查问题的表现是否正确?

  2. 为什么恶意使用在尝试读取另一个应用程序的内存时没有导致分段错误?

  3. 在写入内存(然后从内存读取)之前简单地将内存归零会导致分段错误吗?或者这在操作系统之间会有所不同吗?还是在其他一些环境因素之间?

  4. 显然无法识别对该错误的利用。那是因为心跳函数在调用时没有记录吗?否则肯定任何对 ~64k 字符串的请求都可能是恶意的?

4

2 回答 2

29

我断言 Heartbleed 错误是 C 缓冲区长度检查问题的表现是否正确?

是的。

heartbleed bug 是 C 中经典缓冲区溢出漏洞的表现吗?

不。“经典”缓冲区溢出是指您更多数据写入堆栈分配的缓冲区,而不是它可以容纳的数据,其中写入的数据是由敌对代理提供的。恶意数据溢出缓冲区并覆盖当前方法的返回地址。当该方法结束时,它会返回到包含攻击者选择的代码的地址并开始执行它。

相比之下,heartbleed 缺陷不会覆盖缓冲区,也不会执行任意代码,它只是读取内存中很可能在内存附近有敏感数据的代码中的边界。

为什么恶意使用在尝试读取另一个应用程序的内存时没有导致分段错误?

它没有尝试读取另一个应用程序的内存。该漏洞利用读取当前进程的内存,而不是另一个进程。

为什么恶意使用在尝试读取缓冲区边界之外的内存时没有导致分段错误?

这是这个问题的副本:

为什么这不会产生分段违规错误?

分段错误意味着您触摸了操作系统内存管理器尚未分配给您的页面。这里的错误是您触及了堆管理器尚未分配给您的有效页面上的数据。只要页面有效,就不会出现段错误。通常,堆管理器会向操作系统请求一大块内存,然后将其分配给不同的分配。就操作系统而言,所有这些分配都在有效的内存页面上。

取消引用 null 是一个段错误,因为操作系统永远不会使包含零指针的页面成为有效页面。

更一般地说:编译器和运行时不需要确保未定义的行为导致段错误;UB 可以导致任何行为,包括什么都不做。有关此问题的更多想法,请参阅:

可以在其范围之外访问局部变量的内存吗?

对于我都抱怨 UB应该始终等同于安全关键代码中的段错误,以及一些关于漏洞静态分析讨论的指针,请参阅今天的博客文章:

http://ericlippert.com/2014/04/15/heartbleed-and-static-analysis/

在写入内存(然后从内存读取)之前简单地将内存归零会导致分段错误吗?

不太可能。如果越界读取不会导致段错误,那么越界写入不太可能。一页内存可能是只读的,但在这种情况下似乎不太可能。

当然,将各种你不应该的内存归零的后果是整个节目的段错误。如果您稍后取消引用该归零内存中的指针,则取消引用 null 将产生段错误。

这在操作系统之间会有所不同吗?

问题很模糊。让我重新表述一下。

不同的操作系统和不同的 C/C++ 运行时库是否为分配虚拟内存、分配堆内存以及识别内存访问何时超出范围提供不同的策略?

是的; 不同的东西是不同的。

还是在其他一些环境因素之间?

如?

显然无法识别对该错误的利用。那是因为心跳函数在调用时没有记录吗?

正确的。

肯定任何对 ~64k 字符串的请求都可能是恶意的吗?

我没有跟随你的思路。使请求可能是恶意的原因是发送的字节与请求回显的字节不匹配,而不是请求回显的数据大小。

于 2014-04-15T17:44:04.880 回答
13

不会发生分段错误,因为访问的数据与请求的数据紧邻,并且通常在同一进程的内存中。如果我认为请求足够大,它可能会导致异常,但这样做不符合开发者的利益,因为使进程崩溃会阻止他们获取数据。

为了清楚地解释,这个XKCD漫画很难更好:

在此处输入图像描述

于 2014-04-15T18:13:53.797 回答