心脏出血漏洞可以追根溯源到开源代码库OpenSSL里的一行代码上。本文将告诉你心脏出血的工作原理、利用状况以及怎样修复未打补丁的服务器。
2014年4月,心脏出血漏洞进入了公众视野,该漏洞为攻击者提供了前所未有的敏感信息获取途径,并且成千上万的网络服务器上存在心脏出血漏洞,就连雅虎这样的网络巨头也在此列。
开源代码库OpenSSL中的一个漏洞是引发心脏出血的罪魁祸首,该漏洞使用了传输层安全协议(TLS)和加密套接字协议层(SSL)协议。通过这个漏洞,简而言之,恶意用户可以很容易地诱骗一个脆弱的网络服务器发送用户名和密码等敏感信息。
心脏出血漏洞的工作原理
要了解心脏出血(CVE-2014-0160)的工作原理,你必须对TLS/SSL协议的运作模式和内存存储信息的方式有些许的认识。
TLS / SSL协议的一个重要组成部分被称为“心跳”。从本质上讲,心跳就是两台电脑互相通信从而让对方知道它们仍然相连,即使用户没有下载或上传任何东西。每过一段时间,一方会发送一个加密的数据到另一台电脑上,这被称为心跳请求。第二台电脑会回复同样的加密数据,来证明连接仍然存在。至关重要的是,心跳请求里包含自己的长度信息。
举个例子,如果你正在翻阅你的雅虎邮箱,但是在一段时间内没有进行加载信息到操作,网页浏览器可能会给雅虎的服务器发送一个信号,该信号本质上是“这是一个40KB的消息,你如果能获得它,把它发回给我”(请求信号可以最多可以达到64KB)。雅虎的服务器收到消息时,会分配一个内存缓冲区(一个物理内存区域用以存储信息),该区域的存储空间和心跳请求信号里的长度一致,即40KB。接下来,它会存储请求信号的加密数据到内存缓冲区,然后读取数据并将其发送回你的浏览器。
这是“心跳”的理想工作方式。心脏出血漏洞的出现是因为,OpenSSL的心跳功能缺少了一个至关重要的安全维护手段:计算机接受心跳请求时从不检查该请求和它声称的内容是否一致。如果请求说自身的长度是40KB,但其实只有20KB,接收电脑会预留40KB的内存缓冲区,然后只存储实际接受的20KB数据,然后发送回20KB的原数据和接下来20KB的未知内容内存。这额外的20KB的数据就是攻击者从网站服务器中提取的信息。
这是操作的关键部分。即使计算机处理过某些信息,这些信息会留在内存缓冲区直到新的信息出现并覆盖它。如果你是攻击者,你没有办法提前知道刚刚从服务器获取的20KB里究竟有什么,但是你可以推测出一些可能。这些信息有可能是胡言乱语或者无用而繁琐的东西,也有可能是SSL私钥,这会把服务器的安全通信暴露给攻击者(这个可能性很小,但是却是攻击者的最高追求)。更常见的是,攻击者可能会获得用户名和密码,服务器上的应用或服务收集并保存了这些信息,这将给予攻击者登录和访问渠道。
兰德尔·门罗的网络漫画xkcd因为将复杂的科学概念通过浅显易懂的形式表达而出名,门罗尤其擅长就计算机领域的问题作画。这个2014年诞生的漫画很好地总结了心脏出血漏洞是怎样简单而高效地运作的。
心脏出血错误代码
导致心脏出血漏洞的编程错误可以归于一行代码:
- memcpy(bp, pl, payload);
memcpy()是复制数据的命令。bp是被复制的数据的存储区域,pl是被复制的数据的来源,payload是被复制的数据长度。问题在于,该命令没有检验pl复制的数据是否和payload给予的长度相符。
讽刺的是,OpenSSL是开源软件。任何人都可以查看代码,大概几百人曾访问过这段代码,但是没有人注意到相当基本的编码错误。
心脏出血的利用状况
我们至今不知道,在心脏出血广为人知前,是否有利用该漏洞的现实攻击。很可能早在2013年被某些安全公司侦测到的攻击就是基于该漏洞的,有人甚至认为这些攻击是由政府安全部门发起的。
在2014年4月心脏出血漏洞被公开后,企业争先恐后地更新了系统。但是黑客仍然能够在一些情况下利用该漏洞。一起对社区卫生系统的攻击被归咎于心脏出血漏洞,结果是病人数据被大量窃取,与之类似的是加拿大税务署数以百计的社会身份号码被盗。
如何修复心脏出血漏洞
心脏出血刚被揭露不久,OpenSSL就发布了补丁,而且百分之八九十的受影响服务器及时更新了补丁,但是,总会有些对你来说至关重要的服务器多年来从未进行合适的升级,因此,在你不明了某个服务器是否已经安全的情况下,不妨做个测试。Pentest-tools.com有一个免费的网络测试,你可以输入一个URL来检测服务器是否已经正确地修复了该漏洞。
修补心脏出血漏洞的方式是更新最新的OpenSSL版本,你可以在官网上获取相关链接。
因为OpenSSL是开源的,以下是修复过的代码,感兴趣的话你可以读一下:
- * Read type and payload length first */
- if (1 + 2 + 16 > s->s3->relent)
- return 0;
- /* silently discard */
- hbtype = *p++;
- n2s(p, payload);
- if (1 + 2 + payload + 16 > s->s3->rrec.length)
- return 0;
- /* silently discard per RFC 6520 sec. 4 */
- ppl = p;
代码的第一部分的功能是确定心跳请求的大小不是0KB,不然可能会出错。第二部分用来检验心跳的长度是否和它声称的相符。
如果你发现自己控制的某台服务器已经暴露在该漏洞下有一段时间,你需要做的就不仅仅是更新OpenSSL的代码了。例如,你应该改变SSL证书服务器,因为它们可能已经被无声无息地渗透了。此外,较为麻烦但重要的是:服务器上保有账户信息的用户应该更改密码。
【本文是51CTO专栏作者“”李少鹏“”的原创文章,转载请通过安全牛(微信公众号id:gooann-sectv)获取授权】