• 这次OpenSSL HeartBleed漏洞是怎么一回事呢?


    “心脏出血”(Heartbleed)被称为互联网史上最严重的安全漏洞之一,波及了大量常用网站、服务,包括很多人每天都在用的 Gmail 等等,可能导致用户的密码、信用卡轻易泄露。但是我们可能对它还不是很了解,可能觉得,这不关我事。

    我随便找了个规模还算比较大的网站(域名就不说了),然后在调试器里看看返回信息:

     

    可以看到,这个网站的服务器也用了OpenSSL。其实 OpenSSL 的使用率还是挺高的,如果你经常上网,那么可以说,你几乎每天都在跟 OpenSSL 打交道,你的各种个人信息存储在各种各样的网站上,一旦某个网站因为 Heartbleed 泄漏了你的重要信息,比如信用卡,银行卡什么的,那么可能你就会因此有所损失。

    好奇的人们或许更想知道OpenSSL的程序员到底犯了什么错误,好在有 xkcd 这样的geek网站,用最最通俗易懂的方式,向大家展示了这个漏洞的原理:

     

    正好煎蛋那边有翻译:

     

    所谓heartbleed的说法,源自于「心跳检测」,就是用户发通过起TSL 加密链接,发起 Client Hello询问,测服务器是否正常在线干活(形象的比喻就是心脏脉搏),服务器发回Server hello,表明正常建立SSL通信。每次询问都会附加一个询问的字符长度pad length,bug来了,如果这个pad length大于实际的长度,服务器还是会返回同样规模的字符信息,于是造成了内存里信息的越界访问……

    漫画里,用户meg请求返回 “HAT 五百个字母”,然后色服器返回了内存中包括HAT之后的前500个字,也就是说伺服器将 “五百个字母” 这句话理解为了 显示500个字母 然后将其他人在同时伺服器里操作的前500个字母返回给meg看,而这里面包含很多私密信息。

    看起来这个内存泄露越界BUG很2吗?

    那么在代码层面再看看?假设心跳信息结构体定义为:

    struct hb {
          int type;
          int length;
          unsigned char *data;                                                    
    };
    

    type为心跳的类型,length为data的大小,其中关于data字段的内容结构为:

    type字段占一个字节,payload字段占两个字节,其余的为payload的具体内容,详情如下所示:

    字节序号 备注
    0 type
    1-2 data中具体的内容的大小为payload
    3-len 具体的内容pl

    当服务器收到消息后,会对该消息进行解析,也就是对data中的字符串进行解析,通过解析第0位得到type,第1-2位得到payload,接着申请(1+2+payload)大小的内存,然后再将相应的数据拷贝到该新申请的内存中。

    以下举个简单的示例来说明该问题,假如客户端发送的data数据为"006abcdef",那么服务器端解析可以得到type=0, payload=06, pl='abcdef',申请(1+2+6=9)大小的内存,然后再将type, payload, pl写到新申请的内存中。

    如果大家都是老实人,那么上述流程不会出现任何问题。可是世界上总是存在着那么多不“安分”的人,他们会非常的不诚实,比如客户端发送的字符串“abcdef”明明只有6个,而我非得把payload设置为500,如果服务器傻不拉几的不做任何边界检查,直接申请(1+2+500)大小内存,而且更过分的是还把"abcdef********"所有的内容拷贝到新申请的内存处,并发回给客户端。

    这样那些不安分的人就获得了服务器上很多非常敏感的信息,这些信息可能包括银行帐号信息,电子交易信息等等诸多安全信息。

    当然真实的结构体定义是这样的:

    typedef struct ssl3_record_st
    {
    	int type;               /* type of record */
    	unsigned int length;    /* How many bytes available */
    	unsigned int off;       /* read/write offset into 'buf' */
    	unsigned char *data;    /* pointer to the record data */
    	unsigned char *input;   /* where the decode bytes are */
    	unsigned char *comp;    /* only used with decompression - malloc()ed */
    	unsigned long epoch;    /* epoch number, needed by DTLS1 */
    	unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */
    } SSL3_RECORD;
    

    每条SSLv3记录中包含一个类型域(type)、一个长度域(length)和一个指向记录数据的指针(data)。

    在 dtls1_process_heartbeat 里有这样的语句:

    /* Read type and payload length first */
    hbtype = *p++;
    n2s(p, payload);
    pl = p;
    

    SSLv3记录的第一个字节标明了心跳包的类型。宏n2s从指针p指向的数组中取出前两个字节,并把它们存入变量payload中——这实际上是心跳包载荷的长度域(length)。注意程序并没有检查这条SSLv3记录的实际长度。变量pl则指向由访问者提供的心跳包数据。

    经常看到很多漏洞利用工具命名变量时,都会使用变量名payload,莫非 OpenSSL 的编写者也经常搞漏洞之类的东西么?

  • 相关阅读:
    常用知识点集合
    LeetCode 66 Plus One
    LeetCode 88 Merge Sorted Array
    LeetCode 27 Remove Element
    LeetCode 26 Remove Duplicates from Sorted Array
    LeetCode 448 Find All Numbers Disappeared in an Array
    LeetCode 219 Contains Duplicate II
    LeetCode 118 Pascal's Triangle
    LeetCode 119 Pascal's Triangle II
    LeetCode 1 Two Sum
  • 原文地址:https://www.cnblogs.com/xiaoyang002/p/4016058.html
Copyright © 2020-2023  润新知