Class: Msf::Ui::Console::CommandDispatcher::Exploit

Inherits:
Object
  • Object
show all
Includes:
ModuleArgumentParsing, ModuleCommandDispatcher, ModuleOptionTabCompletion
Defined in:
lib/msf/ui/console/command_dispatcher/exploit.rb

Overview

Exploit module command dispatcher.

Instance Attribute Summary

Attributes included from Msf::Ui::Console::CommandDispatcher

#driver

Attributes included from Rex::Ui::Text::DispatcherShell::CommandDispatcher

#shell, #tab_complete_items

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ModuleOptionTabCompletion

#option_values_actions, #option_values_dispatch, #option_values_encoders, #option_values_nops, #option_values_payloads, #option_values_sessions, #option_values_target_addrs, #option_values_target_ports, #option_values_targets, #tab_complete_datastore_names, #tab_complete_option, #tab_complete_option_names, #tab_complete_option_values, #tab_complete_source_interface

Methods included from ModuleArgumentParsing

#append_datastore_option, #parse_check_opts, #parse_exploit_opts, #parse_opts, #parse_run_opts, #print_module_run_or_check_usage, #quote_whitespaced_value, #resembles_datastore_assignment?, #resembles_rhost_value?

Methods included from ModuleCommandDispatcher

#check_multiple, #check_progress, #check_show_progress, #check_simple, #cmd_check, #cmd_check_help, #cmd_reload, #cmd_reload_help, #mod, #mod=, #reload, #report_vuln

Methods included from Msf::Ui::Console::CommandDispatcher

#active_module, #active_module=, #active_session, #active_session=, #build_range_array, #docs_dir, #framework, #initialize, #load_config, #log_error, #remove_lines

Methods included from Rex::Ui::Text::DispatcherShell::CommandDispatcher

#cmd_help, #cmd_help_help, #cmd_help_tabs, #deprecated_cmd, #deprecated_commands, #deprecated_help, #docs_dir, #help_to_s, included, #initialize, #print, #print_error, #print_good, #print_line, #print_status, #print_warning, #tab_complete_directory, #tab_complete_filenames, #tab_complete_generic, #tab_complete_source_address, #unknown_command, #update_prompt

Class Method Details

.choose_payload(mod) ⇒ Object

Select a reasonable default payload and minimally configure it TODO: Move this somewhere better or make it more dynamic?



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 268

def self.choose_payload(mod)
  compatible_payloads = mod.compatible_payloads(
    excluded_platforms: ['Multi'] # We don't want to select a multi payload
  ).map(&:first)

  # XXX: Determine LHOST based on RHOST or an arbitrary internet address
  lhost = Rex::Socket.source_address(mod.datastore['RHOST'] || '50.50.50.50')

  configure_payload = lambda do |payload|
    mod.datastore['PAYLOAD'] = payload

    # Set LHOST if this is a reverse payload
    if payload.index('reverse')
      mod.datastore['LHOST'] = lhost
    end

    payload
  end

  # If there is only one compatible payload, return it immediately
  if compatible_payloads.length == 1
    return configure_payload.call(compatible_payloads.first)
  end

  # XXX: This approach is subpar, and payloads should really be ranked!
  preferred_payloads = [
    # These payloads are generally reliable and common enough in practice
    '/meterpreter/reverse_tcp',
    '/shell/reverse_tcp',
    'cmd/unix/reverse_netcat',
    'cmd/windows/powershell_reverse_tcp',
    # Fall back on a generic payload to autoselect a specific payload
    'generic/shell_reverse_tcp',
    'generic/shell_bind_tcp'
  ]

  # XXX: This is not efficient in the slightest
  preferred_payloads.each do |type|
    payload = compatible_payloads.find { |name| name.end_with?(type) }

    next unless payload

    return configure_payload.call(payload)
  end

  nil
end

Instance Method Details

#cmd_exploit(*args) ⇒ Object Also known as: cmd_run

Launches exploitation attempts.



93
94
95
96
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 93

def cmd_exploit(*args)
  return false unless (args = parse_exploit_opts(args))

  any_session = false
  force = args[:force] || false

  minrank = RankingName.invert[framework.datastore['MinimumRank']] || 0
  if minrank > mod.rank
    if force
      print_status("Forcing #{mod.refname} to run despite MinimumRank '#{framework.datastore['MinimumRank']}'")
      ilog("Forcing #{mod.refname} to run despite MinimumRank '#{framework.datastore['MinimumRank']}'", 'core')
    else
      print_error("This exploit is below the minimum rank, '#{framework.datastore['MinimumRank']}'.")
      print_error("If you really want to run it, do 'exploit -f' or")
      print_error("setg MinimumRank to something lower ('manual' is")
      print_error("the lowest and would allow running all exploits).")
      return
    end
  end

  mod_with_opts = mod.replicant
  mod_with_opts.datastore.import_options_from_hash(args[:datastore_options])
  rhosts = mod_with_opts.datastore['RHOSTS']

  opts = {
    'Encoder'     => args[:encoder] || mod_with_opts.datastore['ENCODER'],
    'Payload'     => args[:payload] || mod_with_opts.datastore['PAYLOAD'],
    'Target'      => args[:target] || mod_with_opts.datastore['TARGET'],
    'Nop'         => args[:nop] || mod_with_opts.datastore['NOP'],
    'LocalInput'  => driver.input,
    'LocalOutput' => driver.output,
    'RunAsJob'    => args[:jobify] || mod_with_opts.passive?,
    'Background'  => args[:background] || false,
    'Force'       => force,
    'Quiet'       => args[:quiet] || false
  }

  begin
    mod_with_opts.validate
  rescue ::Msf::OptionValidateError => e
    ::Msf::Ui::Formatter::OptionValidateError.print_error(mod_with_opts, e)
    return false
  end

  if rhosts
    rhosts_walker = Msf::RhostsWalker.new(rhosts, mod_with_opts.datastore)
    rhosts_walker_count = rhosts_walker.count
    rhosts_walker = rhosts_walker.to_enum
  end

  # For multiple targets exploit attempts.
  if rhosts_walker && rhosts_walker_count > 1
    opts[:multi] = true
    rhosts_walker.with_index do |datastore, index|
      nmod = mod_with_opts.replicant
      nmod.datastore.merge!(datastore)
      # If rhost is the last target, let exploit handler stop.
      is_last_target = (index + 1) == rhosts_walker_count
      opts["multi"] = false if is_last_target
      # Catch the interrupt exception to stop the whole module during exploit
      begin
        print_status("Exploiting target #{datastore['RHOSTS']}")
        session = exploit_single(nmod, opts)
      rescue ::Interrupt
        print_status("Stopping exploiting current target #{datastore['RHOSTS']}...")
        print_status("Control-C again to force quit exploiting all targets.")
        begin
          Rex.sleep(1)
        rescue ::Interrupt
          raise $!
        end
      end
      # If we were given a session, report it.
      if session
        print_status("Session #{session.sid} created in the background.")
        any_session = true
      end
    end
  # For single target or no rhosts option.
  else
    nmod = mod_with_opts.replicant
    if rhosts_walker && rhosts_walker_count == 1
      nmod.datastore.merge!(rhosts_walker.next)
    end
    session = exploit_single(nmod, opts)
    # If we were given a session, let's see what we can do with it
    if session
      any_session = true
      if !opts['Background'] && session.interactive?
        # If we aren't told to run in the background and the session can be
        # interacted with, start interacting with it by issuing the session
        # interaction command.
        print_line

        driver.run_single("sessions -q -i #{session.sid}")
      # Otherwise, log that we created a session
      else
        # Otherwise, log that we created a session
        print_status("Session #{session.sid} created in the background.")
      end

    elsif opts['RunAsJob'] && nmod.job_id
      # Indicate if he exploit as a job, indicate such so the user doesn't
      # wonder what's up.
      print_status("Exploit running as background job #{nmod.job_id}.")
      # Worst case, the exploit ran but we got no session, bummer.
    end
  end

  # If we didn't get any session and exploit ended launch.
  unless any_session
  # If we didn't run a payload handler for this exploit it doesn't
  # make sense to complain to the user that we didn't get a session
    unless mod_with_opts.datastore["DisablePayloadHandler"]
      fail_msg = 'Exploit completed, but no session was created.'
      print_status(fail_msg)
      begin
        framework.events.on_session_fail(fail_msg)
      rescue ::Exception => e
        wlog("Exception in on_session_open event handler: #{e.class}: #{e}")
        wlog("Call Stack\n#{e.backtrace.join("\n")}")
      end
    end
  end
end

#cmd_exploit_helpObject Also known as: cmd_run_help



221
222
223
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 221

def cmd_exploit_help
  print_module_run_or_check_usage(command: :run, options: @@exploit_opts)
end

#cmd_rcheck(*args) ⇒ Object Also known as: cmd_recheck

Reloads an exploit module and checks the target to see if it's vulnerable.



231
232
233
234
235
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 231

def cmd_rcheck(*args)
  reload()

  cmd_check(*args)
end

#cmd_rexploit(*args) ⇒ Object Also known as: cmd_rerun

Reloads an exploit module and launches an exploit.



242
243
244
245
246
247
248
249
250
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 242

def cmd_rexploit(*args)
  return cmd_rexploit_help if args.include? "-h"

  # Stop existing job and reload the module
  if reload(true)
    # Delegate to the exploit command unless the reload failed
    cmd_exploit(*args)
  end
end

#cmd_rexploit_helpObject Also known as: cmd_rerun_help



256
257
258
259
260
261
262
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 256

def cmd_rexploit_help
  print_module_run_or_check_usage(
    command: :rexploit,
    description: 'Reloads a module, stopping any associated job, and launches an exploitation attempt.',
    options: @@exploit_opts
  )
end

#cmd_run_tabs(str, words) ⇒ Object Also known as: cmd_exploit_tabs, cmd_rerun_tabs

Tab completion for the run command



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 67

def cmd_run_tabs(str, words)
  fmt = {
      '-e' => [ framework.encoders.map { |refname, mod| refname } ],
      '-f' => [ nil                                               ],
      '-h' => [ nil                                               ],
      '-j' => [ nil                                               ],
      '-J' => [ nil                                               ],
      '-n' => [ framework.nops.map { |refname, mod| refname }     ],
      '-o' => [ true                                              ],
      '-p' => [ framework.payloads.map { |refname, mod| refname } ],
      '-t' => [ true                                              ],
      '-z' => [ nil                                               ]
  }
  flags = tab_complete_generic(fmt, str, words)
  options = tab_complete_option(active_module, str, words)
  flags + options
end

#commandsObject

Returns the hash of exploit module specific commands.



21
22
23
24
25
26
27
28
29
30
31
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 21

def commands
  super.update({
    "exploit"  => "Launch an exploit attempt",
    "rcheck"   => "Reloads the module and checks if the target is vulnerable",
    "rexploit" => "Reloads the module and launches an exploit attempt",
    "run"      => "Alias for exploit",
    "recheck"  => "Alias for rcheck",
    "rerun"    => "Alias for rexploit",
    "reload"   => "Just reloads the module"
  })
end

#exploit_single(mod, opts) ⇒ Object

Launches an exploitation single attempt.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 43

def exploit_single(mod, opts)
  begin
    session = mod.exploit_simple(opts)
  rescue ::Interrupt
    raise $!
  rescue ::Msf::OptionValidateError => e
   ::Msf::Ui::Formatter::OptionValidateError.print_error(mod, e)
  rescue ::Exception => e
    print_error("Exploit exception (#{mod.refname}): #{e.class} #{e}")
    if e.class.to_s != 'Msf::OptionValidateError'
      print_error("Call stack:")
      e.backtrace.each do |line|
        break if line =~ /lib.msf.base.simple/
        print_error("  #{line}")
      end
    end
  end

  return session
end

#nameObject

Returns the name of the command dispatcher.



36
37
38
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 36

def name
  "Exploit"
end