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/module_argument_parsing.rb
Views: 11783
# -*- coding: binary -*-12require 'addressable'3require 'msf/ui/console/command_dispatcher'45module Msf6module Ui7module Console89###10#11# A centralized mixin to ensure that options are consistently parsed across all module types12# when running a module's cmd_run/cmd_check/cmd_exploit arguments13#14###15module ModuleArgumentParsing1617# Options which are standard and predictable across all modules18@@module_opts = Rex::Parser::Arguments.new(19['-h', '--help'] => [ false, 'Help banner.' ],20['-j', '--job'] => [ false, 'Run in the context of a job.' ],21['-J', '--foreground'] => [ false, 'Force running in the foreground, even if passive.' ],22['-o', '--options'] => [ true, 'A comma separated list of options in VAR=VAL format.', '<options>' ],23['-q', '--quiet'] => [ false, 'Run the module in quiet mode with no output' ],24['-r', '--reload-libs'] => [ false, 'Reload all libraries before running.' ]25)2627@@module_opts_with_action_support = @@module_opts.merge(28['-a', '--action'] => [ true, 'The action to use. If none is specified, ACTION is used.', '<action>']29)3031@@exploit_opts = @@module_opts.merge(32['-e', '--encoder'] => [ true, 'The payload encoder to use. If none is specified, ENCODER is used.', '<encoder>' ],33['-f', '--force-run'] => [ false, 'Force the exploit to run regardless of the value of MinimumRank.' ],34['-n', '--nop-generator'] => [ true, 'The NOP generator to use. If none is specified, NOP is used.', '<generator>' ],35['-p', '--payload'] => [ true, 'The payload to use. If none is specified, PAYLOAD is used.', '<payload>' ],36['-t', '--target'] => [ true, 'The target index to use. If none is specified, TARGET is used.', '<target>' ],37['-z', '--no-interact'] => [ false, 'Do not interact with the session after successful exploitation.' ]38)3940def parse_check_opts(args)41help_cmd = proc do |_result|42cmd_check_help43end44parse_opts(@@module_opts_with_action_support, args, help_cmd: help_cmd)&.slice(:datastore_options, :reload_libs)45end4647def parse_run_opts(args, action: nil)48help_cmd = proc do |result|49if result[:action].nil?50cmd_run_help51else52cmd_action_help(action)53end54end5556parse_opts(@@module_opts_with_action_support, args, help_cmd: help_cmd, action: action)57end5859def parse_exploit_opts(args)60help_cmd = proc do |_result|61cmd_exploit_help62end63parse_opts(@@exploit_opts, args, help_cmd: help_cmd)&.except(:action)64end6566def print_module_run_or_check_usage(command:, description: nil, options: @@module_opts)67description ||= command == :check ? 'Check if the target is vulnerable' : "Run the current #{name.downcase} module"6869is_http_mod = mod.is_a?(Msf::Exploit::Remote::HttpClient)70is_smb_mod = mod.is_a?(Msf::Exploit::Remote::SMB::Client) || mod.options.include?('SMBUser')71is_mysql_mod = mod.is_a?(Msf::Exploit::Remote::MYSQL)7273print_line("Usage: #{command} [options] [RHOSTS]")74print_line('')75print_line(description)76print_line(options.usage)77print_line('Examples:')78print_line('')79print_line(" #{command} 192.168.1.123")80print_line(" #{command} 192.168.1.1-192.168.1.254")81print_line(" #{command} file:///tmp/rhost_list.txt")82print_line(" #{command} http://192.168.1.123/foo") if is_http_mod83print_line(" #{command} http://user:[email protected]/foo") if is_http_mod84print_line(" #{command} HttpTrace=true http://192.168.1.123/foo") if is_http_mod85print_line(" #{command} mysql://user:[email protected]") if is_mysql_mod86print_line(" #{command} SQL='select version()' mysql://user:[email protected]") if is_mysql_mod && mod.options.include?('SQL')87print_line(" #{command} smb://192.168.1.123") if is_smb_mod88print_line(" #{command} smb://user:[email protected]") if is_smb_mod89print_line(" #{command} LPATH=/tmp/foo.txt smb://user:[email protected]/share_name/foo.txt") if is_smb_mod && mod.options.include?('RPATH')90print_line('')91print_line('Learn more at https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html')92print_line('')93end9495protected9697def parse_opts(opts, args, help_cmd:, action: nil)98result = {99jobify: false,100quiet: false,101datastore_options: {},102action: action || mod.datastore['ACTION']103}104datastore_options = result[:datastore_options]105opts.parse(args) do |opt, _idx, val|106case opt107when '-e'108result[:encoder] = val109when '-f'110result[:force] = true111when '-j'112result[:jobify] = true113when '-J'114result[:jobify] = false115when '-n'116result[:nop] = val117when '-o'118if val.nil?119print_error('Missing OptionStr value')120help_cmd.call result121return122end123val << '=' unless val.include?('=')124val.split(',').each do |opt|125name, value = opt.split('=', 2)126append_datastore_option(datastore_options, name, value)127end128when '-p'129result[:payload] = val130when '-r'131result[:reload_libs] = true132when '-t'133result[:target] = val.to_i134when '-z'135result[:background] = true136when '-a'137result[:action] = val138when '-q'139result[:quiet] = true140when '-h'141help_cmd.call result142return143else144if val && val[0] == '-'145help_cmd.call result146return147end148149if resembles_datastore_assignment?(val)150name, val = val.split('=', 2)151append_datastore_option(datastore_options, name, val)152elsif resembles_rhost_value?(val)153append_datastore_option(datastore_options, 'RHOSTS', val)154else155print_error("Invalid argument #{val}")156help_cmd.call result157return158end159end160end161162result163end164165def resembles_datastore_assignment?(val)166return false unless val167168valid_option_regex = /^(\w|::)+=.*/169valid_option_regex.match?(val)170end171172def resembles_rhost_value?(val)173return false unless val174175::Addressable::URI.parse(val)176true177rescue ::Addressable::URI::InvalidURIError => _e178false179end180181def append_datastore_option(datastore_options, name, value)182if name.casecmp?('RHOST') || name.casecmp?('RHOSTS')183new_value = quote_whitespaced_value(value)184if !datastore_options['RHOSTS']185datastore_options['RHOSTS'] = new_value186else187datastore_options['RHOSTS'] = "#{datastore_options['RHOSTS']} #{new_value}"188end189else190datastore_options[name.upcase] = value191end192datastore_options193end194195# Wraps values which contain spaces in quotes to ensure it's handled correctly later196def quote_whitespaced_value(val)197val.include?(' ') ? "\"#{val}\"" : val198end199end200end201end202end203204205