【问题标题】:Is the heartbleed bug a manifestation of the classic buffer overflow exploit in C?heartbleed bug 是 C 中经典缓冲区溢出漏洞的表现吗?
【发布时间】:2014-05-30 04:13:44
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 1.是的。 2. 是同一个节目。 3.不。由服务器进程拥有,这就是导致“出血”的原因。 4. 没有保持活动的日志,这是我向您发送 1000 个字节(现在回显)的地方,但后来我只向您发送 1 个字节……嘿看,您发送回了 999 个“其他”字节.
  • 为了清楚起见,读取你不拥有的内存并不一定会导致段错误,它只是未定义的行为。
  • 为什么问题提示缓冲区溢出是 C 独有的

标签: c security computer-science heartbleed-bug


【解决方案1】:

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

是的。

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

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

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

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

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

为什么恶意使用在尝试读取超出缓冲区范围的内存时没有导致分段错误?

这是这个问题的重复:

Why does this not give a segmentation violation fault?

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

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

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

Can a local variable's memory be accessed outside its scope?

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

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

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

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

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

这是否因操作系统而异?

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

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

是的; 不同的事物是不同的

或者其他一些环境因素之间?

比如?

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

正确。

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

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

【讨论】:

  • 关于最后一个问题,我想说任何大的回显请求都是恶意的。它消耗服务器资源(带宽,这需要花钱)来做一些完全无用的事情。心跳操作确实没有正当理由支持除零以外的任何长度。
  • @R..:如果 API 的设计者相信他们根本不会允许传递缓冲区,那么显然他们不相信。必须有一些设计上的理由来支持回声功能;为什么它不是一个固定大小的 4 字节缓冲区,这对我来说似乎足够了,我不知道。
  • 我不同意;国际海事组织的设计师只是无能。从安全的角度考虑,没有人会认为支持任意回显请求是合理的。即使不是因为心脏出血溢出问题,也可能存在与对对等方发送的内容进行此类控制相关的加密弱点;这似乎不太可能,但如果没有充分的理由来支持某个功能,密码系统不应该支持它。它应该尽可能简单。
  • 64k 字符串:我读过或听说使用该漏洞可以返回的最大缓冲区长度为 64k 长,并假设任何恶意用户都希望获得尽可能多的长度。但是,您的答案的其他部分表明,过于贪婪实际上可能会增加导致故障的风险,因此检测漏洞利用的最佳方法是实际缓冲区长度与规定缓冲区长度之间的差异
  • 不错的答案,您可能需要注意Theo's comments,如果他们没有在malloc 周围使用包装器,这将导致崩溃。
【解决方案2】:

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

为了解释清楚,这个XKCD 漫画再好不过了:

【讨论】:

  • @chux 10 张图片不值 10,000 字吗?
  • @Mike,没错,更常见的短语是“一张图片值 1000 个字”。在编写文档时,我发现 10000:1 的比例更准确,尤其是在比较文件大小时。 :-)
猜你喜欢
  • 2016-06-04
  • 1970-01-01
  • 1970-01-01
  • 2020-07-13
  • 1970-01-01
  • 1970-01-01
  • 2013-02-01
  • 1970-01-01
  • 2022-01-22
相关资源
最近更新 更多