OpenSSL Heartbleed漏洞(CVE-2014-0160)简要分析和检测

来源:互联网 发布:mac上如何复制粘贴 编辑:程序博客网 时间:2024/06/05 19:59

1.漏洞简介

CVE官网上有这个漏洞的简要介绍、影响范围以及相关文章的索引:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160。大致的意思就是说openssl在接收到client发送的Heartbeat Packet(心跳包)的处理过程出现问题,导致了处理这个数据包指针之后的最大16KB内存信息泄露。如果是处理某些敏感数据的进程,那么会导致敏感信息的泄露。

2.Heartbeat Packet简介

Heartbeat扩展是TLS在1.0.1之后才引入的,目的是用于安全的长连接,不必要每次发送数据之前都需要重新建立连接。定义的RFC文档在http://www.rfc-editor.org/rfc/rfc6520.txt。Heartbeat的数据包结构为,分别为packet类型(request或response)、payload的长度,生成的payload,补充的padding:

struct {   HeartbeatMessageType type;   uint16 payload_length;   opaque payload[HeartbeatMessage.payload_length];   opaque padding[padding_length];} HeartbeatMessage;

为了达到长连接的目的,客户端先自己生成一个payload(可以是任意字符串),然后构造对应的request包发送给服务器,接着服务器返回同样的payload表示目前还处于链接状态,这样一个来回之后客户端和服务端都能继续进行数据传输。知乎上余弦的回答http://zhi.hu/1pr9中的这幅图可以很容易了解这个过程:

这里写图片描述

3.漏洞测试

首先是搭建测试环境,服务器端:CentOS 6.0,openssl 1.0.1e,一个server进程;客户端:一个python poc文件。

服务器端首先需要生成证书,过程参考:http://blog.chinaunix.net/uid-20539097-id-64403.html。然后从http://www.freebuf.com/articles/web/31553.html的分析文章获得server的源代码,直接粘贴上去需要改部分编码导致的问题,然后

gcc -g -o ssl_server ssl_server.c -I/root/openssl_101f_prex/include/ -L/root/openssl_101f_prex/lib/ -lssl

编译生成ssl_server。POC代码在https://gist.github.com/RixTox/10222402。

接着服务器端运行ssl_server,客户端运行poc,可以看到返回结果大小为16384字节:

这里写图片描述

下图可以看到Heartbeat Packet Request的payload部分并没有数据,而payload_length的值是16384:

这里写图片描述

Response返回的payload有16365字节:

这里写图片描述

为什么是16365而不是Request包的16384字节呢?RFC文档规定Heartbeat Message的最大值只能是16384字节,也就是0x4000(16KB),而Heartbeat的结构中type、length和padding部分分别占了1、2、16字节(至少16字节,这里刚好是16),所以传回的payload 16365字节比16384少了19个字节。

同样在openssl的源码中也有定义最大长度,在写入Response的函数中会进行判断,而SSL3_RT_MAX_PLAIN_LENGTH则是16384:

这里写图片描述

这里写图片描述

所以每次能够获取的内存字节数最大只有16KB-19B,而不是有些地方说的两字节64KB。

4.源码分析和修复原理

在源码的ssl/d1_both.c和ssl/t1_lib.c两个文件处理heartbeat包,可以看到其并不是根据request包中的payload实际长度来获取的,而是根据字段中的length的值,导致了length可以构造更长的值来获取实际payload后面的内存内容:

这里写图片描述

在修复之后的代码会在获得request的payload长度之前会判断payload长度是否为0,之后则与实际长度进行比较:

这里写图片描述

当时想的是可能还有一种绕过上面修复之后代码的方法,就是将Length改成大于19+payload_length的值,这样就能绕过dtls1_process_heartbeat函数中增加的几行代码,比如说Length的值是0x3000,payload_length是0x2000。但是实际上经过测试是不行的:

这里写图片描述

查找原因发现在上一层也就是ssl/d1_pkt.c文件的dtls1_read_bytes函数中会调用一个dtls1_get_record函数,这个函数用来获得heartbeat message整个结构,其中有一段如下代码,首先会判断Length的长度和heartbeat的实际长度,如果Length比较大,则会继续从网络中获取后续数据,但是没有后续数据的话就会返回错误:

这里写图片描述

这里保证了Length这个值和heartbeat message实际长度的一致性。至于为什么会想到这里可能会有问题呢?那就是这个漏洞触发的地方开发人员没有考虑实际长度和length值的一致性,猜想前面那个Length可能也会有问题。

5.Snort规则检测

针对这个漏洞的检测需要针对各种不同的利用程序来,而比较常用的一个规则如下。

alert tcp any any -> $HOME_NET [25,443,465,636,992,993,995,2484,9876] (msg:"OpenSSL Heartbleed Attack - SSLv3 heartbeat request";flow:to_server,established; content:"|18 03 00|"; depth: 3;byte_extract:2, 0, pkt_length, relative, big; byte_test:2, >, pkt_length, 6, big; threshold:type limit, track by_src, count 1, seconds 600; reference:cve,2014-0160; classtype:current-event; sid:130101601; rev:1;)
1.首先TSL协议是建立在TCP基础上的,所以是tcp,flow字段表示源地址和端口任意,目的地址是本地IP,在配置文件中定义,本地端口是从FBI的snort检测规则提取出来的,因为,数据包从客户端到服务端2.content字段表示前三个字节中包含0x18 0x03 0x00表示SSLv3,第三字节如果是0x01则是TLS 1.00x02是TLS 1.1, 0x03时TLS 1.23.byte_extract字段表示从上一次匹配之后的位置取两个字节存储到pkt_length变量中(就是数据包中Length的值)4.byte_test字段表示从数据包开头偏移6字节(也就是第78字节)的2字节的值大于pkt_length,并且是大端表示的5.threshold字段则表示每10min600s)为一个周期,检测到第一个匹配的数据包就报警,本周期内同一个IP检测到不再报警.

除此之外,在ICS-CERT官网上有FBI写的许多针对这个漏洞的snort规则,不过这些规则我尚未验证,仅供参考:https://ics-cert.us-cert.gov/UPDATE-FBI-Snort-Signatures-Heartbleed-April-2014。

参考链接:
1.https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160
2.http://www.rfc-editor.org/rfc/rfc6520.txt
3.http://zhi.hu/1pr9
4.http://blog.chinaunix.net/uid-20539097-id-64403.html
5.http://www.freebuf.com/articles/web/31553.html
6.https://gist.github.com/RixTox/10222402
7.https://ics-cert.us-cert.gov/UPDATE-FBI-Snort-Signatures-Heartbleed-April-2014

0 0
原创粉丝点击