CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/lib/msf/ui/console/command_dispatcher/modules.rb
Views: 1904
# -*- coding: binary -*-123module Msf4module Ui5module Console6module CommandDispatcher78#9# {CommandDispatcher} for commands related to background jobs in Metasploit Framework.10#11class Modules1213include Msf::Ui::Console::CommandDispatcher14include Msf::Ui::Console::CommandDispatcher::Common1516include Rex::Text::Color1718@@search_opts = Rex::Parser::Arguments.new(19['-h', '--help'] => [false, 'Help banner'],20['-I', '--ignore'] => [false, 'Ignore the command if the only match has the same name as the search'],21['-o', '--output'] => [true, 'Send output to a file in csv format', '<filename>'],22['-S', '--filter'] => [true, 'Regex pattern used to filter search results', '<filter>'],23['-u', '--use'] => [false, 'Use module if there is one result'],24['-s', '--sort-ascending'] => [true, 'Sort search results by the specified column in ascending order', '<column>'],25['-r', '--sort-descending'] => [true, 'Reverse the order of search results to descending order', '<column>']26)2728@@favorite_opts = Rex::Parser::Arguments.new(29'-h' => [false, 'Help banner'],30'-c' => [false, 'Clear the contents of the favorite modules file'],31'-d' => [false, 'Delete module(s) or the current active module from the favorite modules file'],32'-l' => [false, 'Print the list of favorite modules (alias for `show favorites`)']33)3435@@favorites_opts = Rex::Parser::Arguments.new(36'-h' => [false, 'Help banner']37)3839def commands40{41"back" => "Move back from the current context",42"advanced" => "Displays advanced options for one or more modules",43"info" => "Displays information about one or more modules",44"options" => "Displays global options or for one or more modules",45"loadpath" => "Searches for and loads modules from a path",46"popm" => "Pops the latest module off the stack and makes it active",47"pushm" => "Pushes the active or list of modules onto the module stack",48"listm" => "List the module stack",49"clearm" => "Clear the module stack",50"previous" => "Sets the previously loaded module as the current module",51"reload_all" => "Reloads all modules from all defined module paths",52"search" => "Searches module names and descriptions",53"show" => "Displays modules of a given type, or all modules",54"use" => "Interact with a module by name or search term/index",55"favorite" => "Add module(s) to the list of favorite modules",56"favorites" => "Print the list of favorite modules (alias for `show favorites`)"57}58end5960#61# Initializes the datastore cache62#63def initialize(driver)64super6566@dscache = {}67@previous_module = nil68@module_name_stack = []69# Array of individual modules that have been searched for70@module_search_results = []71# Module search results, with additional metadata on what to do if the module is interacted with72@module_search_results_with_usage_metadata = []73@@payload_show_results = []74@dangerzone_map = nil75end7677#78# Returns the name of the command dispatcher.79#80def name81"Module"82end8384def cmd_advanced_help85print_line 'Usage: advanced [mod1 mod2 ...]'86print_line87print_line 'Queries the supplied module or modules for advanced options. If no module is given,'88print_line 'show advanced options for the currently active module.'89print_line90end9192def cmd_advanced(*args)93if args.empty?94if (active_module)95show_advanced_options(active_module)96return true97else98print_error('No module active')99return false100end101end102103args.each { |name|104mod = framework.modules.create(name)105106if (mod == nil)107print_error("Invalid module: #{name}")108else109show_advanced_options(mod)110end111}112end113114def cmd_info_help115print_line "Usage: info <module name> [mod2 mod3 ...]"116print_line117print_line "Options:"118print_line "* The flag '-j' will print the data in json format"119print_line "* The flag '-d' will show the markdown version with a browser. More info, but could be slow."120print_line "Queries the supplied module or modules for information. If no module is given,"121print_line "show info for the currently active module."122print_line123end124125def print_module_info(mod, dump_json: false, show_doc: false)126if dump_json127print(Serializer::Json.dump_module(mod) + "\n")128elsif show_doc129f = Tempfile.new(["#{mod.shortname}_doc", '.html'])130begin131print_status("Generating documentation for #{mod.shortname}, then opening #{f.path} in a browser...")132Msf::Util::DocumentGenerator.spawn_module_document(mod, f)133ensure134f.close if f135end136else137print(Serializer::ReadableText.dump_module(mod))138print("\nView the full module info with the #{Msf::Ui::Tip.highlight('info -d')} command.\n\n")139end140end141142# Handles the index selection formatting143def print_module_search_results_usage144last_mod_with_usage_metadata = @module_search_results_with_usage_metadata.last145index_usage = "use #{@module_search_results_with_usage_metadata.length - 1}"146index_info = "info #{@module_search_results_with_usage_metadata.length - 1}"147name_usage = "use #{last_mod_with_usage_metadata[:mod].fullname}"148149additional_usage_message = ""150additional_usage_example = (last_mod_with_usage_metadata[:datastore] || {}).first151if framework.features.enabled?(Msf::FeatureManager::HIERARCHICAL_SEARCH_TABLE) && additional_usage_example152key, value = additional_usage_example153additional_usage_message = "\nAfter interacting with a module you can manually set a #{key} with %grnset #{key} '#{value}'%clr"154end155print("Interact with a module by name or index. For example %grn#{index_info}%clr, %grn#{index_usage}%clr or %grn#{name_usage}%clr#{additional_usage_message}\n\n")156end157158#159# Displays information about one or more module.160#161def cmd_info(*args)162dump_json = false163show_doc = false164165if args.include?('-j')166args.delete('-j')167dump_json = true168end169170if args.include?('-d')171args.delete('-d')172show_doc = true173end174175if (args.length == 0)176if active_module177print_module_info(active_module, dump_json: dump_json, show_doc: show_doc)178return true179else180cmd_info_help181return false182end183elsif args.include? '-h'184cmd_info_help185return false186end187188args.each do |arg|189mod_name = arg190191additional_datastore_values = nil192193# Use a module by search index194index_from_list(@module_search_results_with_usage_metadata, mod_name) do |result|195mod = result&.[](:mod)196next unless mod && mod.respond_to?(:fullname)197198# Module cache object199mod_name = mod.fullname200additional_datastore_values = result[:datastore]201end202203# Ensure we have a reference name and not a path204name = trim_path(mod_name, 'modules')205206# Creates an instance of the module207mod = framework.modules.create(name)208209# If any additional datastore values were provided, set these values210mod.datastore.update(additional_datastore_values) unless additional_datastore_values.nil?211212if mod.nil?213print_error("Invalid module: #{name}")214else215print_module_info(mod, dump_json: dump_json, show_doc: show_doc)216end217end218end219220def cmd_options_help221print_line 'Usage: options [mod1 mod2 ...]'222print_line223print_line 'Queries the supplied module or modules for options. If no module is given,'224print_line 'show options for the currently active module.'225print_line226end227228def cmd_options(*args)229if args.empty?230if (active_module)231show_options(active_module)232return true233else234show_global_options235return true236end237end238239args.each do |name|240mod = framework.modules.create(name)241242if (mod == nil)243print_error("Invalid module: #{name}")244else245show_options(mod)246end247end248end249250#251# Tab completion for the advanced command (same as use)252#253# @param str (see #cmd_use_tabs)254# @param words (see #cmd_use_tabs)255256def cmd_advanced_tabs(str, words)257cmd_use_tabs(str, words)258end259260#261# Tab completion for the advanced command (same as use)262#263# @param str (see #cmd_use_tabs)264# @param words (see #cmd_use_tabs)265266def cmd_info_tabs(str, words)267cmd_use_tabs(str, words)268end269270#271# Tab completion for the advanced command (same as use)272#273# @param str (see #cmd_use_tabs)274# @param words (see #cmd_use_tabs)275276def cmd_options_tabs(str, words)277cmd_use_tabs(str, words)278end279280def cmd_loadpath_help281print_line "Usage: loadpath </path/to/modules>"282print_line283print_line "Loads modules from the given directory which should contain subdirectories for"284print_line "module types, e.g. /path/to/modules/exploits"285print_line286end287288#289# Adds one or more search paths.290#291def cmd_loadpath(*args)292if (args.length == 0 or args.include? "-h")293cmd_loadpath_help294return true295end296297totals = {}298overall = 0299curr_path = nil300301begin302# Walk the list of supplied search paths attempting to add each one303# along the way304args.each { |path|305curr_path = path306307# Load modules, but do not consult the cache308if (counts = framework.modules.add_module_path(path))309counts.each_pair { |type, count|310totals[type] = (totals[type]) ? (totals[type] + count) : count311312overall += count313}314end315}316rescue NameError, RuntimeError317log_error("Failed to add search path #{curr_path}: #{$!}")318return true319end320321added = "Loaded #{overall} modules:\n"322323totals.sort_by { |type, _count| type }.each { |type, count|324added << " #{count} #{type} modules\n"325}326327print(added)328end329330#331# Tab completion for the loadpath command332#333# @param str [String] the string currently being typed before tab was hit334# @param words [Array<String>] the previously completed words on the command line. words is always335# at least 1 when tab completion has reached this stage since the command itself has been completed336337def cmd_loadpath_tabs(str, words)338return [] if words.length > 1339340# This custom completion might better than Readline's... We'll leave it for now.341#tab_complete_filenames(str,words)342343paths = []344if (File.directory?(str))345paths = Dir.entries(str)346paths = paths.map { |f|347if File.directory? File.join(str,f)348File.join(str,f)349end350}351paths.delete_if { |f| f.nil? or File.basename(f) == '.' or File.basename(f) == '..' }352else353d = Dir.glob(str + "*").map { |f| f if File.directory?(f) }354d.delete_if { |f| f.nil? or f == '.' or f == '..' }355# If there's only one possibility, descend to the next level356if (1 == d.length)357paths = Dir.entries(d[0])358paths = paths.map { |f|359if File.directory? File.join(d[0],f)360File.join(d[0],f)361end362}363paths.delete_if { |f| f.nil? or File.basename(f) == '.' or File.basename(f) == '..' }364else365paths = d366end367end368paths.sort!369return paths370end371372def cmd_search_help373print_line "Usage: search [<options>] [<keywords>:<value>]"374print_line375print_line "Prepending a value with '-' will exclude any matching results."376print_line "If no options or keywords are provided, cached results are displayed."377print_line378print @@search_opts.usage379print_line380print_line "Keywords:"381{382'adapter' => 'Modules with a matching adater reference name',383'aka' => 'Modules with a matching AKA (also-known-as) name',384'author' => 'Modules written by this author',385'arch' => 'Modules affecting this architecture',386'bid' => 'Modules with a matching Bugtraq ID',387'cve' => 'Modules with a matching CVE ID',388'edb' => 'Modules with a matching Exploit-DB ID',389'check' => 'Modules that support the \'check\' method',390'date' => 'Modules with a matching disclosure date',391'description' => 'Modules with a matching description',392'fullname' => 'Modules with a matching full name',393'mod_time' => 'Modules with a matching modification date',394'name' => 'Modules with a matching descriptive name',395'path' => 'Modules with a matching path',396'platform' => 'Modules affecting this platform',397'port' => 'Modules with a matching port',398'rank' => 'Modules with a matching rank (Can be descriptive (ex: \'good\') or numeric with comparison operators (ex: \'gte400\'))',399'ref' => 'Modules with a matching ref',400'reference' => 'Modules with a matching reference',401'session_type' => 'Modules with a matching session type (SMB, MySQL, Meterpreter, etc)',402'stage' => 'Modules with a matching stage reference name',403'stager' => 'Modules with a matching stager reference name',404'target' => 'Modules affecting this target',405'type' => 'Modules of a specific type (exploit, payload, auxiliary, encoder, evasion, post, or nop)',406'action' => 'Modules with a matching action name or description',407}.each_pair do |keyword, description|408print_line " #{keyword.ljust 17}: #{description}"409end410print_line411print_line "Supported search columns:"412{413'rank' => 'Sort modules by their exploitability rank',414'date' => 'Sort modules by their disclosure date. Alias for disclosure_date',415'disclosure_date' => 'Sort modules by their disclosure date',416'name' => 'Sort modules by their name',417'type' => 'Sort modules by their type',418'check' => 'Sort modules by whether or not they have a check method',419'action' => 'Sort modules by whether or not they have actions',420}.each_pair do |keyword, description|421print_line " #{keyword.ljust 17}: #{description}"422end423print_line424print_line "Examples:"425print_line " search cve:2009 type:exploit"426print_line " search cve:2009 type:exploit platform:-linux"427print_line " search cve:2009 -s name"428print_line " search type:exploit -s type -r"429print_line430end431432#433# Searches modules for specific keywords434#435def cmd_search(*args)436match = ''437row_filter = nil438output_file = nil439cached = false440use = false441count = -1442search_terms = []443sort_attribute = 'name'444valid_sort_attributes = ['action', 'rank','disclosure_date','name','date','type','check']445reverse_sort = false446ignore_use_exact_match = false447448@@search_opts.parse(args) do |opt, idx, val|449case opt450when '-S'451row_filter = val452when '-h'453cmd_search_help454return false455when '-o'456output_file = val457when '-u'458use = true459when '-I'460ignore_use_exact_match = true461when '-s'462sort_attribute = val463when '-r'464reverse_sort = true465else466match += val + ' '467end468end469470if args.empty?471if @module_search_results_with_usage_metadata.empty?472cmd_search_help473return false474end475476cached = true477end478479if sort_attribute && !valid_sort_attributes.include?(sort_attribute)480print_error("Supported options for the -s flag are: #{valid_sort_attributes}")481return false482end483484begin485if cached486print_status('Displaying cached results')487else488search_params = Msf::Modules::Metadata::Search.parse_search_string(match)489@module_search_results = Msf::Modules::Metadata::Cache.instance.find(search_params)490491@module_search_results.sort_by! do |module_metadata|492if sort_attribute == 'action'493module_metadata.actions&.any? ? 0 : 1494elsif sort_attribute == 'check'495module_metadata.check ? 0 : 1496elsif sort_attribute == 'disclosure_date' || sort_attribute == 'date'497# Not all modules have disclosure_date, i.e. multi/handler498module_metadata.disclosure_date || Time.utc(0)499else500module_metadata.send(sort_attribute)501end502end503504if reverse_sort505@module_search_results.reverse!506end507end508509if @module_search_results.empty?510print_error('No results from search')511return false512end513514if ignore_use_exact_match && @module_search_results.length == 1 &&515@module_search_results.first.fullname == match.strip516return false517end518519if !search_params.nil? && !search_params['text'].nil?520search_params['text'][0].each do |t|521search_terms << t522end523end524525# Generate the table used to display matches526tbl = generate_module_table('Matching Modules', search_terms, row_filter)527528@module_search_results_with_usage_metadata = []529@module_search_results.each do |m|530@module_search_results_with_usage_metadata << { mod: m }531count += 1532tbl << [533count,534"#{m.fullname}",535m.disclosure_date.nil? ? '' : m.disclosure_date.strftime("%Y-%m-%d"),536m.rank,537m.check ? 'Yes' : 'No',538m.name,539]540541if framework.features.enabled?(Msf::FeatureManager::HIERARCHICAL_SEARCH_TABLE)542total_children_rows = (m.actions&.length || 0) + (m.targets&.length || 0) + (m.notes&.[]('AKA')&.length || 0)543show_child_items = total_children_rows > 1544next unless show_child_items545546indent = " \\_ "547# Note: We still use visual indicators for blank values as it's easier to read548# We can't always use a generic formatter/styler, as it would be applied to the 'parent' rows too549blank_value = '.'550if (m.actions&.length || 0) > 1551m.actions.each do |action|552@module_search_results_with_usage_metadata << { mod: m, datastore: { 'ACTION' => action['name'] } }553count += 1554tbl << [555count,556"#{indent}action: #{action['name']}",557blank_value,558blank_value,559blank_value,560action['description'],561]562end563end564565if (m.targets&.length || 0) > 1566m.targets.each do |target|567@module_search_results_with_usage_metadata << { mod: m, datastore: { 'TARGET' => target } }568count += 1569tbl << [570count,571"#{indent}target: #{target}",572blank_value,573blank_value,574blank_value,575blank_value576]577end578end579580if (m.notes&.[]('AKA')&.length || 0) > 1581m.notes['AKA'].each do |aka|582@module_search_results_with_usage_metadata << { mod: m }583count += 1584tbl << [585count,586"#{indent}AKA: #{aka}",587blank_value,588blank_value,589blank_value,590blank_value591]592end593end594end595end596rescue ArgumentError597print_error("Invalid argument(s)\n")598cmd_search_help599return false600end601602if output_file603print_status("Wrote search results to #{output_file}")604::File.open(output_file, "wb") { |ofd|605ofd.write(tbl.to_csv)606}607return true608end609610print_line(tbl.to_s)611print_module_search_results_usage612613if @module_search_results.length == 1 && use614used_module = @module_search_results_with_usage_metadata.first[:mod].fullname615print_status("Using #{used_module}") if used_module616cmd_use(used_module, true)617end618619true620end621622#623# Tab completion for the search command624#625# @param str [String] the string currently being typed before tab was hit626# @param words [Array<String>] the previously completed words on the command line. words is always627# at least 1 when tab completion has reached this stage since the command itself has been completed628629def cmd_search_tabs(str, words)630if words.length == 1631return @@search_opts.option_keys632end633634[]635end636637def cmd_show_help638global_opts = %w{all encoders nops exploits payloads auxiliary post plugins info options favorites}639print_status("Valid parameters for the \"show\" command are: #{global_opts.join(", ")}")640641module_opts = %w{ missing advanced evasion targets actions }642print_status("Additional module-specific parameters are: #{module_opts.join(", ")}")643end644645#646# Displays the list of modules based on their type, or all modules if647# no type is provided.648#649def cmd_show(*args)650if args.empty?651print_error("Argument required\n")652cmd_show_help653return654end655656mod = self.active_module657658args.each { |type|659case type660when '-h'661cmd_show_help662when 'all'663show_encoders664show_nops665show_exploits666show_payloads667show_auxiliary668show_post669show_plugins670when 'encoders'671show_encoders672when 'nops'673show_nops674when 'exploits'675show_exploits676when 'payloads'677show_payloads678when 'auxiliary'679show_auxiliary680when 'post'681show_post682when 'favorites'683show_favorites684when 'info'685cmd_info(*args[1, args.length])686when 'options'687if (mod)688show_options(mod)689else690show_global_options691end692when 'missing'693if (mod)694show_missing(mod)695else696print_error("No module selected.")697end698when 'advanced'699if (mod)700show_advanced_options(mod)701else702print_error("No module selected.")703end704when 'evasion'705if (mod)706show_evasion_options(mod)707else708show_evasion709end710when 'sessions'711if (active_module and active_module.respond_to?(:compatible_sessions))712sessions = active_module.compatible_sessions713else714sessions = framework.sessions.keys.sort715end716print_line717print(Serializer::ReadableText.dump_sessions(framework, :session_ids => sessions))718print_line719when "plugins"720show_plugins721when "targets"722if (mod and (mod.exploit? or mod.evasion?))723show_targets(mod)724else725print_error("No exploit module selected.")726end727when "actions"728if mod && mod.kind_of?(Msf::Module::HasActions)729show_actions(mod)730else731print_error("No module with actions selected.")732end733734else735print_error("Invalid parameter \"#{type}\", use \"show -h\" for more information")736end737}738end739740#741# Tab completion for the show command742#743# @param str [String] the string currently being typed before tab was hit744# @param words [Array<String>] the previously completed words on the command line. words is always745# at least 1 when tab completion has reached this stage since the command itself has been completed746747def cmd_show_tabs(str, words)748return [] if words.length > 1749750res = %w{all encoders nops exploits payloads auxiliary post plugins options favorites}751if (active_module)752res.concat %w{missing advanced evasion targets actions info}753if (active_module.respond_to? :compatible_sessions)754res << "sessions"755end756end757return res758end759760def cmd_use_help761print_line 'Usage: use <name|term|index>'762print_line763print_line 'Interact with a module by name or search term/index.'764print_line 'If a module name is not found, it will be treated as a search term.'765print_line 'An index from the previous search results can be selected if desired.'766print_line767print_line 'Examples:'768print_line ' use exploit/windows/smb/ms17_010_eternalblue'769print_line770print_line ' use eternalblue'771print_line ' use <name|index>'772print_line773print_line ' search eternalblue'774print_line ' use <name|index>'775print_line776print_april_fools_module_use777end778779#780# Uses a module.781#782def cmd_use(*args)783if args.length == 0 || args.first == '-h'784cmd_use_help785return false786end787788# Divert logic for dangerzone mode789args = dangerzone_codename_to_module(args)790791# Try to create an instance of the supplied module name792mod_name = args[0]793794additional_datastore_values = nil795796# Use a module by search index797index_from_list(@module_search_results_with_usage_metadata, mod_name) do |result|798mod = result&.[](:mod)799unless mod && mod.respond_to?(:fullname)800print_error("Invalid module index: #{mod_name}")801return false802end803804# Module cache object from @module_search_results_with_usage_metadata805mod_name = mod.fullname806additional_datastore_values = result[:datastore]807end808809# See if the supplied module name has already been resolved810mod_resolved = args[1] == true ? true : false811812# Ensure we have a reference name and not a path813mod_name = trim_path(mod_name, "modules")814815begin816mod = framework.modules.create(mod_name)817818unless mod819# Checks to see if we have any load_errors for the current module.820# and if so, returns them to the user.821load_error = framework.modules.load_error_by_name(mod_name)822if load_error823print_error("Failed to load module: #{load_error}")824return false825end826unless mod_resolved827elog("Module #{mod_name} not found, and no loading errors found. If you're using a custom module" \828' refer to our wiki: https://docs.metasploit.com/docs/using-metasploit/intermediate/running-private-modules.html')829830# Avoid trying to use the search result if it exactly matches831# the module we were trying to load. The module cannot be832# loaded and searching isn't going to change that.833mods_found = cmd_search('-I', '-u', *args)834end835836unless mods_found837print_error("Failed to load module: #{mod_name}")838return false839end840end841rescue Rex::AmbiguousArgumentError => info842print_error(info.to_s)843rescue NameError => info844log_error("The supplied module name is ambiguous: #{$!}.")845end846847return false if (mod == nil)848849# Enstack the command dispatcher for this module type850dispatcher = nil851852case mod.type853when Msf::MODULE_ENCODER854dispatcher = Msf::Ui::Console::CommandDispatcher::Encoder855when Msf::MODULE_EXPLOIT856dispatcher = Msf::Ui::Console::CommandDispatcher::Exploit857when Msf::MODULE_NOP858dispatcher = Msf::Ui::Console::CommandDispatcher::Nop859when Msf::MODULE_PAYLOAD860dispatcher = Msf::Ui::Console::CommandDispatcher::Payload861when Msf::MODULE_AUX862dispatcher = Msf::Ui::Console::CommandDispatcher::Auxiliary863when Msf::MODULE_POST864dispatcher = Msf::Ui::Console::CommandDispatcher::Post865when Msf::MODULE_EVASION866dispatcher = Msf::Ui::Console::CommandDispatcher::Evasion867else868print_error("Unsupported module type: #{mod.type}")869return false870end871872# If there's currently an active module, enqueque it and go back873if (active_module)874@previous_module = active_module875cmd_back()876end877878if (dispatcher != nil)879driver.enstack_dispatcher(dispatcher)880end881882# Update the active module883self.active_module = mod884885# If a datastore cache exists for this module, then load it up886if @dscache[active_module.fullname]887active_module.datastore.update(@dscache[active_module.fullname])888end889890# If any additional datastore values were provided, set these values891unless additional_datastore_values.nil? || additional_datastore_values.empty?892mod.datastore.update(additional_datastore_values)893print_status("Additionally setting #{additional_datastore_values.map { |k,v| "#{k} => #{v}" }.join(", ")}")894if additional_datastore_values['TARGET'] && (mod.exploit? || mod.evasion?)895mod.import_target_defaults896end897end898899# Choose a default payload when the module is used, not run900if mod.datastore['PAYLOAD']901print_status("Using configured payload #{mod.datastore['PAYLOAD']}")902elsif dispatcher.respond_to?(:choose_payload)903chosen_payload = dispatcher.choose_payload(mod)904print_status("No payload configured, defaulting to #{chosen_payload}") if chosen_payload905end906907mod.init_ui(driver.input, driver.output)908end909910#911# Command to take to the previously active module912#913def cmd_previous(*args)914if @previous_module915self.cmd_use(@previous_module.fullname)916else917print_error("There isn't a previous module at the moment")918end919end920921#922# Help for the 'previous' command923#924def cmd_previous_help925print_line "Usage: previous"926print_line927print_line "Set the previously loaded module as the current module"928print_line929print_line "Previous module: #{@previous_module ? @previous_module.fullname : 'none'}"930print_line931end932933#934# Command to enqueque a module on the module stack935#936def cmd_pushm(*args)937# could check if each argument is a valid module, but for now let them hang themselves938if args.count > 0939args.each do |arg|940@module_name_stack.push(arg)941# Note new modules are appended to the array and are only module (full)names942end943else #then just push the active module944if active_module945#print_status "Pushing the active module"946@module_name_stack.push(active_module.fullname)947else948print_error("There isn't an active module and you didn't specify a module to push")949return self.cmd_pushm_help950end951end952end953954#955# Tab completion for the pushm command956#957# @param str [String] the string currently being typed before tab was hit958# @param words [Array<String>] the previously completed words on the command line. words is always959# at least 1 when tab completion has reached this stage since the command itself has been completed960961def cmd_pushm_tabs(str, words)962tab_complete_module(str, words)963end964965#966# Help for the 'pushm' command967#968def cmd_pushm_help969print_line "Usage: pushm [module1 [,module2, module3...]]"970print_line971print_line "push current active module or specified modules onto the module stack"972print_line973end974975#976# Command to dequeque a module from the module stack977#978def cmd_popm(*args)979if (args.count > 1 or not args[0].respond_to?("to_i"))980return self.cmd_popm_help981elsif args.count == 1982# then pop 'n' items off the stack, but don't change the active module983if args[0].to_i >= @module_name_stack.count984# in case they pass in a number >= the length of @module_name_stack985@module_name_stack = []986print_status("The module stack is empty")987else988@module_name_stack.pop(args[0].to_i)989end990else #then just pop the array and make that the active module991pop = @module_name_stack.pop992if pop993return self.cmd_use(pop)994else995print_error("There isn't anything to pop, the module stack is empty")996end997end998end9991000#1001# Help for the 'popm' command1002#1003def cmd_popm_help1004print_line "Usage: popm [n]"1005print_line1006print_line "pop the latest module off of the module stack and make it the active module"1007print_line "or pop n modules off the stack, but don't change the active module"1008print_line1009end10101011def cmd_listm_help1012print_line 'Usage: listm'1013print_line1014print_line 'List the module stack'1015print_line1016end10171018def cmd_listm(*_args)1019if @module_name_stack.empty?1020print_error('The module stack is empty')1021return1022end10231024print_status("Module stack:\n")10251026@module_name_stack.to_enum.with_index.reverse_each do |name, idx|1027print_line("[#{idx}]\t#{name}")1028end1029end10301031def cmd_clearm_help1032print_line 'Usage: clearm'1033print_line1034print_line 'Clear the module stack'1035print_line1036end10371038def cmd_clearm(*_args)1039print_status('Clearing the module stack')1040@module_name_stack.clear1041end10421043#1044# Tab completion for the use command1045#1046# @param str [String] the string currently being typed before tab was hit1047# @param words [Array<String>] the previously completed words on the command line. words is always1048# at least 1 when tab completion has reached this stage since the command itself has been completed10491050def cmd_use_tabs(str, words)1051return [] if words.length > 110521053tab_complete_module(str, words)1054end10551056def cmd_reload_all_help1057print_line "Usage: reload_all"1058print_line1059print_line "Reload all modules from all configured module paths. This may take awhile."1060print_line "See also: loadpath"1061print_line1062end10631064#1065# Reload all module paths that we are aware of1066#1067def cmd_reload_all(*args)1068if args.length > 01069cmd_reload_all_help1070return1071end10721073print_status("Reloading modules from all module paths...")1074framework.modules.reload_modules10751076log_msg = "Please see #{File.join(Msf::Config.log_directory, 'framework.log')} for details."10771078# Check for modules that failed to load1079if framework.modules.module_load_error_by_path.length > 01080wlog("WARNING! The following modules could not be loaded!")10811082framework.modules.module_load_error_by_path.each do |path, _error|1083wlog("\t#{path}")1084end10851086wlog(log_msg)1087end10881089if framework.modules.module_load_warnings.length > 01090wlog("The following modules were loaded with warnings:")10911092framework.modules.module_load_warnings.each do |path, _error|1093wlog("\t#{path}")1094end10951096wlog(log_msg)1097end10981099self.driver.run_single('reload')1100self.driver.run_single("banner")1101end11021103def cmd_back_help1104print_line "Usage: back"1105print_line1106print_line "Return to the global dispatcher context"1107print_line1108end11091110#1111# Pop the current dispatcher stack context, assuming it isn't pointed at1112# the core or database backend stack context.1113#1114def cmd_back(*args)1115if (driver.dispatcher_stack.size > 1 and1116driver.current_dispatcher.name != 'Core' and1117driver.current_dispatcher.name != 'Database Backend')1118# Reset the active module if we have one1119if (active_module)11201121# Do NOT reset the UI anymore1122# active_module.reset_ui11231124# Save the module's datastore so that we can load it later1125# if the module is used again1126@dscache[active_module.fullname] = active_module.datastore.dup11271128self.active_module = nil1129end11301131# Destack the current dispatcher1132driver.destack_dispatcher1133end1134end11351136def cmd_favorite_help1137print_line 'Usage: favorite [mod1 mod2 ...]'1138print_line1139print_line "Add one or multiple modules to the list of favorite modules stored in #{Msf::Config.fav_modules_file}"1140print_line 'If no module name is specified, the command will add the active module if there is one'1141print @@favorite_opts.usage1142end11431144#1145# Helper method for cmd_favorite that writes modules to the fav_modules_file1146#1147def favorite_add(modules, favs_file)1148fav_limit = 501149# obtain useful info about the fav_modules file1150exists, writable, readable, contents = favorite_check_fav_modules(favs_file)11511152# if the fav_modules file exists, check the file permissions1153if exists1154case1155when !writable1156print_error("Unable to save module(s) to the favorite modules file because it is not writable")1157return1158when !readable1159print_error("Unable to save module(s) to the favorite modules file because it is not readable")1160return1161end1162end11631164fav_count = 01165if contents1166fav_count = contents.split.size1167end11681169modules = modules.uniq # prevent modules from being added more than once1170modules.each do |name|1171mod = framework.modules.create(name)1172if (mod == nil)1173print_error("Invalid module: #{name}")1174next1175end11761177if contents && contents.include?(mod.fullname)1178print_warning("Module #{mod.fullname} has already been favorited and will not be added to the favorite modules file")1179next1180end11811182if fav_count >= fav_limit1183print_error("Favorite module limit (#{fav_limit}) exceeded. No more modules will be added.")1184return1185end11861187File.open(favs_file, 'a+') { |file| file.puts(mod.fullname) }1188print_good("Added #{mod.fullname} to the favorite modules file")1189fav_count += 11190end1191return1192end11931194#1195# Helper method for cmd_favorite that deletes modules from the fav_modules_file1196#1197def favorite_del(modules, delete_all, favs_file)1198# obtain useful info about the fav_modules file1199exists, writable, readable, contents = favorite_check_fav_modules(favs_file)12001201if delete_all1202custom_message = 'clear the contents of'1203else1204custom_message = 'delete module(s) from'1205end12061207case # error handling based on the existence / permissions of the fav_modules file1208when !exists1209print_warning("Unable to #{custom_message} the favorite modules file because it does not exist")1210return1211when !writable1212print_error("Unable to #{custom_message} the favorite modules file because it is not writable")1213return1214when !readable1215unless delete_all1216print_error("Unable to #{custom_message} the favorite modules file because it is not readable")1217return1218end1219when contents.empty?1220print_warning("Unable to #{custom_message} the favorite modules file because it is already empty")1221return1222end12231224if delete_all1225File.write(favs_file, '')1226print_good("Favorite modules file cleared")1227return1228end12291230modules = modules.uniq # prevent modules from being deleted more than once1231contents = contents.split1232modules.each do |name|1233mod = framework.modules.create(name)1234if (mod == nil)1235print_error("Invalid module: #{name}")1236next1237end12381239unless contents.include?(mod.fullname)1240print_warning("Module #{mod.fullname} cannot be deleted because it is not in the favorite modules file")1241next1242end12431244contents.delete(mod.fullname)1245print_status("Removing #{mod.fullname} from the favorite modules file")1246end12471248# clear the contents of the fav_modules file if removing the module(s) makes it empty1249if contents.length == 01250File.write(favs_file, '')1251return1252end12531254File.open(favs_file, 'w') { |file| file.puts(contents.join("\n")) }1255end12561257#1258# Helper method for cmd_favorite that checks if the fav_modules file exists and is readable / writable1259#1260def favorite_check_fav_modules(favs_file)1261exists = false1262writable = false1263readable = false1264contents = ''12651266if File.exist?(favs_file)1267exists = true1268end12691270if File.writable?(favs_file)1271writable = true1272end12731274if File.readable?(favs_file)1275readable = true1276contents = File.read(favs_file)1277end12781279return exists, writable, readable, contents1280end12811282#1283# Add modules to or delete modules from the fav_modules file1284#1285def cmd_favorite(*args)1286valid_custom_args = ['-c', '-d', '-l']1287favs_file = Msf::Config.fav_modules_file12881289# always display the help banner if -h is provided or if multiple options are provided1290if args.include?('-h') || args.select{ |arg| arg if valid_custom_args.include?(arg) }.length > 11291cmd_favorite_help1292return1293end12941295# if no arguments were provided, check if there is an active module to add1296if args.empty?1297unless active_module1298print_error('No module has been provided to favorite.')1299cmd_favorite_help1300return1301end13021303args = [active_module.fullname]1304favorite_add(args, favs_file)1305return1306end13071308case args[0]1309when '-c'1310args.delete('-c')1311unless args.empty?1312print_error('Option `-c` does not support arguments.')1313cmd_favorite_help1314return1315end13161317favorite_del(args, true, favs_file)1318when '-d'1319args.delete('-d')1320if args.empty?1321unless active_module1322print_error('No module has been provided to delete.')1323cmd_favorite_help1324return1325end13261327args = [active_module.fullname]1328end13291330favorite_del(args, false, favs_file)1331when '-l'1332args.delete('-l')1333unless args.empty?1334print_error('Option `-l` does not support arguments.')1335cmd_favorite_help1336return1337end1338cmd_show('favorites')1339else # no valid options, but there are arguments1340if args[0].start_with?('-')1341print_error('Invalid option provided')1342cmd_favorite_help1343return1344end13451346favorite_add(args, favs_file)1347end1348end13491350def cmd_favorites_help1351print_line 'Usage: favorites'1352print_line1353print_line 'Print the list of favorite modules (alias for `show favorites`)'1354print_line 'You can use the %grnfavorite%clr command to add the current module to your favorites list'1355print @@favorites_opts.usage1356end13571358#1359# Print the list of favorite modules from the fav_modules file (alias for `show favorites`)1360#1361def cmd_favorites(*args)1362if args.empty?1363cmd_show('favorites')1364return1365end13661367# always display the help banner if the command is called with arguments1368unless args.include?('-h')1369print_error('Invalid option(s) provided')1370end13711372cmd_favorites_help1373end13741375#1376# Tab complete module names1377#1378def tab_complete_module(str, words)1379res = []1380module_metadata = Msf::Modules::Metadata::Cache.instance.get_metadata1381module_metadata.each do |m|1382res << "#{m.type}/#{m.ref_name}"1383end1384framework.modules.module_types.each do |mtyp|1385mset = framework.modules.module_names(mtyp)1386mset.each do |mref|1387res << mtyp + '/' + mref1388end1389end13901391return dangerzone_modules_to_codenames(res.sort) if dangerzone_active?1392return res.uniq.sort1393end13941395def print_april_fools_module_use1396return unless ENV['APRILFOOLSMODULEUSE'] || Time.now.strftime("%m%d") == "0401"13971398banner = Msf::Ui::Banner.readfile('help-using-a-module.txt')1399print_line("%grn#{banner}%clr")1400end14011402#1403# Convert squirrel names back to regular module names1404#1405def dangerzone_codename_to_module(args)1406return args unless dangerzone_active? && args.length > 0 && args[0].length > 01407return args unless args[0] =~ /^[A-Z]/1408args[0] = dangerzone_codename_to_module_name(args[0])1409args1410end14111412#1413# Determine if dangerzone mode is active via date or environment variable1414#1415def dangerzone_active?1416active = Time.now.strftime("%m%d") == "0401" || Rex::Compat.getenv('DANGERZONE').to_i > 01417if active && @dangerzone_map.nil?1418dangerzone_build_map1419end1420active1421end14221423#1424# Convert module names to squirrel names1425#1426def dangerzone_modules_to_codenames(names)1427(names + @dangerzone_map.keys.grep(/^[A-Z]+/)).sort1428end14291430def dangerzone_codename_to_module_name(cname)1431@dangerzone_map[cname] || cname1432end14331434def dangerzone_module_name_to_codename(mname)1435@dangerzone_map[mname] || mname1436end14371438def dangerzone_build_map1439return unless @dangerzone_map.nil?14401441@dangerzone_map = {}14421443res = []1444%W{exploit auxiliary}.each do |mtyp|1445mset = framework.modules.module_names(mtyp)1446mset.each do |mref|1447res << mtyp + '/' + mref1448end1449end14501451words_a = ::File.readlines(::File.join(1452::Msf::Config.data_directory, "wordlists", "dangerzone_a.txt"1453)).map{|line| line.strip.upcase}14541455words_b = ::File.readlines(::File.join(1456::Msf::Config.data_directory, "wordlists", "dangerzone_b.txt"1457)).map{|line| line.strip.upcase}14581459aidx = -11460bidx = -114611462res.sort.each do |mname|1463word_a = words_a[ (aidx += 1) % words_a.length ]1464word_b = words_b[ (bidx += 1) % words_b.length ]1465cname = word_a + word_b14661467while @dangerzone_map[cname]1468aidx += 11469word_a = words_a[ (aidx += 1) % words_a.length ]1470cname = word_a + word_b1471end14721473@dangerzone_map[mname] = cname1474@dangerzone_map[cname] = mname1475end1476end14771478#1479# Module list enumeration1480#14811482def show_encoders # :nodoc:1483# If an active module has been selected and it's an exploit, get the1484# list of compatible encoders and display them1485if (active_module and active_module.exploit? == true)1486show_module_metadata('Compatible Encoders', active_module.compatible_encoders)1487else1488show_module_metadata('Encoders', 'encoder')1489end1490end14911492def show_nops # :nodoc:1493show_module_metadata('NOP Generators', 'nop')1494end14951496def show_exploits # :nodoc:1497show_module_metadata('Exploits', 'exploit')1498end14991500def show_payloads # :nodoc:1501# If an active module has been selected and it's an exploit, get the1502# list of compatible payloads and display them1503if active_module && (active_module.exploit? || active_module.evasion?)1504@@payload_show_results = active_module.compatible_payloads15051506show_module_metadata('Compatible Payloads', @@payload_show_results)1507else1508# show_module_set(‘Payloads’, framework.payloads, regex, minrank, opts)1509show_module_metadata('Payloads', 'payload')1510end1511end15121513def show_auxiliary # :nodoc:1514show_module_metadata('Auxiliary','auxiliary')1515end15161517def show_post # :nodoc:1518show_module_metadata('Post','post')1519end15201521def show_evasion # :nodoc:1522show_module_metadata('Evasion','evasion')1523end15241525def show_favorites # :nodoc:1526favs_file = Msf::Config.fav_modules_file15271528unless File.exist?(favs_file)1529print_error("The favorite modules file does not exist")1530return1531end15321533if File.zero?(favs_file)1534print_warning("The favorite modules file is empty")1535return1536end15371538unless File.readable?(favs_file)1539print_error("Unable to read from #{favs_file}")1540return1541end15421543# create module set using the saved modules1544fav_modules = {}15451546# get the full module names from the favorites file and use then to search the MetaData Cache for matching modules1547saved_favs = File.readlines(favs_file).map(&:strip)1548saved_favs.each do |mod|1549# populate hash with module fullname and module object1550fav_modules[mod] = framework.modules[mod]1551end15521553fav_modules.each do |fullname, mod_obj|1554if mod_obj.nil?1555print_warning("#{favs_file} contains a module that can not be found - #{fullname}.")1556end1557end15581559# find cache module instance and add it to @module_search_results1560@module_search_results = Msf::Modules::Metadata::Cache.instance.find('fullname' => [saved_favs, []])15611562# This scenario is for when a module fullname is a substring of other module fullnames1563# Example, searching for the payload/windows/meterpreter/reverse_tcp module can result in matches for:1564# - windows/meterpreter/reverse_tcp_allports1565# - windows/meterpreter/reverse_tcp_dns1566# So if @module_search_results is greater than the amount of fav_modules, we need to filter the results to be more accurate1567if fav_modules.length < @module_search_results.length1568filtered_results = []1569fav_modules.each do |fullname, _mod_obj|1570filtered_results << @module_search_results.select do |search_result|1571search_result.fullname == fullname1572end1573end1574@module_search_results = filtered_results.flatten.sort_by(&:fullname)1575end1576@module_search_results_with_usage_metadata = @module_search_results.map { |mod| { mod: mod, datastore: {} } }15771578show_module_metadata('Favorites', fav_modules)1579print_module_search_results_usage1580end15811582def show_missing(mod) # :nodoc:1583mod_opt = Serializer::ReadableText.dump_options(mod, ' ', true)1584print("\nModule options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)15851586# If it's an exploit and a payload is defined, create it and1587# display the payload's options1588if (mod.exploit? and mod.datastore['PAYLOAD'])1589p = framework.payloads.create(mod.datastore['PAYLOAD'])15901591if (!p)1592print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")1593return1594end15951596p.share_datastore(mod.datastore)15971598if (p)1599p_opt = Serializer::ReadableText.dump_options(p, ' ', true)1600print("\nPayload options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)1601end1602end1603end16041605def show_global_options1606columns = [ 'Option', 'Current Setting', 'Description' ]1607tbl = Table.new(1608Table::Style::Default,1609'Header' => 'Global Options:',1610'Prefix' => "\n",1611'Postfix' => "\n",1612'Columns' => columns1613)1614[1615[ 'ConsoleLogging', framework.datastore['ConsoleLogging'] || "false", 'Log all console input and output' ],1616[ 'LogLevel', framework.datastore['LogLevel'] || "0", 'Verbosity of logs (default 0, max 3)' ],1617[ 'MinimumRank', framework.datastore['MinimumRank'] || "0", 'The minimum rank of exploits that will run without explicit confirmation' ],1618[ 'SessionLogging', framework.datastore['SessionLogging'] || "false", 'Log all input and output for sessions' ],1619[ 'SessionTlvLogging', framework.datastore['SessionTlvLogging'] || "false", 'Log all incoming and outgoing TLV packets' ],1620[ 'TimestampOutput', framework.datastore['TimestampOutput'] || "false", 'Prefix all console output with a timestamp' ],1621[ 'Prompt', framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt.to_s.gsub(/%.../,"") , "The prompt string" ],1622[ 'PromptChar', framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar.to_s.gsub(/%.../,""), "The prompt character" ],1623[ 'PromptTimeFormat', framework.datastore['PromptTimeFormat'] || Time::DATE_FORMATS[:db].to_s, 'Format for timestamp escapes in prompts' ],1624[ 'MeterpreterPrompt', framework.datastore['MeterpreterPrompt'] || '%undmeterpreter%clr', 'The meterpreter prompt string' ],1625].each { |r| tbl << r }16261627print(tbl.to_s)1628end16291630def show_targets(mod) # :nodoc:1631case mod1632when Msf::Exploit1633mod_targs = Serializer::ReadableText.dump_exploit_targets(mod, '', "\nExploit targets:")1634print("#{mod_targs}\n") if (mod_targs and mod_targs.length > 0)1635when Msf::Evasion1636mod_targs = Serializer::ReadableText.dump_evasion_targets(mod, '', "\nEvasion targets:")1637print("#{mod_targs}\n") if (mod_targs and mod_targs.length > 0)1638end1639end16401641def show_actions(mod) # :nodoc:1642mod_actions = Serializer::ReadableText.dump_module_actions(mod, ' ')1643print("\n#{mod.type.capitalize} actions:\n\n#{mod_actions}\n") if (mod_actions and mod_actions.length > 0)1644end16451646def show_advanced_options(mod) # :nodoc:1647mod_opt = Serializer::ReadableText.dump_advanced_options(mod, ' ')1648print("\nModule advanced options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)16491650# If it's an exploit and a payload is defined, create it and1651# display the payload's options1652if (mod.exploit? and mod.datastore['PAYLOAD'])1653p = framework.payloads.create(mod.datastore['PAYLOAD'])16541655if (!p)1656print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")1657return1658end16591660p.share_datastore(mod.datastore)16611662if (p)1663p_opt = Serializer::ReadableText.dump_advanced_options(p, ' ')1664print("\nPayload advanced options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)1665end1666end1667print("\nView the full module info with the #{Msf::Ui::Tip.highlight('info')}, or #{Msf::Ui::Tip.highlight('info -d')} command.\n\n")1668end16691670def show_evasion_options(mod) # :nodoc:1671mod_opt = Serializer::ReadableText.dump_evasion_options(mod, ' ')1672print("\nModule evasion options:\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)16731674# If it's an exploit and a payload is defined, create it and1675# display the payload's options1676if (mod.evasion? and mod.datastore['PAYLOAD'])1677p = framework.payloads.create(mod.datastore['PAYLOAD'])16781679if (!p)1680print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")1681return1682end16831684p.share_datastore(mod.datastore)16851686if (p)1687p_opt = Serializer::ReadableText.dump_evasion_options(p, ' ')1688print("\nPayload evasion options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)1689end1690end1691end16921693def show_plugins # :nodoc:1694tbl = Table.new(1695Table::Style::Default,1696'Header' => 'Loaded Plugins',1697'Prefix' => "\n",1698'Postfix' => "\n",1699'Columns' => [ 'Name', 'Description' ]1700)17011702framework.plugins.each { |plugin|1703tbl << [ plugin.name, plugin.desc ]1704}17051706# create an instance of core to call the list_plugins1707core = Msf::Ui::Console::CommandDispatcher::Core.new(driver)1708core.list_plugins1709print(tbl.to_s)1710end17111712# @param [table_name] used to name table1713# @param [module_filter] this will either be a modules fullname, or it will be an Array(show payloads/encoders)1714# or a Hash(show favorites) containing fullname1715# @param [compatible_mod] handles logic for if there is an active module when the1716# `show` command is run1717#1718# Handles the filtering of modules that will be generated into a table1719def show_module_metadata(table_name, module_filter)1720count = -11721tbl = generate_module_table(table_name)17221723if module_filter.is_a?(Array) || module_filter.is_a?(Hash)1724module_filter.sort.each do |_mod_fullname, mod_obj|1725mod = nil17261727begin1728mod = mod_obj.new1729rescue ::Exception1730end1731next unless mod17321733count += 11734tbl << add_record(mod, count, true)1735end1736else1737results = Msf::Modules::Metadata::Cache.instance.find(1738'type' => [[module_filter], []]1739)1740# Loop over each module and gather data1741results.each do |mod, _value|1742count += 11743tbl << add_record(mod, count, false)1744end1745end1746print(tbl.to_s)1747end17481749# @param [mod] current module being passed in1750# @param [count] passes the count for each record1751# @param [compatible_mod] handles logic for if there is an active module when the1752# `show` command is run1753#1754# Adds a record for a table, also handle logic for whether the module is currently1755# handling compatible payloads/encoders1756def add_record(mod, count, compatible_mod)1757if compatible_mod1758check = mod.has_check? ? 'Yes' : 'No'1759else1760check = mod.check ? 'Yes' : 'No'1761end1762[1763count,1764mod.fullname,1765mod.disclosure_date.nil? ? '' : mod.disclosure_date.strftime('%Y-%m-%d'),1766mod.rank,1767check,1768mod.name1769]1770end17711772def generate_module_table(type, search_terms = [], row_filter = nil) # :nodoc:1773table_hierarchy_formatters = framework.features.enabled?(Msf::FeatureManager::HIERARCHICAL_SEARCH_TABLE) ? [Msf::Ui::Console::TablePrint::BlankFormatter.new] : []17741775Table.new(1776Table::Style::Default,1777'Header' => type,1778'Prefix' => "\n",1779'Postfix' => "\n",1780'SearchTerm' => row_filter,1781'SortIndex' => -1,1782# For now, don't perform any word wrapping on the search table as it breaks the workflow of1783# copying module names in conjunction with the `use <paste-buffer>` command1784'WordWrap' => false,1785'Columns' => [1786'#',1787'Name',1788'Disclosure Date',1789'Rank',1790'Check',1791'Description'1792],1793'ColProps' => {1794'Rank' => {1795'Formatters' => [1796*table_hierarchy_formatters,1797Msf::Ui::Console::TablePrint::RankFormatter.new1798],1799'Stylers' => [1800Msf::Ui::Console::TablePrint::RankStyler.new1801]1802},1803'Name' => {1804'Strip' => false,1805'Stylers' => [Msf::Ui::Console::TablePrint::HighlightSubstringStyler.new(search_terms)]1806},1807'Check' => {1808'Formatters' => [1809*table_hierarchy_formatters,1810]1811},1812'Disclosure Date' => {1813'Formatters' => [1814*table_hierarchy_formatters,1815]1816},1817'Description' => {1818'Stylers' => [1819Msf::Ui::Console::TablePrint::HighlightSubstringStyler.new(search_terms)1820]1821}1822}1823)1824end1825end1826end1827end1828end1829end183018311832