@@ -290,6 +290,7 @@ def creds_search(*args)
290
290
port_ranges = [ ]
291
291
svcs = [ ]
292
292
rhosts = [ ]
293
+ opts = { }
293
294
294
295
set_rhosts = false
295
296
@@ -314,6 +315,7 @@ def creds_search(*args)
314
315
end
315
316
when "-t" , "--type"
316
317
ptype = args . shift
318
+ opts [ :ptype ] = ptype
317
319
if ( !ptype )
318
320
print_error ( "Argument required for -t" )
319
321
return
@@ -325,14 +327,17 @@ def creds_search(*args)
325
327
return
326
328
end
327
329
svcs = service . split ( /[\s ]*,[\s ]*/ )
330
+ opts [ :svcs ] = svcs
328
331
when "-P" , "--password"
329
332
pass = args . shift
333
+ opts [ :pass ] = pass
330
334
if ( !pass )
331
335
print_error ( "Argument required for -P" )
332
336
return
333
337
end
334
338
when "-u" , "--user"
335
339
user = args . shift
340
+ opts [ :user ] = user
336
341
if ( !user )
337
342
print_error ( "Argument required for -u" )
338
343
return
@@ -343,13 +348,15 @@ def creds_search(*args)
343
348
set_rhosts = true
344
349
when '-O' , '--origins'
345
350
hosts = args . shift
351
+ opts [ :hosts ] = hosts
346
352
if !hosts
347
353
print_error ( "Argument required for -O" )
348
354
return
349
355
end
350
356
arg_host_range ( hosts , origin_ranges )
351
357
when '-S' , '--search-term'
352
358
search_term = args . shift
359
+ opts [ :search_term ] = search_term
353
360
else
354
361
# Anything that wasn't an option is a host to search for
355
362
unless ( arg_host_range ( arg , host_ranges ) )
@@ -374,6 +381,8 @@ def creds_search(*args)
374
381
end
375
382
end
376
383
384
+ opts [ :type ] = type if type
385
+
377
386
# normalize
378
387
ports = port_ranges . flatten . uniq
379
388
svcs . flatten!
@@ -384,120 +393,117 @@ def creds_search(*args)
384
393
}
385
394
386
395
tbl = Rex ::Text ::Table . new ( tbl_opts )
396
+ opts = { }
397
+ opts [ :wspace ] = framework . db . workspace
398
+ query = framework . db . creds ( opts )
387
399
388
- ::ActiveRecord ::Base . connection_pool . with_connection {
389
- query = Metasploit ::Credential ::Core . where ( workspace_id : framework . db . workspace )
390
- query = query . includes ( :private , :public , :logins ) . references ( :private , :public , :logins )
391
- query = query . includes ( logins : [ :service , { service : :host } ] )
392
-
393
- if type . present?
394
- query = query . where ( metasploit_credential_privates : { type : type } )
395
- end
396
-
397
- if svcs . present?
398
- query = query . where ( Mdm ::Service [ :name ] . in ( svcs ) )
399
- end
400
+ query . each do |core |
400
401
401
- if ports . present?
402
- query = query . where ( Mdm ::Service [ :port ] . in ( ports ) )
402
+ # Exclude non-blank username creds if that's what we're after
403
+ if user == "" && core . public && !( core . public . username . blank? )
404
+ next
403
405
end
404
406
405
- if user . present?
406
- # If we have a user regex, only include those that match
407
- query = query . where ( '"metasploit_credential_publics"."username" ~* ?' , user )
407
+ # Exclude non-blank password creds if that's what we're after
408
+ if pass == "" && core . private && ! ( core . private . data . blank? )
409
+ next
408
410
end
409
411
410
- if pass . present?
411
- # If we have a password regex, only include those that match
412
- query = query . where ( '"metasploit_credential_privates"."data" ~* ?' , pass )
412
+ origin = ''
413
+ if core . origin . kind_of? ( Metasploit ::Credential ::Origin ::Service )
414
+ origin = core . origin . service . host . address
415
+ elsif core . origin . kind_of? ( Metasploit ::Credential ::Origin ::Session )
416
+ origin = core . origin . session . host . address
413
417
end
414
418
415
- if host_ranges . any? || ports . any? || svcs . any?
416
- # Only find Cores that have non-zero Logins if the user specified a
417
- # filter based on host, port, or service name
418
- query = query . where ( Metasploit ::Credential ::Login [ :id ] . not_eq ( nil ) )
419
+ if !origin . empty? && origin_ranges . present? && !origin_ranges . any? { |range | range . include? ( origin ) }
420
+ next
419
421
end
420
422
421
- query . find_each do |core |
422
-
423
- # Exclude non-blank username creds if that's what we're after
424
- if user == "" && core . public && !( core . public . username . blank? )
425
- next
426
- end
427
-
428
- # Exclude non-blank password creds if that's what we're after
429
- if pass == "" && core . private && !( core . private . data . blank? )
430
- next
431
- end
432
-
433
- origin = ''
434
- if core . origin . kind_of? ( Metasploit ::Credential ::Origin ::Service )
435
- origin = core . origin . service . host . address
436
- elsif core . origin . kind_of? ( Metasploit ::Credential ::Origin ::Session )
437
- origin = core . origin . session . host . address
423
+ if core . logins . empty? && origin_ranges . empty?
424
+ public_val = core . public ? core . public . username : ""
425
+ private_val = core . private ? core . private . data : ""
426
+ realm_val = core . realm ? core . realm . value : ""
427
+ human_val = ""
428
+ # TODO: We shouldn't have separate code paths depending on the model we're working with
429
+ # This should always expect an OpenStruct.
430
+ if core . private
431
+ if core . private . is_a? ( OpenStruct )
432
+ human_val = core . human
433
+ else
434
+ human_val = core . private . class . model_name . human
435
+ end
438
436
end
439
437
440
- if !origin . empty? && origin_ranges . present? && !origin_ranges . any? { |range | range . include? ( origin ) }
441
- next
442
- end
438
+ tbl << [
439
+ "" , # host
440
+ "" , # cred
441
+ "" , # service
442
+ public_val ,
443
+ private_val ,
444
+ realm_val ,
445
+ human_val ,
446
+ ]
447
+ else
448
+ core . logins . each do |login |
449
+ # If none of this Core's associated Logins is for a host within
450
+ # the user-supplied RangeWalker, then we don't have any reason to
451
+ # print it out. However, we treat the absence of ranges as meaning
452
+ # all hosts.
453
+ if host_ranges . present? && !host_ranges . any? { |range | range . include? ( login . service . host . address ) }
454
+ next
455
+ end
443
456
444
- if core . logins . empty? && origin_ranges . empty?
445
- tbl << [
446
- "" , # host
447
- "" , # cred
448
- "" , # service
449
- core . public ,
450
- core . private ,
451
- core . realm ,
452
- core . private ? core . private . class . model_name . human : "" ,
453
- ]
454
- else
455
- core . logins . each do |login |
456
- # If none of this Core's associated Logins is for a host within
457
- # the user-supplied RangeWalker, then we don't have any reason to
458
- # print it out. However, we treat the absence of ranges as meaning
459
- # all hosts.
460
- if host_ranges . present? && !host_ranges . any? { |range | range . include? ( login . service . host . address ) }
461
- next
462
- end
457
+ row = [ login . service . host . address ]
458
+ row << origin
459
+ rhosts << login . service . host . address
460
+ if login . service . name . present?
461
+ row << "#{ login . service . port } /#{ login . service . proto } (#{ login . service . name } )"
462
+ else
463
+ row << "#{ login . service . port } /#{ login . service . proto } "
464
+ end
463
465
464
- row = [ login . service . host . address ]
465
- row << origin
466
- rhosts << login . service . host . address
467
- if login . service . name . present?
468
- row << "#{ login . service . port } /#{ login . service . proto } (#{ login . service . name } )"
466
+ public_val = core . public ? core . public . username : ""
467
+ private_val = core . private ? core . private . data : ""
468
+ realm_val = core . realm ? core . realm . value : ""
469
+ human_val = ""
470
+ # TODO: We shouldn't have separate code paths depending on the model we're working with
471
+ # This should always expect an OpenStruct.
472
+ if core . private
473
+ if core . private . is_a? ( OpenStruct )
474
+ human_val = core . human
469
475
else
470
- row << " #{ login . service . port } / #{ login . service . proto } "
476
+ human_val = core . private . class . model_name . human
471
477
end
472
-
473
- row += [
474
- core . public ,
475
- core . private ,
476
- core . realm ,
477
- core . private ? core . private . class . model_name . human : "" ,
478
- ]
479
- tbl << row
480
478
end
481
- end
482
- if mode == :delete
483
- core . destroy
484
- delete_count += 1
479
+
480
+ row += [
481
+ public_val ,
482
+ private_val ,
483
+ realm_val ,
484
+ human_val ,
485
+ ]
486
+ tbl << row
485
487
end
486
488
end
487
-
488
- if output_file . nil?
489
- print_line ( tbl . to_s )
490
- else
491
- # create the output file
492
- ::File . open ( output_file , "wb" ) { |f | f . write ( tbl . to_csv ) }
493
- print_status ( "Wrote creds to #{ output_file } " )
489
+ if mode == :delete
490
+ core . destroy
491
+ delete_count += 1
494
492
end
493
+ end
495
494
496
- # Finally, handle the case where the user wants the resulting list
497
- # of hosts to go into RHOSTS.
498
- set_rhosts_from_addrs ( rhosts . uniq ) if set_rhosts
499
- print_status ( "Deleted #{ delete_count } creds" ) if delete_count > 0
500
- }
495
+ if output_file . nil?
496
+ print_line ( tbl . to_s )
497
+ else
498
+ # create the output file
499
+ ::File . open ( output_file , "wb" ) { |f | f . write ( tbl . to_csv ) }
500
+ print_status ( "Wrote creds to #{ output_file } " )
501
+ end
502
+
503
+ # Finally, handle the case where the user wants the resulting list
504
+ # of hosts to go into RHOSTS.
505
+ set_rhosts_from_addrs ( rhosts . uniq ) if set_rhosts
506
+ print_status ( "Deleted #{ delete_count } creds" ) if delete_count > 0
501
507
end
502
508
503
509
def cmd_creds_tabs ( str , words )
0 commit comments