在我们关于安全性的第一次CS讲座中,我们讨论了C的问题,没有检查所谓的缓冲区长度以及可以利用此漏洞的不同方式的一些示例。
在这种情况下,它看起来像是恶意读取操作的情况,其中应用程序只读出了很多字节的内存
我是否正确断言Heartbleed错误是C缓冲区长度检查问题的表现?
为什么恶意使用在尝试读取其他应用程序的内存时不会导致分段错误?
在写入内存之前简单地将内存归零(然后再从中读取)会导致分段错误吗?或者这在操作系统之间有所不同吗?还是介于其他一些环境因素之间?
显然无法识别漏洞的利用。是因为心跳功能在调用时不记录?否则,对64k字符串的任何请求肯定都是恶意的?
答案 0 :(得分:25)
我是否正确断言Heartbleed错误是C缓冲区长度检查问题的表现?
是。
Heartbleed bug是C中经典缓冲区溢出漏洞的表现吗?
没有。 "经典"缓冲区溢出是指将写入更多数据到堆栈分配缓冲区中而不是它可以容纳的缓冲区溢出,其中写入的数据由恶意代理提供。恶意数据溢出缓冲区并覆盖当前方法的返回地址。当方法结束时,然后返回包含攻击者选择代码的地址并开始执行它。
相比之下,心脏缺陷不会覆盖一个缓冲区并且不会执行任意代码,只是读取超出代码中的范围很可能在内存中附近有敏感数据。
为什么恶意使用在尝试读取其他应用程序的内存时会导致分段错误?
它没有尝试阅读其他应用程序的内存。漏洞会读取当前进程的内存,而不是另一个进程。
为什么恶意使用在尝试读取超出缓冲区范围的内存时会导致分段错误?
这是这个问题的重复:
Why does this not give a segmentation violation fault?
分段错误意味着您触摸了操作系统内存管理器尚未分配给您的页面。这里的错误是您在堆管理器尚未分配给您的有效页面上触及数据。只要页面有效,您就不会获得段错误。通常,堆管理器会向操作系统请求大量内存,然后将其划分到不同的分配中。就操作系统而言,所有这些分配都在有效的内存页上。
解除引用null是一个段错误,因为操作系统永远不会使包含零指针的页面成为有效页面。
更一般地说:编译器和运行时不需要确保未定义的行为导致段错误; UB可以导致任何行为,包括什么都不做。有关此问题的更多想法,请参阅:
Can a local variable's memory be accessed outside its scope?
对于我抱怨UB 应该总是等同于安全关键代码中的段错误,以及关于漏洞静态分析讨论的一些指示,请参阅今天的#39;博客文章:
http://ericlippert.com/2014/04/15/heartbleed-and-static-analysis/
在写入内存之前简单地将内存归零(然后随后从中读取)会导致分段错误吗?
不太可能。如果读出界限不会导致段错误,则不可能写出越界。 可能一页内存是只读的,但在这种情况下似乎不太可能。
当然,以后将整个节目中的各种内存归零的结果都是错误的。如果在该归零的内存中有一个指针,您稍后将其取消引用,那么该解除引用将导致段错误。
这在操作系统之间有所不同吗?
问题很模糊。让我重新说一下。
不同的操作系统和不同的C / C ++运行时库是否提供了不同的策略来分配虚拟内存,分配堆内存以及识别内存访问何时超出范围?
是; 不同的事物不同。
或其他一些环境因素之间?
如?
显然无法识别漏洞的利用。是因为心跳功能在调用时不记录?
正确。
肯定对~64k字符串的任何请求都可能是恶意的吗?
我没有按照你的想法思考。什么使得请求可能是恶意的是发送的字节和请求回显的字节之间的不匹配,而不是要求回显的数据的大小。
答案 1 :(得分:10)
不会发生分段错误,因为访问的数据与请求的数据紧邻,并且通常位于同一进程的内存中。如果请求足够大,它可能会导致异常,但这样做并不符合开发人员的利益,因为崩溃进程会阻止他们获取数据。
要获得清晰的解释,这个XKCD漫画很难更好: