Module: Msf::Ui::Console::ModuleArgumentParsing

Includes:
ModuleOptionValidation
Included in:
CommandDispatcher::Exploit, CommandDispatcher::Post, ModuleActionCommands, ModuleCommandDispatcher
Defined in:
lib/msf/ui/console/module_argument_parsing.rb

Overview

A centralized mixin to ensure that options are consistently parsed across all module types when running a module’s cmd_run/cmd_check/cmd_exploit arguments

Constant Summary collapse

@@module_opts =

Options which are standard and predictable across all modules

Rex::Parser::Arguments.new(
  ['-h', '--help']        => [ false, 'Help banner.'                                                       ],
  ['-j', '--job']         => [ false, 'Run in the context of a job.'                                       ],
  ['-J', '--foreground']  => [ false, 'Force running in the foreground, even if passive.'                  ],
  ['-o', '--options']     => [ true,  'A comma separated list of options in VAR=VAL format.', '<options>'  ],
  ['-q', '--quiet']       => [ false, 'Run the module in quiet mode with no output'                        ],
  ['-r', '--reload-libs'] => [ false, 'Reload all libraries before running.'                               ]
)
@@module_opts_with_action_support =
@@module_opts.merge(
  ['-a', '--action'] => [ true, 'The action to use. If none is specified, ACTION is used.', '<action>']
)
@@exploit_opts =
@@module_opts.merge(
  ['-e', '--encoder']       => [ true,  'The payload encoder to use.  If none is specified, ENCODER is used.', '<encoder>'   ],
  ['-f', '--force-run']     => [ false, 'Force the exploit to run regardless of the value of MinimumRank.'                   ],
  ['-n', '--nop-generator'] => [ true,  'The NOP generator to use.  If none is specified, NOP is used.', '<generator>'       ],
  ['-p', '--payload']       => [ true,  'The payload to use.  If none is specified, PAYLOAD is used.', '<payload>'           ],
  ['-t', '--target']        => [ true,  'The target index to use.  If none is specified, TARGET is used.', '<target>'        ],
  ['-z', '--no-interact']   => [ false, 'Do not interact with the session after successful exploitation.'                    ]
)

Instance Method Summary collapse

Methods included from ModuleOptionValidation

#datastore_option_names, #unknown_datastore_option_message, #valid_datastore_option_names

Instance Method Details

#append_datastore_option(datastore_options, name, value) ⇒ Object (protected)



190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 190

def append_datastore_option(datastore_options, name, value)
  if name.casecmp?('RHOST') || name.casecmp?('RHOSTS')
    new_value = quote_whitespaced_value(value)
    if !datastore_options['RHOSTS']
      datastore_options['RHOSTS'] = new_value
    else
      datastore_options['RHOSTS'] = "#{datastore_options['RHOSTS']} #{new_value}"
    end
  else
    datastore_options[name.upcase] = value
  end
  datastore_options
end

#parse_check_opts(args) ⇒ Object



43
44
45
46
47
48
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 43

def parse_check_opts(args)
  help_cmd = proc do |_result|
    cmd_check_help
  end
  parse_opts(@@module_opts_with_action_support, args, help_cmd: help_cmd)&.slice(:datastore_options, :reload_libs)
end

#parse_exploit_opts(args) ⇒ Object



62
63
64
65
66
67
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 62

def parse_exploit_opts(args)
  help_cmd = proc do |_result|
    cmd_exploit_help
  end
  parse_opts(@@exploit_opts, args, help_cmd: help_cmd)
end

#parse_opts(opts, args, help_cmd:, action: nil) ⇒ Object (protected)



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 100

def parse_opts(opts, args, help_cmd:, action: nil)
  result = {
    jobify: false,
    quiet: false,
    datastore_options: {},
    action: action || mod.datastore['ACTION']
  }
  datastore_options = result[:datastore_options]
  opts.parse(args) do |opt, _idx, val|
    case opt
    when '-e'
      result[:encoder] = val
    when '-f'
      result[:force] = true
    when '-j'
      result[:jobify] = true
    when '-J'
      result[:jobify] = false
    when '-n'
      result[:nop] = val
    when '-o'
      if val.nil?
        print_error('Missing OptionStr value')
        help_cmd.call result
        return
      end
      val << '=' unless val.include?('=')
      val.split(',').each do |opt|
        name, value = opt.split('=', 2)
        warn_unknown_datastore_option(name) if mod
        append_datastore_option(datastore_options, name, value)
      end
    when '-p'
      result[:payload] = val
    when '-r'
      result[:reload_libs] = true
    when '-t'
      result[:target] = val.to_i
    when '-z'
      result[:background] = true
    when '-a'
      result[:action] = val
    when '-q'
      result[:quiet] = true
    when '-h'
      help_cmd.call result
      return
    else
      if val && val[0] == '-'
        help_cmd.call result
        return
      end

      if resembles_datastore_assignment?(val)
        name, val = val.split('=', 2)
        if name.upcase == 'ACTION'
          result[:action] = val
        else
          warn_unknown_datastore_option(name) if mod
          append_datastore_option(datastore_options, name, val)
        end
      elsif resembles_rhost_value?(val)
        append_datastore_option(datastore_options, 'RHOSTS', val)
      else
        print_error("Invalid argument #{val}")
        help_cmd.call result
        return
      end
    end
  end

  result
end

#parse_run_opts(args, action: nil) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 50

def parse_run_opts(args, action: nil)
  help_cmd = proc do |result|
    if result[:action].nil?
      cmd_run_help
    else
      cmd_action_help(action)
    end
  end

  parse_opts(@@module_opts_with_action_support, args, help_cmd: help_cmd, action: action)
end


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 69

def print_module_run_or_check_usage(command:, description: nil, options: @@module_opts)
  description ||= command == :check ? 'Check if the target is vulnerable' : "Run the current #{name.downcase} module"

  is_http_mod = mod.is_a?(Msf::Exploit::Remote::HttpClient)
  is_smb_mod = mod.is_a?(Msf::Exploit::Remote::SMB::Client) || mod.options.include?('SMBUser')
  is_mysql_mod = mod.is_a?(Msf::Exploit::Remote::MYSQL)

  print_line("Usage: #{command} [options] [RHOSTS]")
  print_line('')
  print_line(description)
  print_line(options.usage)
  print_line('Examples:')
  print_line('')
  print_line("    #{command} 192.168.1.123")
  print_line("    #{command} 192.168.1.1-192.168.1.254")
  print_line("    #{command} file:///tmp/rhost_list.txt")
  print_line("    #{command} http://192.168.1.123/foo") if is_http_mod
  print_line("    #{command} http://user:pass@192.168.1.123/foo") if is_http_mod
  print_line("    #{command} HttpTrace=true http://192.168.1.123/foo") if is_http_mod
  print_line("    #{command} mysql://user:pass@192.168.1.123") if is_mysql_mod
  print_line("    #{command} SQL='select version()' mysql://user:pass@192.168.1.123") if is_mysql_mod && mod.options.include?('SQL')
  print_line("    #{command} smb://192.168.1.123") if is_smb_mod
  print_line("    #{command} smb://user:pass@192.168.1.123") if is_smb_mod
  print_line("    #{command} LPATH=/tmp/foo.txt smb://user:pass@192.168.1.123/share_name/foo.txt") if is_smb_mod && mod.options.include?('RPATH')
  print_line('')
  print_line('Learn more at https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html')
  print_line('')
end

#quote_whitespaced_value(val) ⇒ Object (protected)

Wraps values which contain spaces in quotes to ensure it’s handled correctly later



210
211
212
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 210

def quote_whitespaced_value(val)
  val.include?(' ') ? "\"#{val}\"" : val
end

#resembles_datastore_assignment?(val) ⇒ Boolean (protected)

Returns:

  • (Boolean)


174
175
176
177
178
179
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 174

def resembles_datastore_assignment?(val)
  return false unless val

  valid_option_regex = /^(\w|::)+=.*/
  valid_option_regex.match?(val)
end

#resembles_rhost_value?(val) ⇒ Boolean (protected)

Returns:

  • (Boolean)


181
182
183
184
185
186
187
188
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 181

def resembles_rhost_value?(val)
  return false unless val

  ::Addressable::URI.parse(val)
  true
rescue ::Addressable::URI::InvalidURIError => _e
  false
end

#warn_unknown_datastore_option(name) ⇒ Object (protected)



204
205
206
207
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 204

def warn_unknown_datastore_option(name)
  message = unknown_datastore_option_message(mod, name)
  print_warning(message) if message
end