但是,服务器上的进程怎么可能从RAM返回64kb的随机数据呢?
操作系统不是应该阻止对实际RAM的访问,而只允许访问其中一个进程无法访问其他进程的内存内容的虚拟内存吗?
可以吗? OpenSSL以内核模式运行,因此可以访问所有RAM?
如果进程尝试访问未显式分配的任何内存,我会期望出现分段错误。我可以理解从运行OpenSSL程序本身的进程中获取了64kb的随机数据,但是我什至看不到如何看到服务器的完整RAM才能将其发送回客户端。
更新:
@ paj28的评论,是的,正是这些错误的信息使我对此感到疑惑。如您所说,即使是Heartbleed.com官方咨询也以一种误导性的方式来形容它(尽管我会说他们这样做是因为它的目标受众不仅是我们的技术人员,而且他们希望保持简单)
作为参考,以下是heartbleed.com声明的方式(强调我的意思):
Heartbleed错误允许Internet上的任何人读取受保护的系统的内存。易受攻击的OpenSSL软件版本。
对于任何暗示虚拟机/物理机具有完整RAM的技术人员。
#1 楼
@ paj28的评论涵盖了重点。 OpenSSL是一个共享库,因此它在与使用它的进程相同的用户模式地址空间中执行。它根本看不到其他进程的内存。但是,OpenSSL所使用的内存(可能是Heartbleed过度读取的缓冲区附近的内存)充满了敏感数据。具体来说,它可能同时包含任何最近或即将发生的传输的密文和明文。如果您攻击服务器,则意味着您将看到其他人发送到服务器的消息以及服务器对这些消息的响应。这是窃取会话令牌和私人信息的好方法,而且您可能还会捕获某人的登录凭据。 OpenSSL存储的其他数据包括对称加密密钥(用于通过TLS进行批量数据加密和完整性)和私钥(用于证明服务器的身份)。窃取这些信息的攻击者可以实时窃听(甚至修改)受到破坏的TLS通信,或者分别成功假冒服务器(假设网络上居于中间位置)。
现在,关于Heartbleed的一件奇怪的事情使它变得比您预期的更糟。通常,如果您尝试从进程中的任意堆地址开始读取64k数据,则很有可能遇到一个未分配的内存地址(虚拟内存没有任何内容支持,因此无法使用)很快。进程地址空间中的这些漏洞非常普遍,因为当进程释放不再需要的内存时,操作系统会回收该内存,以便其他进程可以使用它。除非您的程序像筛子那样泄漏内存,否则内存中除了当前正在使用的数据之外通常不会有那么多数据。尝试读取未分配的内存(例如,尝试访问已释放的内存)会导致读取访问冲突(在Windows上)/分段错误(在* nix上),这将导致程序崩溃(并且崩溃之前无法完成)像发送数据一样)。这仍然可以被利用(作为拒绝服务攻击),但是还不及让攻击者获取所有数据那么糟糕。
使用Heartbleed,该过程几乎从未崩溃过。事实证明,OpenSSL显然认为平台内存管理库太慢(或其他原因;我将不尝试证明该决定的合理性),它会预先分配大量内存,然后使用其自己的内存管理功能在那。这意味着几件事情:
当OpenSSL“释放”内存时,就操作系统而言,它实际上并没有被释放,因此该进程仍然可以使用内存。 OpenSSL的内部内存管理器可能认为未分配内存,但是就操作系统而言,使用OpenSSL的进程仍然拥有该内存。
当OpenSSL“释放”内存时,除非它在调用其
free
函数之前显式擦除了数据,否则该内存将保留“释放”之前的所有值。这意味着可以读取实际上尚未使用的许多数据。OpenSSL所使用的内存堆是连续的;因此,无法使用。就操作系统而言,它之间没有任何差距。因此,过度读取的缓冲区不太可能会进入未分配的页面,因此它不太可能崩溃。
OpenSSL的内存使用具有很高的局部性-也就是说,它集中在相对较小的地址范围内(预分配的块)-而不是在OS内存分配器的作用下分散在地址空间中。因此,读取64KB的内存(这不是很多,即使紧挨32位进程的典型2GB范围,也远不及64位进程的巨大范围),这可能会获得很多数据。当前(或最近)在使用中,即使这些数据位于一堆据认为是单独分配的结果中。
评论
请注意,出于性能原因而实现自己的元内存管理器并非闻所未闻。它节省了很多开销。尽管实际上释放的内存更有可能引起分段错误,但真正的问题是,缓冲区可能首先被读取。
–贾斯汀
16-10-10在23:58
自定义分配器的另一个效果是使用valgrind的“酷刑测试”无效。
–paj28
16-10-11在13:44
ISTR,OpenSSL自己的分配器存在的问题主要是它使检查内存访问的工具无用,因为从系统库的角度(这是工具可以使用的地方)来看,所有内容都一直在使用中,由OpenSSL分配器保留。在大多数情况下,释放的内存也不会立即返回到操作系统,Linux上glibc的默认设置似乎是仅当分配的块为128 kB或更大时才创建单独的mmap()。因此,对于任何小于此的内容,即使是64 kB的缓冲区,也不太可能出现内存漏洞。
–ilkkachu
16-10-11在15:26
也许更重要的是,自定义分配器意味着您可能会从openssl获取数据,而不是从应用程序中随机获取数据。我想这会大大增加获得所有重要私钥的可能性(这使您可以使用MITM服务器,并使用非dh密码套件解密所有会话)。
– Peter Green
16-10-11在20:47
哦,是的,不是声称OpenSSL的自定义malloc没有任何优势,只是从安全角度而言-对于这样一个以安全性为重点的代码相当重要-这很危险,它使Heartbleed的(已经很糟糕)很明显更差。这似乎与问题有关;尽管提问者似乎有些困惑,但确实,Heartbleed确实出奇地有效。许多软件将很难获得如此多汁的结果。
– CBHacking
16-10-11在22:28
#2 楼
如果进程尝试访问未显式分配的任何内存,我会期望出现分段错误。
这就是误解所在。
任何中断的内存访问都可能导致分段错误,但是实际上,如果所请求的内存地址位于当前进程的地址空间(例如,您刚刚释放的变量)内,则这种可能性很小。
这就是为什么您不应该依赖分段错误来查找内存访问错误!
评论
像Java这样的现代语言,范围检查所有数组访问,因此,如果openssl的源语言是Java,则这种利用将不存在。几乎所有内存利用都与老式语言(例如C和C ++)相关,后者依赖于程序员检查自己的数组访问权限。
– ddyer
16-10-13在17:44
@ddyer:谢天谢地,这些带有边界检查功能的“现代”语言,例如Algol 60,Ada 83甚至Lisp。 :-)
–奇怪的思考
16-10-14在3:59
@ddyer,您知道JVM本身是用C ++编写的,对吗?我想我们应该停止教新的程序员旧的语言,而要永远使用现有的“旧式”工具,并希望它们永不中断。对?
–通配符
16-10-14在4:43
@ddyer:一种语言是否有边界检查几乎与它的年龄无关。相反,它与预期用途有关。当然,您可以用其他语言编写OpenSSL,但是对于一些至关重要的事情,离机器更近是一件好事。 SSL实现= sloooooooow中针对每个单个数组访问的语言授权范围检查。
–轨道轻赛
16-10-14在8:40
评论
OpenSSL是一个共享库,因此它与使用它的进程在相同的内存空间中运行(例如Apache)。操作系统停止从其他进程读取内存,但可以从同一进程读取内存,该进程有时会包含敏感数据。@ paj28如果是这样,这个问题可以很简单地回答。当我流血的消息公开时,我没有太多的时间来阅读新闻并向我通报有关的事情,因此我抓挠不了表面,不幸的是,此后再也没有这样做。但是,我确实知道,大众媒体描绘了令人伤心的错误,以使攻击者能够在有足够时间的情况下将服务器整个内存的映像复制到他们身上。这可能是这个问题的来源。 (但是,如果这是错误的信息,则问题可能基于错误的信息。)
所有内存都来自运行openssl的同一进程-是什么让您认为它是来自不同进程的内存?
@ UTF-8:如果用“服务器”表示“物理或虚拟硬件机器”,那么,是的,Heartbleed无法从其中复制完整的内存。但是,“服务器”也用于指代服务器进程,例如Apache(httpd),Tomcat,IIS,sendmail,openvpn的服务器等。在实践中,很难转储服务器的全部内存(进程)。 ),即使您排除了可执行页,但如果您对它的工作时间足够长,则可能可以获得所有您关心的内容。
@ UTF-8-我正要说这是媒体愚蠢的事情。但是公平地说,最初的建议也含糊不清。我认为这是他们“使”咨询变得“性感”的尝试。