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

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

Overview

Exploit module command dispatcher.

Constant Summary collapse

@@exploit_opts =
Rex::Parser::Arguments.new(
"-e" => [ true,  "The payload encoder to use.  If none is specified, ENCODER is used." ],
"-f" => [ false, "Force the exploit to run regardless of the value of MinimumRank."    ],
"-h" => [ false, "Help banner."                                                        ],
"-j" => [ false, "Run in the context of a job."                                        ],
"-J" => [ false, "Force running in the foreground, even if passive."                   ],
"-n" => [ true,  "The NOP generator to use.  If none is specified, NOP is used."       ],
"-o" => [ true,  "A comma separated list of options in VAR=VAL format."                ],
"-p" => [ true,  "The payload to use.  If none is specified, PAYLOAD is used."         ],
"-t" => [ true,  "The target index to use.  If none is specified, TARGET is used."     ],
"-z" => [ false, "Do not interact with the session after successful exploitation."     ])

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 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, #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, #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, #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?


292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 292

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.


91
92
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 91

def cmd_exploit(*args)
  force = false
  module_opts = []
  any_session = false
  opts = {
    'Encoder'     => mod.datastore['ENCODER'],
    'Payload'     => mod.datastore['PAYLOAD'],
    'Target'      => mod.datastore['TARGET'],
    'Nop'         => mod.datastore['NOP'],
    'OptionStr'   => nil,
    'LocalInput'  => driver.input,
    'LocalOutput' => driver.output,
    'RunAsJob'    => false,
    'Background'  => false,
    'Force'       => false
  }

  if mod.passive?
    opts['RunAsJob'] = true
  end

  @@exploit_opts.parse(args) do |opt, idx, val|
    case opt
    when '-e'
      opts['Encoder'] = val
    when '-f'
      force = true
    when '-j'
      opts['RunAsJob'] = true
    when '-J'
      opts['RunAsJob'] = false
    when '-n'
      opts['Nop'] = val
    when '-o'
      module_opts.push(val)
    when '-p'
      opts['Payload'] = val
    when '-t'
      opts['Target'] = val.to_i
    when '-z'
      opts['Background'] = true
    when '-h'
      cmd_exploit_help
      return false
    else
      if val[0] != '-' && val.match?('=')
        module_opts.push(val)
      else
        cmd_exploit_help
        return false
      end
    end
  end

  unless module_opts.empty?
    opts['OptionStr'] = module_opts.join(',')
  end

  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

  rhosts = mod.datastore['RHOSTS']
  if rhosts
    rhosts_opt = Msf::OptAddressRange.new('RHOSTS')
    rhosts_range = Rex::Socket::RangeWalker.new(rhosts_opt.normalize(rhosts))
  end
  # For multiple targets exploit attempts.
  if rhosts_range && rhosts_range.length.to_i > 1
    opts[:multi] = true
    rhosts_range.each do |rhost|
      nmod = mod.replicant
      nmod.datastore['RHOST'] = rhost
      # If rhost is the last target, let exploit handler stop.
      opts["multi"] = false if rhost == (Rex::Socket.addr_itoa(rhosts_range.ranges.first.stop))
      # Catch the interrupt exception to stop the whole module during exploit
      begin
        print_status("Exploiting target #{rhost}")
        session = exploit_single(nmod, opts)
      rescue ::Interrupt
        print_status("Stopping exploiting current target #{rhost}...")
        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
    # avoid bug when the cidr of rhosts is 32, like 8.8.8.8/32
    if rhosts_range && rhosts_range.length == 1
      mod.datastore['RHOST'] = (Rex::Socket.addr_itoa(rhosts_range.ranges.first.start))
    end
    session = exploit_single(mod, 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'] && mod.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 #{mod.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 luanch.
  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.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


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

def cmd_exploit_help
  print_line "Usage: exploit [options]"
  print_line
  print_line "Launches an exploitation attempt."
  print @@exploit_opts.usage
end

#cmd_exploit_tabs(str, words) ⇒ Object


72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 72

def cmd_exploit_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                                               ]
  }
  tab_complete_generic(fmt, str, words)
end

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

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


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

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.


269
270
271
272
273
274
275
276
277
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 269

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


281
282
283
284
285
286
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 281

def cmd_rexploit_help
  print_line "Usage: rexploit [options]"
  print_line
  print_line "Reloads a module, stopping any associated job, and launches an exploitation attempt."
  print @@exploit_opts.usage
end

#commandsObject

Returns the hash of exploit module specific commands.


31
32
33
34
35
36
37
38
39
40
41
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 31

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.


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 53

def exploit_single(mod, opts)
  begin
    session = mod.exploit_simple(opts)
  rescue ::Interrupt
    raise $!
  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.


46
47
48
# File 'lib/msf/ui/console/command_dispatcher/exploit.rb', line 46

def name
  "Exploit"
end