二、漏洞描述
漏洞编号:CVE-2014-0160
发现人员: 安全公司Codenomicon和谷歌安全工程师
漏洞简述:
- OpenSSL在实现TLS和DTLS的心跳处理逻辑时,存在编码缺陷。O**p**enSSL的心跳处理逻辑没有检测心跳包中的长度字段是否和后续的数据字段相符合,攻击者模拟向服务器端发送自己编写的Heartbeat心跳数据包,若payload_lenght长度大于HeartbeatMes sage的length,则会在服务器返回的response响应包中产生数据溢出,造成有用数据泄露。
- 攻击者可以利用这一点,构造异常的数据包,来获取心跳数据所在的内存区域的后续数据。这些数据中可能包含了证书私钥,用户名,用户密码,用户邮箱等敏感信息。该漏洞允许攻击者单个心跳从内存中读取多达64KB的数据,攻击者可以继续重新连接,或者在活动TLS连接期间不断请求任意数量的64 KB内存内容块,直到获取足够的机密数据为止。该漏洞在国内被称为“ OpenSSL心脏出血漏洞”,因其破坏性之大和影响的范围之广,堪称网络安全里程碑事件。
影响范围:OpenSSL 1.0.2-beta, OpenSSL 1.0.1 - OpenSSL 1.0.1f
三、漏洞成因
- 心脏滴血漏洞从本质上来说是在memcpy的时候,没有对拷贝的内存做合法性检查,下面针对含有心脏滴血漏洞的openssl1.0.1f,从源代码层面对漏洞成因进行分析:
- 心脏滴血漏洞是在heartbeat功能中引入的,在OpenSSL中使用了编译宏OPENSSL_NO_HEARTBEATS来决定是否开启heat beat 功能。因此搜索OPENSSL_NO _HEARTBEATS可以找到相关实现函数,如下图。
图x openssl心跳模块实现函数
- 首先定位到s3_lib.c文件的ssl3_ctrl函数,该函数中包含了发送心跳包的相关代码,根据是否使用UDP协议传输,定义了dtls1_heartbeat和tls1_heartbeat两个发包函数。
在dtls1_heartbeat(d1_both.c)和tls1_heartbeat(t1_lib.c)的实现中,均对发送的数据包的长度进行了限制,发送的最大报文长度是16384字节。
<br />图x 发送心跳包相关代码<br />
考虑漏洞泄漏的是服务器端的内存数据,因此继续分析心跳包响应的处理逻辑。定位到dtls1_process_heartbeat函数(d1_both.c)和tls1_process_heartbeat函数(t1_lib.c)。
函数首先让p指向发送过来的SSLv3记录数组(SSL3_RECORD),然后hptype指向第一个字节即心跳包类型,p指针向后移动指向下一个字节,宏n2s从指针p现在指向的位置取出前两个字节,并把它们存入变量payload中——即心跳包载荷的长度域(length)。这里程序并没有检查这条SSLv3记录的实际长度。变量pl则指向由访问者提供的心跳包数据。
图x 服务端响应心跳包相关代码(获取发送长度)
图x p指向发送过来的SSLv3记录数组
图x SSLv3记录结构
图x n2s实现
接下来程序将分配一段由访问者指定大小的内存区域,这段内存区域最大为 (65535 + 1 + 2 + 16) 个字节。变量bp是用来访问这段内存区域的指针。然后调用宏s2n,将与请求的心跳包载荷长度相同的长度值存入变量payload。然后程序从pl处开始复制payload个字节到新分配的bp数组中——pl指向了用户提供的心跳包数据。最后,程序将所有数据发回给用户。
图x 服务端响应心跳包相关代码(获取发送内存数据)
图x s2n实现
但是如果攻击者构造一个非法的心跳包发送给服务器,将payload的数值设置的比实际发送的SSLv3记录的实际长度大,由于pl是一个内存空间,因此在复制的时候就会发生越界。payload是一个 unsigned int 类型,因此最大可能泄露的内存空间为2^64,即64K大小的数据。这种情况下,即使发送数据时对数据长度进行了限制,在响应时也可以突破这种限制。bp是要发送的Buffer,如果紧邻pl的内存数据是网站秘钥的话,则秘钥会被返回给客户端,造成了网站秘钥的泄露。如果紧邻的内存是用户名和密码,则网站的用户名和密码都会被泄露,如果不停的对网站发起heartbeat请求,则网站很多重要的内存信息都会被泄漏。
参考
https://blog.csdn.net/liuxb1223/article/details/35276179