心脏滴血漏洞HeartBleed CVE-2014-0160深入代码层面的分析

前几天有人问我你不是看过openssl吗?那聊聊openssl漏洞,当时我一脸迷茫。我说我知道著名的心脏滴血漏洞,但是具体漏洞是什么原因导致的没有回答上来。对于自诩看过openssl源码的人,我觉得有必要对着代码研究一下,因此就有了本文。

对于心脏滴血的详细介绍,看以参考这个网站,但是这里主要是概述性质的,并没有深入到代码层次。实际上,我简单搜索了一下,在网上有很多的分析,但是深入代码的文章,网上基本没有,也许我这篇有望成为第一篇深入代码层次解读心脏滴血漏洞的文章。由于github上没有opnessl-1.0.1f版本的代码,只有1.0.1stable。因此下载这方面代码的时候可以到这里进行下载。因为滴血漏洞的影响范围仅限于openssl1.0.1到1.0.1f之间的版本。

本文对比的是openssl1.0.1f (存在心脏滴血问题)以及1.1.0f(修复了该漏洞的)代码差异。

心脏滴血漏洞从本质上来说是在memcpy的时候,没有对拷贝的内存做合法性检查,并非网上流传的在申请内存的时候即OPENSSL_malloc没有做合法性检查。因为虽然OPENSSL_malloc没有做合法性检查,但是其并不会泄露服务器的内存数据,真正世露数据的是memcpy动作。

心脏滴血漏洞是在heartbeat (RFC6520定义的功能)中引入的,在OpenSSL中使用了编译宏OPENSSL_NO_HEARTBEATS来决定是否开启heat beat 功能。因此搜索OPENSSL_NO _HEARTBEATS可以找到相关的代码。其实在OpenSSL-1.0.1f发送方函数中,对于发送的长度是有限制的。也就是说如果使用openssl库生成的报文,长度上是没有问题的。在1.0.1f中函数ssl3_ctrlcase SSL_CTRL_DTLS_EXT_SEND_HEARTBEAT分支调用函数dtls1_heartbeat中,这其中做了如下限制OPENSSL_assert(payload + padding <= 16381),即发送的最大报文长度是16384 (加上type一个字节,长度占两个字节)。

由于泄漏的是服务器的信息,因此定位到函数dtls1_process_heartbeat。openssl1.0.1f以及以前的版本在接收方函数,并没有做长度的限制。接收方在收到心跳报文TLS1_HB_REQUEST之后,给发送方回的响应中报文的长度,就是发送方传递过来的报文长度。如下代码:

buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;

/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);

问题主要出在memcpy,其中payload就是发送方带过来的报文长度,pl是接收方用于存储发送方发来的heartbeat请求部分的内存空间,bp是要发送的Buffer。由于前面提到发送方其实规定了能够传输的最大长度,例如发送内容的时候就做了限定,为2^14-3=16381,即接收方数组也会做限定,即pl空间有最大值。但是如果构造的heartbeat请求报文中长度超过了16381 (自行构造的异常报文),由于pl是一个内存空间,因此在复制的时候就会发生越界。payload是一个 unsigned int 类型,因此则最大可能泄露的内存空间为2^64,即64K大小的数据。bp是要发送的Buffer,如果紧邻pl的内存数据是网站秘钥的话,则秘钥会被返回给客户端,造成了网站秘钥的泄露。如果紧邻的内存是用户名和密码,则网站的用户名和密码都会被泄露,由于64K还是一个挺大的数据空间,如果不停的对网站发起heartbeat请求,则网站秘钥,用户信息的泄露可想而知,因此这也是心脏滴血漏洞如此致命的原因。

既然知道为何泄露,那么相应的补丁也就很好打了。发送端加何限制发送的长度大小,那么接收端做同样的限制即可。例如在openssl 1.1.0f中的修复就是如下代码:

unsigned int write_length = HEARTBEAT_SIZE(payload, padding);
int r;

if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
    return 0;

SSL3_RT_MAX_PLAIN_LENGTH的值为16384,这样发送方和接收方的长度就保持了一 致。

以上就是对于心脏滴血漏洞CVE-2014-0160在代码层面的分析。当然文中是以dtls1_process_heartbeat这样的函数为例来说明,dtls是针对传输层是UDP的加密,对于传输层是TCP,相应的函数应为tls1_process_heartbeat,当然不同的openssl版本可能略有差异,但是总体上来说DTLS以及TLS都曾存在该漏洞。

本文为CSDN村中少年原创文章,转载记得加上小尾巴偶,博主链接这里

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

村中少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值