@@ -35,6 +35,10 @@ def require_deps
3535 require 'msf/core/payload_generator'
3636 require 'msf/core/constants'
3737
38+ unless $stdout. tty?
39+ Rex ::Text ::Table . unwrap_tables!
40+ end
41+
3842 @framework_loaded = true
3943end
4044
@@ -55,10 +59,6 @@ def init_framework(create_opts={})
5559 end
5660
5761 @framework = ::Msf ::Simple ::Framework . create ( create_opts )
58-
59- unless $stdout. tty?
60- Rex ::Text ::Table . unwrap_tables!
61- end
6262end
6363
6464# Cached framework object
@@ -196,6 +196,10 @@ def parse_args(args)
196196 opts [ :timeout ] = x
197197 end
198198
199+ opt . on ( '--refresh-cache' , 'Rebuild the module metadata cache from disk before listing' ) do
200+ opts [ :refresh_cache ] = true
201+ end
202+
199203 opt . on_tail ( '-h' , '--help' , 'Show this message' ) do
200204 raise HelpError , "#{ opt } "
201205 end
@@ -227,7 +231,7 @@ def parse_args(args)
227231 opts [ :payload ] = "stdin"
228232 end
229233
230- if opts [ :payload ] . downcase == 'stdin' && !opts [ :list ]
234+ if opts [ :payload ] . downcase == 'stdin' && !opts [ :list ] && ! opts [ :refresh_cache ]
231235 $stderr. puts "Attempting to read payload from STDIN..."
232236 begin
233237 opts [ :timeout ] ||= 30
@@ -255,7 +259,7 @@ def payload_stdin
255259end
256260
257261def dump_platforms
258- init_framework ( :module_types => [ ] )
262+ require_deps unless @framework_loaded
259263 supported_platforms = [ ]
260264 Msf ::Module ::Platform . subclasses . each { |c | supported_platforms << c . realname . downcase }
261265
@@ -275,7 +279,7 @@ def dump_platforms
275279end
276280
277281def dump_archs
278- init_framework ( :module_types => [ ] )
282+ require_deps unless @framework_loaded
279283 supported_archs = ARCH_ALL . dup
280284
281285 tbl = Rex ::Text ::Table . new (
@@ -294,7 +298,7 @@ def dump_archs
294298end
295299
296300def dump_encrypt
297- init_framework ( :module_types => [ ] )
301+ require_deps unless @framework_loaded
298302 tbl = Rex ::Text ::Table . new (
299303 'Indent' => 4 ,
300304 'Header' => "Framework Encryption Formats [--encrypt <value>]" ,
@@ -311,7 +315,7 @@ def dump_encrypt
311315end
312316
313317def dump_formats
314- init_framework ( :module_types => [ ] )
318+ require_deps unless @framework_loaded
315319 tbl1 = Rex ::Text ::Table . new (
316320 'Indent' => 4 ,
317321 'Header' => "Framework Executable Formats [--format <value>]" ,
@@ -340,33 +344,50 @@ def dump_formats
340344end
341345
342346def dump_payloads ( platform = nil , arch = nil )
343- init_framework ( :module_types => [ :payload ] )
347+ require_deps unless @framework_loaded
348+ metadata_cache = Msf ::Modules ::Metadata ::Cache . instance
349+ all_payloads = metadata_cache . get_metadata . select { |m | m . type == 'payload' }
350+
351+ platform_filter = platform ? Msf ::Module ::PlatformList . transform ( platform . split ( ',' ) . map ( &:strip ) . reject ( &:empty? ) ) : nil
352+ arch_filter = arch ? arch . split ( ',' ) . map ( &:strip ) . reject ( &:empty? ) : nil
353+
354+ filtered = all_payloads . select do |m |
355+ next false if arch_filter && ( Array ( m . arch . to_s . split ( ',' ) . map ( &:strip ) ) & arch_filter ) . empty?
356+
357+ next false if platform_filter && m . platform_list && ( m . platform_list & platform_filter ) . empty?
358+
359+ true
360+ end
361+
344362 tbl = Rex ::Text ::Table . new (
345363 'Indent' => 4 ,
346- 'Header' => "Framework Payloads (#{ framework . stats . num_payloads } total) [--payload <value>]" ,
364+ 'Header' => "Framework Payloads (#{ all_payloads . size } total) [--payload <value>]" ,
347365 'Columns' =>
348366 [
349367 "Name" ,
350368 "Description"
351369 ] )
352370
353- framework . payloads . each_module (
354- 'Platform' => platform ? Msf ::Module ::PlatformList . transform ( platform . split ( ',' ) ) : nil ,
355- 'Arch' => arch ? arch . split ( ',' ) : nil ) do |name , mod |
356- begin
357- mod_info = mod . new . description . split . join ( ' ' )
358- rescue ::Exception , ::LoadError => e
359- wlog ( "Module #{ name } failed to initialize: #{ e } " , 'core' , LEV_0 )
360- next
361- end
362- tbl << [ name , mod_info ]
371+ filtered . sort_by ( &:ref_name ) . each do |m |
372+ tbl << [ m . ref_name , m . description . to_s . split . join ( ' ' ) ]
363373 end
364374
365375 "\n " + tbl . to_s + "\n "
366376end
367377
368378def dump_encoders ( arch = nil )
369- init_framework ( :module_types => [ :encoder ] )
379+ require_deps unless @framework_loaded
380+ metadata_cache = Msf ::Modules ::Metadata ::Cache . instance
381+ all_encoders = metadata_cache . get_metadata . select { |m | m . type == 'encoder' }
382+
383+ arch_filter = arch ? arch . split ( ',' ) . map ( &:strip ) . reject ( &:empty? ) : nil
384+
385+ filtered = all_encoders . select do |m |
386+ next false if arch_filter && ( Array ( m . arch . to_s . split ( ',' ) . map ( &:strip ) ) & arch_filter ) . empty?
387+
388+ true
389+ end
390+
370391 tbl = Rex ::Text ::Table . new (
371392 'Indent' => 4 ,
372393 'Header' => "Framework Encoders" + ( ( arch ) ? " (architectures: #{ arch } )" : "" ) + " [--encoder <value>]" ,
@@ -378,29 +399,30 @@ def dump_encoders(arch = nil)
378399 ] )
379400 cnt = 0
380401
381- framework . encoders . each_module (
382- 'Arch' => arch ? arch . split ( ',' ) : nil ) do |name , mod |
383- tbl << [ name , mod . rank_to_s , mod . new . name ]
384-
385- cnt += 1
402+ filtered . sort_by ( &:ref_name ) . each do |m |
403+ tbl << [ m . ref_name , Msf ::RankingName [ m . rank ] || 'normal' , m . name ]
404+ cnt += 1
386405 end
387406
388407 ( cnt > 0 ) ? "\n " + tbl . to_s + "\n " : "\n No compatible encoders found.\n \n "
389408end
390409
391410def dump_nops
392- init_framework ( :module_types => [ :nop ] )
411+ require_deps unless @framework_loaded
412+ metadata_cache = Msf ::Modules ::Metadata ::Cache . instance
413+ all_nops = metadata_cache . get_metadata . select { |m | m . type == 'nop' }
414+
393415 tbl = Rex ::Text ::Table . new (
394416 'Indent' => 4 ,
395- 'Header' => "Framework NOPs (#{ framework . stats . num_nops } total)" ,
417+ 'Header' => "Framework NOPs (#{ all_nops . size } total)" ,
396418 'Columns' =>
397419 [
398420 "Name" ,
399421 "Description"
400422 ] )
401423
402- framework . nops . each_module do |name , mod |
403- tbl << [ name , mod . new . description . split . join ( ' ' ) ]
424+ all_nops . sort_by ( & :ref_name ) . each do |m |
425+ tbl << [ m . ref_name , m . description . to_s . split . join ( ' ' ) ]
404426 end
405427
406428 "\n " + tbl . to_s + "\n "
@@ -417,6 +439,21 @@ rescue MsfVenomError => e
417439 exit ( 1 )
418440end
419441
442+ if generator_opts [ :refresh_cache ]
443+ warn 'Refreshing module metadata cache...'
444+ require_deps unless @framework_loaded
445+ @framework = ::Msf ::Simple ::Framework . create ( { } )
446+ # Ensure the background cache load thread has finished before refreshing,
447+ # otherwise it can race and overwrite the refreshed in-memory cache.
448+ Msf ::Modules ::Metadata ::Cache . instance . get_metadata
449+ framework . modules . refresh_cache_from_module_files
450+ warn 'Module cache successfully refreshed.'
451+ # If no other action was requested, exit after refreshing
452+ unless generator_opts [ :list ] || generator_opts [ :list_options ] || generator_opts [ :payload ] != 'stdin'
453+ exit ( 0 )
454+ end
455+ end
456+
420457if generator_opts [ :list ]
421458 generator_opts [ :list ] . each do |mod |
422459 case mod . downcase
@@ -435,9 +472,6 @@ if generator_opts[:list]
435472 when "formats" , "format" , "f"
436473 $stdout. puts dump_formats
437474 when "all" , "a"
438- # Init here so #dump_payloads doesn't create a framework with
439- # only payloads, etc.
440- init_framework
441475 $stdout. puts dump_payloads
442476 $stdout. puts dump_encoders
443477 $stdout. puts dump_nops
0 commit comments