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

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'                        ]
)
@@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

Instance Method Details

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



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

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



40
41
42
43
44
45
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 40

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)
end

#parse_exploit_opts(args) ⇒ Object



59
60
61
62
63
64
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 59

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

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



97
98
99
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
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 97

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)
        append_datastore_option(datastore_options, name, value)
      end
    when '-p'
      result[:payload] = val
    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)
        append_datastore_option(datastore_options, name, val)
      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



47
48
49
50
51
52
53
54
55
56
57
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 47

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


66
67
68
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
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 66

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://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit')
  print_line('')
end

#quote_whitespaced_value(val) ⇒ Object (protected)

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



194
195
196
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 194

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

#resembles_datastore_assignment?(val) ⇒ Boolean (protected)

Returns:

  • (Boolean)


163
164
165
166
167
168
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 163

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)


170
171
172
173
174
175
176
177
# File 'lib/msf/ui/console/module_argument_parsing.rb', line 170

def resembles_rhost_value?(val)
  return false unless val

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