将 Heartbleed 错误称为堆栈溢出是否准确?在我的理解中,这是一个非常典型的例子。这在技术上正确吗?
3 回答
栈是一种以“后进先出”为主要特征的数据结构。它允许调用者(程序的一部分)将信息“推送”到堆栈上,并“弹出”最后推送的项目。对于严格堆栈,不允许进行其他操作。
堆栈用于程序调用子程序时(函数、方法、子程序都是子程序,它们在不同的上下文中有不同的名称)。当程序调用子程序时,需要保存一堆信息,以便子程序返回时可用。所以这个“执行上下文”被压入堆栈,然后在返回时检索。此操作对计算机非常重要,计算机硬件直接支持它;换句话说,有机器指令可以做到这一点,因此不必在软件中完成(更慢)。
计算机中通常有一定数量的内存专用于此运行时堆栈,甚至通常用于每个正在运行的程序的堆栈和一些用于操作系统等的堆栈。如果子例程调用变得如此“深”以至于堆栈空间量分配的不会保存发生调用所需的所有信息,这是一个堆栈溢出错误。
这不是令人心血的问题。它允许运行程序设置要返回给它的缓冲区空间量,并返回内存中超出该外部程序发送的少量数据的任何内容。
所以这个问题的真正答案是“不”,我无法想象谁会认为这是一个典型的例子。
从技术上讲,是的。但不是在传统的溢出意义上,您尝试粉碎堆栈并摆弄返回值并尝试执行代码。这纯粹是一个“泄露私人数据”的问题。
OpenSSL 规范要求客户端在其心跳包中发送一大块随机数据。服务器需要将数据完全按原样发送给客户端。
错误是客户端基本上发送了两位数据:
size_of_heartbeat(表示心跳数据大小的 16 位整数) heartbeat_data(最多 64k 数据)
恶意客户端可以对它发送的数据撒谎,并说:
size_of_hearbeat = 64k
heartbeat_data = '' (1 byte)
OpenSSL 无法验证 size_of_hearbeat == actual_size(heartbeat_data),并且会信任 size_of_heartbeat,所以基本上你有:
-- allocate as much memory as the client claims they sent to you
-- copy the user's heartbeat packet into the response packet.
由于用户声称他们向您发送了 64k,因此 OpenSSL 正确分配了一个 64k 缓冲区,但随后执行了一个无界的 memcpy() 并愉快地将多达 64k 的 ram 复制到客户端心跳数据实际发生的位置。
如果对此进行了足够多的尝试,您可以对服务器内存中的内容建立一个非常完整的图像,一次 64k,并最终能够提取服务器的 SSL 证书、以前通过加密层等...