Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/msf/ui/console/command_dispatcher/modules.rb
Views: 11784
# -*- 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_payload905end906907if framework.features.enabled?(Msf::FeatureManager::DISPLAY_MODULE_ACTION) && mod.respond_to?(:actions) && mod.actions.size > 1908print_status "Using action %grn#{mod.action.name}%clr - view all #{mod.actions.size} actions with the %grnshow actions%clr command"909end910911mod.init_ui(driver.input, driver.output)912end913914#915# Command to take to the previously active module916#917def cmd_previous(*args)918if @previous_module919self.cmd_use(@previous_module.fullname)920else921print_error("There isn't a previous module at the moment")922end923end924925#926# Help for the 'previous' command927#928def cmd_previous_help929print_line "Usage: previous"930print_line931print_line "Set the previously loaded module as the current module"932print_line933print_line "Previous module: #{@previous_module ? @previous_module.fullname : 'none'}"934print_line935end936937#938# Command to enqueque a module on the module stack939#940def cmd_pushm(*args)941# could check if each argument is a valid module, but for now let them hang themselves942if args.count > 0943args.each do |arg|944@module_name_stack.push(arg)945# Note new modules are appended to the array and are only module (full)names946end947else #then just push the active module948if active_module949#print_status "Pushing the active module"950@module_name_stack.push(active_module.fullname)951else952print_error("There isn't an active module and you didn't specify a module to push")953return self.cmd_pushm_help954end955end956end957958#959# Tab completion for the pushm command960#961# @param str [String] the string currently being typed before tab was hit962# @param words [Array<String>] the previously completed words on the command line. words is always963# at least 1 when tab completion has reached this stage since the command itself has been completed964965def cmd_pushm_tabs(str, words)966tab_complete_module(str, words)967end968969#970# Help for the 'pushm' command971#972def cmd_pushm_help973print_line "Usage: pushm [module1 [,module2, module3...]]"974print_line975print_line "push current active module or specified modules onto the module stack"976print_line977end978979#980# Command to dequeque a module from the module stack981#982def cmd_popm(*args)983if (args.count > 1 or not args[0].respond_to?("to_i"))984return self.cmd_popm_help985elsif args.count == 1986# then pop 'n' items off the stack, but don't change the active module987if args[0].to_i >= @module_name_stack.count988# in case they pass in a number >= the length of @module_name_stack989@module_name_stack = []990print_status("The module stack is empty")991else992@module_name_stack.pop(args[0].to_i)993end994else #then just pop the array and make that the active module995pop = @module_name_stack.pop996if pop997return self.cmd_use(pop)998else999print_error("There isn't anything to pop, the module stack is empty")1000end1001end1002end10031004#1005# Help for the 'popm' command1006#1007def cmd_popm_help1008print_line "Usage: popm [n]"1009print_line1010print_line "pop the latest module off of the module stack and make it the active module"1011print_line "or pop n modules off the stack, but don't change the active module"1012print_line1013end10141015def cmd_listm_help1016print_line 'Usage: listm'1017print_line1018print_line 'List the module stack'1019print_line1020end10211022def cmd_listm(*_args)1023if @module_name_stack.empty?1024print_error('The module stack is empty')1025return1026end10271028print_status("Module stack:\n")10291030@module_name_stack.to_enum.with_index.reverse_each do |name, idx|1031print_line("[#{idx}]\t#{name}")1032end1033end10341035def cmd_clearm_help1036print_line 'Usage: clearm'1037print_line1038print_line 'Clear the module stack'1039print_line1040end10411042def cmd_clearm(*_args)1043print_status('Clearing the module stack')1044@module_name_stack.clear1045end10461047#1048# Tab completion for the use command1049#1050# @param str [String] the string currently being typed before tab was hit1051# @param words [Array<String>] the previously completed words on the command line. words is always1052# at least 1 when tab completion has reached this stage since the command itself has been completed10531054def cmd_use_tabs(str, words)1055return [] if words.length > 110561057tab_complete_module(str, words)1058end10591060def cmd_reload_all_help1061print_line "Usage: reload_all"1062print_line1063print_line "Reload all modules from all configured module paths. This may take awhile."1064print_line "See also: loadpath"1065print_line1066end10671068#1069# Reload all module paths that we are aware of1070#1071def cmd_reload_all(*args)1072if args.length > 01073cmd_reload_all_help1074return1075end10761077print_status("Reloading modules from all module paths...")1078framework.modules.reload_modules10791080log_msg = "Please see #{File.join(Msf::Config.log_directory, 'framework.log')} for details."10811082# Check for modules that failed to load1083if framework.modules.module_load_error_by_path.length > 01084wlog("WARNING! The following modules could not be loaded!")10851086framework.modules.module_load_error_by_path.each do |path, _error|1087wlog("\t#{path}")1088end10891090wlog(log_msg)1091end10921093if framework.modules.module_load_warnings.length > 01094wlog("The following modules were loaded with warnings:")10951096framework.modules.module_load_warnings.each do |path, _error|1097wlog("\t#{path}")1098end10991100wlog(log_msg)1101end11021103self.driver.run_single('reload')1104self.driver.run_single("banner")1105end11061107def cmd_back_help1108print_line "Usage: back"1109print_line1110print_line "Return to the global dispatcher context"1111print_line1112end11131114#1115# Pop the current dispatcher stack context, assuming it isn't pointed at1116# the core or database backend stack context.1117#1118def cmd_back(*args)1119if (driver.dispatcher_stack.size > 1 and1120driver.current_dispatcher.name != 'Core' and1121driver.current_dispatcher.name != 'Database Backend')1122# Reset the active module if we have one1123if (active_module)11241125# Do NOT reset the UI anymore1126# active_module.reset_ui11271128# Save the module's datastore so that we can load it later1129# if the module is used again1130@dscache[active_module.fullname] = active_module.datastore.dup11311132self.active_module = nil1133end11341135# Destack the current dispatcher1136driver.destack_dispatcher1137end1138end11391140def cmd_favorite_help1141print_line 'Usage: favorite [mod1 mod2 ...]'1142print_line1143print_line "Add one or multiple modules to the list of favorite modules stored in #{Msf::Config.fav_modules_file}"1144print_line 'If no module name is specified, the command will add the active module if there is one'1145print @@favorite_opts.usage1146end11471148#1149# Helper method for cmd_favorite that writes modules to the fav_modules_file1150#1151def favorite_add(modules, favs_file)1152fav_limit = 501153# obtain useful info about the fav_modules file1154exists, writable, readable, contents = favorite_check_fav_modules(favs_file)11551156# if the fav_modules file exists, check the file permissions1157if exists1158case1159when !writable1160print_error("Unable to save module(s) to the favorite modules file because it is not writable")1161return1162when !readable1163print_error("Unable to save module(s) to the favorite modules file because it is not readable")1164return1165end1166end11671168fav_count = 01169if contents1170fav_count = contents.split.size1171end11721173modules = modules.uniq # prevent modules from being added more than once1174modules.each do |name|1175mod = framework.modules.create(name)1176if (mod == nil)1177print_error("Invalid module: #{name}")1178next1179end11801181if contents && contents.include?(mod.fullname)1182print_warning("Module #{mod.fullname} has already been favorited and will not be added to the favorite modules file")1183next1184end11851186if fav_count >= fav_limit1187print_error("Favorite module limit (#{fav_limit}) exceeded. No more modules will be added.")1188return1189end11901191File.open(favs_file, 'a+') { |file| file.puts(mod.fullname) }1192print_good("Added #{mod.fullname} to the favorite modules file")1193fav_count += 11194end1195return1196end11971198#1199# Helper method for cmd_favorite that deletes modules from the fav_modules_file1200#1201def favorite_del(modules, delete_all, favs_file)1202# obtain useful info about the fav_modules file1203exists, writable, readable, contents = favorite_check_fav_modules(favs_file)12041205if delete_all1206custom_message = 'clear the contents of'1207else1208custom_message = 'delete module(s) from'1209end12101211case # error handling based on the existence / permissions of the fav_modules file1212when !exists1213print_warning("Unable to #{custom_message} the favorite modules file because it does not exist")1214return1215when !writable1216print_error("Unable to #{custom_message} the favorite modules file because it is not writable")1217return1218when !readable1219unless delete_all1220print_error("Unable to #{custom_message} the favorite modules file because it is not readable")1221return1222end1223when contents.empty?1224print_warning("Unable to #{custom_message} the favorite modules file because it is already empty")1225return1226end12271228if delete_all1229File.write(favs_file, '')1230print_good("Favorite modules file cleared")1231return1232end12331234modules = modules.uniq # prevent modules from being deleted more than once1235contents = contents.split1236modules.each do |name|1237mod = framework.modules.create(name)1238if (mod == nil)1239print_error("Invalid module: #{name}")1240next1241end12421243unless contents.include?(mod.fullname)1244print_warning("Module #{mod.fullname} cannot be deleted because it is not in the favorite modules file")1245next1246end12471248contents.delete(mod.fullname)1249print_status("Removing #{mod.fullname} from the favorite modules file")1250end12511252# clear the contents of the fav_modules file if removing the module(s) makes it empty1253if contents.length == 01254File.write(favs_file, '')1255return1256end12571258File.open(favs_file, 'w') { |file| file.puts(contents.join("\n")) }1259end12601261#1262# Helper method for cmd_favorite that checks if the fav_modules file exists and is readable / writable1263#1264def favorite_check_fav_modules(favs_file)1265exists = false1266writable = false1267readable = false1268contents = ''12691270if File.exist?(favs_file)1271exists = true1272end12731274if File.writable?(favs_file)1275writable = true1276end12771278if File.readable?(favs_file)1279readable = true1280contents = File.read(favs_file)1281end12821283return exists, writable, readable, contents1284end12851286#1287# Add modules to or delete modules from the fav_modules file1288#1289def cmd_favorite(*args)1290valid_custom_args = ['-c', '-d', '-l']1291favs_file = Msf::Config.fav_modules_file12921293# always display the help banner if -h is provided or if multiple options are provided1294if args.include?('-h') || args.select{ |arg| arg if valid_custom_args.include?(arg) }.length > 11295cmd_favorite_help1296return1297end12981299# if no arguments were provided, check if there is an active module to add1300if args.empty?1301unless active_module1302print_error('No module has been provided to favorite.')1303cmd_favorite_help1304return1305end13061307args = [active_module.fullname]1308favorite_add(args, favs_file)1309return1310end13111312case args[0]1313when '-c'1314args.delete('-c')1315unless args.empty?1316print_error('Option `-c` does not support arguments.')1317cmd_favorite_help1318return1319end13201321favorite_del(args, true, favs_file)1322when '-d'1323args.delete('-d')1324if args.empty?1325unless active_module1326print_error('No module has been provided to delete.')1327cmd_favorite_help1328return1329end13301331args = [active_module.fullname]1332end13331334favorite_del(args, false, favs_file)1335when '-l'1336args.delete('-l')1337unless args.empty?1338print_error('Option `-l` does not support arguments.')1339cmd_favorite_help1340return1341end1342cmd_show('favorites')1343else # no valid options, but there are arguments1344if args[0].start_with?('-')1345print_error('Invalid option provided')1346cmd_favorite_help1347return1348end13491350favorite_add(args, favs_file)1351end1352end13531354def cmd_favorites_help1355print_line 'Usage: favorites'1356print_line1357print_line 'Print the list of favorite modules (alias for `show favorites`)'1358print_line 'You can use the %grnfavorite%clr command to add the current module to your favorites list'1359print @@favorites_opts.usage1360end13611362#1363# Print the list of favorite modules from the fav_modules file (alias for `show favorites`)1364#1365def cmd_favorites(*args)1366if args.empty?1367cmd_show('favorites')1368return1369end13701371# always display the help banner if the command is called with arguments1372unless args.include?('-h')1373print_error('Invalid option(s) provided')1374end13751376cmd_favorites_help1377end13781379#1380# Tab complete module names1381#1382def tab_complete_module(str, words)1383res = []1384module_metadata = Msf::Modules::Metadata::Cache.instance.get_metadata1385module_metadata.each do |m|1386res << "#{m.type}/#{m.ref_name}"1387end1388framework.modules.module_types.each do |mtyp|1389mset = framework.modules.module_names(mtyp)1390mset.each do |mref|1391res << mtyp + '/' + mref1392end1393end13941395return dangerzone_modules_to_codenames(res.sort) if dangerzone_active?1396return res.uniq.sort1397end13981399def print_april_fools_module_use1400return unless ENV['APRILFOOLSMODULEUSE'] || Time.now.strftime("%m%d") == "0401"14011402banner = Msf::Ui::Banner.readfile('help-using-a-module.txt')1403print_line("%grn#{banner}%clr")1404end14051406#1407# Convert squirrel names back to regular module names1408#1409def dangerzone_codename_to_module(args)1410return args unless dangerzone_active? && args.length > 0 && args[0].length > 01411return args unless args[0] =~ /^[A-Z]/1412args[0] = dangerzone_codename_to_module_name(args[0])1413args1414end14151416#1417# Determine if dangerzone mode is active via date or environment variable1418#1419def dangerzone_active?1420active = Time.now.strftime("%m%d") == "0401" || Rex::Compat.getenv('DANGERZONE').to_i > 01421if active && @dangerzone_map.nil?1422dangerzone_build_map1423end1424active1425end14261427#1428# Convert module names to squirrel names1429#1430def dangerzone_modules_to_codenames(names)1431(names + @dangerzone_map.keys.grep(/^[A-Z]+/)).sort1432end14331434def dangerzone_codename_to_module_name(cname)1435@dangerzone_map[cname] || cname1436end14371438def dangerzone_module_name_to_codename(mname)1439@dangerzone_map[mname] || mname1440end14411442def dangerzone_build_map1443return unless @dangerzone_map.nil?14441445@dangerzone_map = {}14461447res = []1448%W{exploit auxiliary}.each do |mtyp|1449mset = framework.modules.module_names(mtyp)1450mset.each do |mref|1451res << mtyp + '/' + mref1452end1453end14541455words_a = ::File.readlines(::File.join(1456::Msf::Config.data_directory, "wordlists", "dangerzone_a.txt"1457)).map{|line| line.strip.upcase}14581459words_b = ::File.readlines(::File.join(1460::Msf::Config.data_directory, "wordlists", "dangerzone_b.txt"1461)).map{|line| line.strip.upcase}14621463aidx = -11464bidx = -114651466res.sort.each do |mname|1467word_a = words_a[ (aidx += 1) % words_a.length ]1468word_b = words_b[ (bidx += 1) % words_b.length ]1469cname = word_a + word_b14701471while @dangerzone_map[cname]1472aidx += 11473word_a = words_a[ (aidx += 1) % words_a.length ]1474cname = word_a + word_b1475end14761477@dangerzone_map[mname] = cname1478@dangerzone_map[cname] = mname1479end1480end14811482#1483# Module list enumeration1484#14851486def show_encoders # :nodoc:1487# If an active module has been selected and it's an exploit, get the1488# list of compatible encoders and display them1489if (active_module and active_module.exploit? == true)1490show_module_metadata('Compatible Encoders', active_module.compatible_encoders)1491else1492show_module_metadata('Encoders', 'encoder')1493end1494end14951496def show_nops # :nodoc:1497show_module_metadata('NOP Generators', 'nop')1498end14991500def show_exploits # :nodoc:1501show_module_metadata('Exploits', 'exploit')1502end15031504def show_payloads # :nodoc:1505# If an active module has been selected and it's an exploit, get the1506# list of compatible payloads and display them1507if active_module && (active_module.exploit? || active_module.evasion?)1508@@payload_show_results = active_module.compatible_payloads15091510show_module_metadata('Compatible Payloads', @@payload_show_results)1511else1512# show_module_set(‘Payloads’, framework.payloads, regex, minrank, opts)1513show_module_metadata('Payloads', 'payload')1514end1515end15161517def show_auxiliary # :nodoc:1518show_module_metadata('Auxiliary','auxiliary')1519end15201521def show_post # :nodoc:1522show_module_metadata('Post','post')1523end15241525def show_evasion # :nodoc:1526show_module_metadata('Evasion','evasion')1527end15281529def show_favorites # :nodoc:1530favs_file = Msf::Config.fav_modules_file15311532unless File.exist?(favs_file)1533print_error("The favorite modules file does not exist")1534return1535end15361537if File.zero?(favs_file)1538print_warning("The favorite modules file is empty")1539return1540end15411542unless File.readable?(favs_file)1543print_error("Unable to read from #{favs_file}")1544return1545end15461547# create module set using the saved modules1548fav_modules = {}15491550# get the full module names from the favorites file and use then to search the MetaData Cache for matching modules1551saved_favs = File.readlines(favs_file).map(&:strip)1552saved_favs.each do |mod|1553# populate hash with module fullname and module object1554fav_modules[mod] = framework.modules[mod]1555end15561557fav_modules.each do |fullname, mod_obj|1558if mod_obj.nil?1559print_warning("#{favs_file} contains a module that can not be found - #{fullname}.")1560end1561end15621563# find cache module instance and add it to @module_search_results1564@module_search_results = Msf::Modules::Metadata::Cache.instance.find('fullname' => [saved_favs, []])15651566# This scenario is for when a module fullname is a substring of other module fullnames1567# Example, searching for the payload/windows/meterpreter/reverse_tcp module can result in matches for:1568# - windows/meterpreter/reverse_tcp_allports1569# - windows/meterpreter/reverse_tcp_dns1570# So if @module_search_results is greater than the amount of fav_modules, we need to filter the results to be more accurate1571if fav_modules.length < @module_search_results.length1572filtered_results = []1573fav_modules.each do |fullname, _mod_obj|1574filtered_results << @module_search_results.select do |search_result|1575search_result.fullname == fullname1576end1577end1578@module_search_results = filtered_results.flatten.sort_by(&:fullname)1579end1580@module_search_results_with_usage_metadata = @module_search_results.map { |mod| { mod: mod, datastore: {} } }15811582show_module_metadata('Favorites', fav_modules)1583print_module_search_results_usage1584end15851586def show_missing(mod) # :nodoc:1587mod_opt = Serializer::ReadableText.dump_options(mod, ' ', true)1588print("\nModule options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)15891590# If it's an exploit and a payload is defined, create it and1591# display the payload's options1592if (mod.exploit? and mod.datastore['PAYLOAD'])1593p = framework.payloads.create(mod.datastore['PAYLOAD'])15941595if (!p)1596print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")1597return1598end15991600p.share_datastore(mod.datastore)16011602if (p)1603p_opt = Serializer::ReadableText.dump_options(p, ' ', true)1604print("\nPayload options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)1605end1606end1607end16081609def show_global_options1610columns = [ 'Option', 'Current Setting', 'Description' ]1611tbl = Table.new(1612Table::Style::Default,1613'Header' => 'Global Options:',1614'Prefix' => "\n",1615'Postfix' => "\n",1616'Columns' => columns1617)1618[1619[ 'ConsoleLogging', framework.datastore['ConsoleLogging'] || "false", 'Log all console input and output' ],1620[ 'LogLevel', framework.datastore['LogLevel'] || "0", 'Verbosity of logs (default 0, max 3)' ],1621[ 'MinimumRank', framework.datastore['MinimumRank'] || "0", 'The minimum rank of exploits that will run without explicit confirmation' ],1622[ 'SessionLogging', framework.datastore['SessionLogging'] || "false", 'Log all input and output for sessions' ],1623[ 'SessionTlvLogging', framework.datastore['SessionTlvLogging'] || "false", 'Log all incoming and outgoing TLV packets' ],1624[ 'TimestampOutput', framework.datastore['TimestampOutput'] || "false", 'Prefix all console output with a timestamp' ],1625[ 'Prompt', framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt.to_s.gsub(/%.../,"") , "The prompt string" ],1626[ 'PromptChar', framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar.to_s.gsub(/%.../,""), "The prompt character" ],1627[ 'PromptTimeFormat', framework.datastore['PromptTimeFormat'] || Time::DATE_FORMATS[:db].to_s, 'Format for timestamp escapes in prompts' ],1628[ 'MeterpreterPrompt', framework.datastore['MeterpreterPrompt'] || '%undmeterpreter%clr', 'The meterpreter prompt string' ],1629].each { |r| tbl << r }16301631print(tbl.to_s)1632end16331634def show_targets(mod) # :nodoc:1635case mod1636when Msf::Exploit1637mod_targs = Serializer::ReadableText.dump_exploit_targets(mod, '', "\nExploit targets:")1638print("#{mod_targs}\n") if (mod_targs and mod_targs.length > 0)1639when Msf::Evasion1640mod_targs = Serializer::ReadableText.dump_evasion_targets(mod, '', "\nEvasion targets:")1641print("#{mod_targs}\n") if (mod_targs and mod_targs.length > 0)1642end1643end16441645def show_actions(mod) # :nodoc:1646mod_actions = Serializer::ReadableText.dump_module_actions(mod, ' ')1647print("\n#{mod.type.capitalize} actions:\n\n#{mod_actions}\n") if (mod_actions and mod_actions.length > 0)1648end16491650def show_advanced_options(mod) # :nodoc:1651mod_opt = Serializer::ReadableText.dump_advanced_options(mod, ' ')1652print("\nModule advanced options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)16531654# If it's an exploit and a payload is defined, create it and1655# display the payload's options1656if (mod.exploit? and mod.datastore['PAYLOAD'])1657p = framework.payloads.create(mod.datastore['PAYLOAD'])16581659if (!p)1660print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")1661return1662end16631664p.share_datastore(mod.datastore)16651666if (p)1667p_opt = Serializer::ReadableText.dump_advanced_options(p, ' ')1668print("\nPayload advanced options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)1669end1670end1671print("\nView the full module info with the #{Msf::Ui::Tip.highlight('info')}, or #{Msf::Ui::Tip.highlight('info -d')} command.\n\n")1672end16731674def show_evasion_options(mod) # :nodoc:1675mod_opt = Serializer::ReadableText.dump_evasion_options(mod, ' ')1676print("\nModule evasion options:\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)16771678# If it's an exploit and a payload is defined, create it and1679# display the payload's options1680if (mod.evasion? and mod.datastore['PAYLOAD'])1681p = framework.payloads.create(mod.datastore['PAYLOAD'])16821683if (!p)1684print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")1685return1686end16871688p.share_datastore(mod.datastore)16891690if (p)1691p_opt = Serializer::ReadableText.dump_evasion_options(p, ' ')1692print("\nPayload evasion options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)1693end1694end1695end16961697def show_plugins # :nodoc:1698tbl = Table.new(1699Table::Style::Default,1700'Header' => 'Loaded Plugins',1701'Prefix' => "\n",1702'Postfix' => "\n",1703'Columns' => [ 'Name', 'Description' ]1704)17051706framework.plugins.each { |plugin|1707tbl << [ plugin.name, plugin.desc ]1708}17091710# create an instance of core to call the list_plugins1711core = Msf::Ui::Console::CommandDispatcher::Core.new(driver)1712core.list_plugins1713print(tbl.to_s)1714end17151716# @param [table_name] used to name table1717# @param [module_filter] this will either be a modules fullname, or it will be an Array(show payloads/encoders)1718# or a Hash(show favorites) containing fullname1719# @param [compatible_mod] handles logic for if there is an active module when the1720# `show` command is run1721#1722# Handles the filtering of modules that will be generated into a table1723def show_module_metadata(table_name, module_filter)1724count = -11725tbl = generate_module_table(table_name)17261727if module_filter.is_a?(Array) || module_filter.is_a?(Hash)1728module_filter.sort.each do |_mod_fullname, mod_obj|1729mod = nil17301731begin1732mod = mod_obj.new1733rescue ::Exception1734end1735next unless mod17361737count += 11738tbl << add_record(mod, count, true)1739end1740else1741results = Msf::Modules::Metadata::Cache.instance.find(1742'type' => [[module_filter], []]1743)1744# Loop over each module and gather data1745results.each do |mod, _value|1746count += 11747tbl << add_record(mod, count, false)1748end1749end1750print(tbl.to_s)1751end17521753# @param [mod] current module being passed in1754# @param [count] passes the count for each record1755# @param [compatible_mod] handles logic for if there is an active module when the1756# `show` command is run1757#1758# Adds a record for a table, also handle logic for whether the module is currently1759# handling compatible payloads/encoders1760def add_record(mod, count, compatible_mod)1761if compatible_mod1762check = mod.has_check? ? 'Yes' : 'No'1763else1764check = mod.check ? 'Yes' : 'No'1765end1766[1767count,1768mod.fullname,1769mod.disclosure_date.nil? ? '' : mod.disclosure_date.strftime('%Y-%m-%d'),1770mod.rank,1771check,1772mod.name1773]1774end17751776def generate_module_table(type, search_terms = [], row_filter = nil) # :nodoc:1777table_hierarchy_formatters = framework.features.enabled?(Msf::FeatureManager::HIERARCHICAL_SEARCH_TABLE) ? [Msf::Ui::Console::TablePrint::BlankFormatter.new] : []17781779Table.new(1780Table::Style::Default,1781'Header' => type,1782'Prefix' => "\n",1783'Postfix' => "\n",1784'SearchTerm' => row_filter,1785'SortIndex' => -1,1786# For now, don't perform any word wrapping on the search table as it breaks the workflow of1787# copying module names in conjunction with the `use <paste-buffer>` command1788'WordWrap' => false,1789'Columns' => [1790'#',1791'Name',1792'Disclosure Date',1793'Rank',1794'Check',1795'Description'1796],1797'ColProps' => {1798'Rank' => {1799'Formatters' => [1800*table_hierarchy_formatters,1801Msf::Ui::Console::TablePrint::RankFormatter.new1802],1803'Stylers' => [1804Msf::Ui::Console::TablePrint::RankStyler.new1805]1806},1807'Name' => {1808'Strip' => false,1809'Stylers' => [Msf::Ui::Console::TablePrint::HighlightSubstringStyler.new(search_terms)]1810},1811'Check' => {1812'Formatters' => [1813*table_hierarchy_formatters,1814]1815},1816'Disclosure Date' => {1817'Formatters' => [1818*table_hierarchy_formatters,1819]1820},1821'Description' => {1822'Stylers' => [1823Msf::Ui::Console::TablePrint::HighlightSubstringStyler.new(search_terms)1824]1825}1826}1827)1828end1829end1830end1831end1832end1833end183418351836