专栏名称: 利刃信安
利刃信安
目录
相关文章推荐
连州点点网  ·  期待您到场领奖!关于召开“2025年连州市春 ... ·  3 天前  
51好读  ›  专栏  ›  利刃信安

【商密测评】“心脏滴血漏洞”测评经验分享

利刃信安  · 公众号  ·  · 2024-04-28 14:23

正文

“心脏滴血漏洞”测评经验分享

1 前言

1.1 编写目的

“心脏滴血漏洞”测评经验分享

1.2 读者对象

本文档读者对象为:测评相关工程师、项目管理者、测试工程师、质量管理人员、文档工程师等技术人员。

1.3 名词术语

1.4 参考文档

2 测评前的准备

2.1 心脏滴血漏洞是什么?

Heartbleed漏洞,也叫“心脏滴血漏洞”。是OpenSSL加密软件库中的一个严重漏洞。这个漏洞允许窃取正常情况下使用SSL/TLS加密保护的信息;

自2011年12月31日,漏洞就已经存在,而且随着OpenSSL版本1.0.1于2012年3月14日释出,有缺陷的代码被互联网广泛使用;Heartbleed漏洞允许互联网上的任何人不受限制的读取受OpenSSL漏洞保护系统的内存。攻击者可根据漏洞窃听信息,直接从服务和用户那里窃取潜在的敏感数据,甚至包括服务器的专用主密钥;

如果存在此漏洞;攻击者可以通过被动中间人攻击,获取此时服务器内存中存储的信息(如果服务器和客户端未使用完全正向保密,或使用了完全正向保密时攻击方发动“主动中间人攻击”)。攻击者无法控制服务器返回的数据,因为服务器会使用一个随机内存块(最大64KB)作为响应;而且攻击者可以不断发送攻击请求报文,获取服务器内存中的数据。

安全公司Codenomicon和Google工程师Neel Mehta最早于2014年4月8日发现(公布)了 OpenSSL的Heartbleed漏洞;安全公司Codenomicon为这个漏洞制作了一个符合漏洞形象的logo;Codenomicon公司的工程师“Ossi Herrala”为漏洞名起了很炫的名字:“Heartbleed”;心脏滴血的名称由此而来。

2.2 漏洞范围

Heartbleed于2011年12月被引入到OpenSSL中,自OpenSSL于2012年3月14日发布1.0.1以来就一直存在。2014年4月7日发布的OpenSSL 1.0.1g修复了这个漏洞。.

漏洞详细说明见:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160

自2014年漏洞发布起即全球%30的网站存在被攻击的风险,漏洞影响的范围到底有多大? 根据以下当年发布的信息可以说明情况;

节选来自Heartbleed的官方说明:OpenSSL在Web容器如Apache/Nginx中使用,这两款中间件的全球份额超过66%。一些大型的互联网公司常使用 OpenSSL,而这曾经被认为是最安全的数据传输手段之一;

众多网络路由器厂商包括 Cisco Systems 与 Juniper Networks等,在漏洞公布当天纷纷发布了紧急公告,列出一系列受此漏洞影响的路由器产品。虽说这些产品由于使用旧版SSL,厂商也表示会尽快更新补洞,据悉,有的黑客在漏洞发布一年前就已经在利用这个漏洞了,获取到了不少大网站的敏感信息;

国内知名企业如淘宝、阿里、360、京东(滚动资讯)、微信、支付宝等公司的技术团队也在漏洞发布当天彻夜奋战,和黑客们开展起了一场“你盗我堵”的赛跑,在黑客窃取更多用户数据前赶紧予以修复…

下面图片反应了2014年在发布漏洞后的紧急情况:

2.3 漏洞描述

Heartbleed漏洞,这项严重缺陷(CVE-2014-0160)的产生是由于未能在memcpy()调用受害用户输入内容作为长度参数之前正确进行边界检查。攻击者可以追踪OpenSSL所分配的64KB缓存、将超出必要范围的字节信息复制到缓存当中再返回缓存内容,这样一来受害者的内存内容就会以每次(每次SSL心跳报文请求)64KB的速度进行泄露;原理如下图所示:

2.4 漏洞原理

2.4.1 心跳检测报文(Heartbeat)

要对心脏滴血漏洞进行更好的理解,首先需要知道心跳检测报文的作用和运行原理,这里做简要解释;

(A)心跳检测报文的作用

TLS心跳扩展报文为TLS/DTLS提供了一种允许在不重新进行商议和发送路径MTU探索包(PMTU)的情况下而使用保持持续通信功能的新协议。

所谓心跳检测,就是建立一个 Client Hello 问询来检测对方服务器是不是正常在线 ,服务器发回 Server hello,表明正常保持SSL通讯。就像我们打电话时会问对方“喂听得到吗?”一样;

每次问询都会附加一个问询的字符长度“pad length”,如果这个“pad length” 大于实际的长度,应答方仍是会返回相同字符长度的字符信息。

(B)TLS/DTLS心跳检测报文的结构

TLS数据包格式如下:

DTLS数据包格式如下:

(C)TLS/DTLS心跳检测报文抓包示范

心跳检测报文包括A、请求包(heartbeat Request)和B、响应包(heartbeat Response);本文以常见TLS数据包为例,通过wireshark进行抓包获取信息如下:

A、TLS请求包抓包示例如下:

B、TLS响应包抓包示例如下:

通过对比心跳检测请求报文和响应报文不难看出,响应报文和请求报文使用相同的报文格式;如果仔细观察请求报文,可以发现请求报文请求的报文长度是16384,但实际的载荷(Payload)值为0;但应答方回复请求方的实际载荷(Payload)为16381(约64KB);这里,就是心脏发生滴血的地方;即可以发现攻击方通过制造畸形心跳检测请求报文进行了攻击;

如果打开应答报文Payload字段,可以看到因漏洞产生内存溢出的数据;溢出的数据是随机的,但是攻击方可以通过多次进行攻击,从而获取更多应答方内存中的数据,直到获取有价值的数据;而且64KB是可以泄露出足够多的信息的;如下图攻击方通过伪造报文已经获取了关键的用户账户和口令信息:

这里还想说一些题外话,此类漏洞主要是因为攻击方制造了畸形报文进行了攻击,目前可以抵御的手段可以通过IPS、WAF等安全防护规则库进行拦截;但根本上最好的修复方法还是更新SSL/TLS版本;后续的SSL/TLS版本中对协议代码进行了优化(对输入内容作为长度参数之前正确的进行了边界检查)。

2.4.2 代码原理示例

漏洞出现在SSL服务ssl/d1_both.c中,对用户传入的payload长度没有检查就进行内存拷贝;下面是代码示意:


漏洞出现在SSL服务ssl/d1_both.c中,对用户传入的payload长度没有检查就进行内存拷贝;下面是代码示意:1)基本结构-------------------------------------------------------------------------int                                                    dtls1_process_heartbeat(SSL *s){                                                      unsigned char *p = &s->s3->rrec.data[0], *pl;    unsigned short hbtype;    unsigned int payload;    unsigned int padding = 16; /* Use minimum padding */}-------------------------------------------------------------------------2)p指向一条SSLv3的记录,结构如下:-------------------------------------------------------------------------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;-------------------------------------------------------------------------3)回到上面的程序,接下来对指针进行一些操作:-------------------------------------------------------------------------/* Read type and payload length first */hbtype = *p++;n2s(p, payload);pl = p;-------------------------------------------------------------------------4)这里先读取个type,然后n2s把下一个length的两个字节放到payload里面,作为后面内存拷贝的长度;-------------------------------------------------------------------------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






请到「今天看啥」查看全文