Module: Msf::Exploit::CmdStager

Includes:
HTTP, EXE
Defined in:
lib/msf/core/exploit/cmdstager.rb,
lib/msf/core/exploit/cmdstager/http.rb

Overview

This mixin provides an interface to generating cmdstagers

Defined Under Namespace

Modules: HTTP

Constant Summary collapse

STAGERS =

Constant for stagers - used when creating an stager instance.

{
  :bourne => Rex::Exploitation::CmdStagerBourne,
  :debug_asm => Rex::Exploitation::CmdStagerDebugAsm,
  :debug_write => Rex::Exploitation::CmdStagerDebugWrite,
  :echo => Rex::Exploitation::CmdStagerEcho,
  :printf => Rex::Exploitation::CmdStagerPrintf,
  :vbs => Rex::Exploitation::CmdStagerVBS,
  :vbs_adodb => Rex::Exploitation::CmdStagerVBS,
  :certutil => Rex::Exploitation::CmdStagerCertutil,
  :tftp => Rex::Exploitation::CmdStagerTFTP,
  :wget => Rex::Exploitation::CmdStagerWget,
  :curl => Rex::Exploitation::CmdStagerCurl,
  :fetch => Rex::Exploitation::CmdStagerFetch,
  :lwprequest => Rex::Exploitation::CmdStagerLwpRequest,
  :psh_invokewebrequest => Rex::Exploitation::CmdStagerPSHInvokeWebRequest
}
DECODERS =

Constant for decoders - used when checking the default flavor decoder.

{
  :debug_asm => File.join(Rex::Exploitation::DATA_DIR, "exploits", "cmdstager", "debug_asm"),
  :debug_write => File.join(Rex::Exploitation::DATA_DIR, "exploits", "cmdstager", "debug_write"),
  :vbs => File.join(Rex::Exploitation::DATA_DIR, "exploits", "cmdstager", "vbs_b64"),
  :vbs_adodb => File.join(Rex::Exploitation::DATA_DIR, "exploits", "cmdstager", "vbs_b64_adodb")
}

Instance Attribute Summary collapse

Attributes included from Remote::SocketServer

#service

Instance Method Summary collapse

Methods included from HTTP

#on_request_uri, #start_service

Methods included from Remote::HttpServer

#add_resource, #add_robots_resource, #autofilter, #check_dependencies, #cleanup, #cli, #cli=, #close_client, #create_response, #fingerprint_user_agent, #get_resource, #get_uri, #hardcoded_uripath, #on_request_uri, #print_prefix, #random_uri, #regenerate_payload, #remove_resource, #report_user_agent, #resource_uri, #send_local_redirect, #send_not_found, #send_redirect, #send_response, #send_robots, #srvhost_addr, #srvport, #start_service, #use_zlib

Methods included from Auxiliary::Report

#active_db?, #create_cracked_credential, #create_credential, #create_credential_and_login, #create_credential_login, #db, #db_warning_given?, #get_client, #get_host, #inside_workspace_boundary?, #invalidate_login, #mytask, #myworkspace, #myworkspace_id, #report_auth_info, #report_client, #report_exploit, #report_host, #report_loot, #report_note, #report_service, #report_vuln, #report_web_form, #report_web_page, #report_web_site, #report_web_vuln, #store_cred, #store_local, #store_loot

Methods included from Metasploit::Framework::Require

optionally, optionally_active_record_railtie, optionally_include_metasploit_credential_creation, #optionally_include_metasploit_credential_creation, optionally_require_metasploit_db_gem_engines

Methods included from Remote::TcpServer

#on_client_close, #on_client_connect, #ssl, #ssl_cert, #ssl_cipher, #ssl_compression, #start_service

Methods included from Remote::SocketServer

#_determine_server_comm, #cleanup, #exploit, #on_client_data, #primer, #regenerate_payload, #srvhost, #srvport, #start_service, #stop_service, #via_string_for_ip

Methods included from EXE

#exe_init_options, #exe_post_generation, #generate_payload_dccw_gdiplus_dll, #generate_payload_dll, #generate_payload_exe, #generate_payload_exe_service, #generate_payload_msi, #get_custom_exe, #get_eicar_exe

Instance Attribute Details

#cmd_listObject

Returns the value of attribute cmd_list


41
42
43
# File 'lib/msf/core/exploit/cmdstager.rb', line 41

def cmd_list
  @cmd_list
end

#decoderObject

Returns the value of attribute decoder


43
44
45
# File 'lib/msf/core/exploit/cmdstager.rb', line 43

def decoder
  @decoder
end

#exeObject

Returns the value of attribute exe


44
45
46
# File 'lib/msf/core/exploit/cmdstager.rb', line 44

def exe
  @exe
end

#flavorObject

Returns the value of attribute flavor


42
43
44
# File 'lib/msf/core/exploit/cmdstager.rb', line 42

def flavor
  @flavor
end

#stager_instanceObject

Returns the value of attribute stager_instance


40
41
42
# File 'lib/msf/core/exploit/cmdstager.rb', line 40

def stager_instance
  @stager_instance
end

Instance Method Details

#compatible_flavor?(f) ⇒ Boolean

Answers if the input flavor is compatible with the current target or module.

Parameters:

  • f (Symbol)

    The flavor to check

Returns:

  • (Boolean)

    true if compatible, false otherwise.


320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/msf/core/exploit/cmdstager.rb', line 320

def compatible_flavor?(f)
  return true if target_flavor.nil?
  case target_flavor
  when String
    return true if target_flavor == f.to_s
  when Array
    target_flavor.each { |tr| return true if tr.to_sym == f }
  when Symbol
    return true if target_flavor == f
  end
  false
end

#create_stagerRex::Exploitation::CmdStagerBase

Create an instance of the flavored stager.

Returns:

  • (Rex::Exploitation::CmdStagerBase)

    The cmd stager to use.

Raises:

  • (NoMethodError)

    raised if the flavor doesn't exist.


208
209
210
# File 'lib/msf/core/exploit/cmdstager.rb', line 208

def create_stager
  STAGERS[flavor].new(exe)
end

#default_decoder(f) ⇒ Symbol?

Returns the default decoder stub for the input flavor.

Parameters:

  • f (Symbol)

    the input flavor.

Returns:

  • (Symbol)

    the decoder.

  • (nil)

    if there isn't a default decoder to use for the current cmd stager flavor.


218
219
220
# File 'lib/msf/core/exploit/cmdstager.rb', line 218

def default_decoder(f)
  DECODERS[f]
end

#execute_cmdstager(opts = {}) ⇒ void

This method returns an undefined value.

Executes the command stager while showing the progress. This method should be called from exploits using this mixin.

Parameters:

  • opts (Hash) (defaults to: {})

    Hash containing configuration options. Also allow to send opts to the Rex::Exploitation::CmdStagerBase constructor.

Options Hash (opts):

  • :flavor (Symbol)

    The CMD Stager to use.

  • :decoder (Symbol)

    The decoder stub to use.

  • :delay (Float)

    Delay between command executions.


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/msf/core/exploit/cmdstager.rb', line 84

def execute_cmdstager(opts = {})
  self.cmd_list = generate_cmdstager(opts)

  stager_instance.setup(self)

  begin
    execute_cmdstager_begin(opts)

    sent = 0
    total_bytes = 0
    cmd_list.each { |cmd| total_bytes += cmd.length }

    delay = opts[:delay]
    delay ||= 0.25

    cmd_list.each do |cmd|
      execute_command(cmd, opts)
      sent += cmd.length

      # In cases where a server has multiple threads, we want to be sure that
      # commands we execute happen in the correct (serial) order.
      ::IO.select(nil, nil, nil, delay)

      progress(total_bytes, sent)
    end

    execute_cmdstager_end(opts)
  ensure
    stager_instance.teardown(self)
  end
end

#execute_cmdstager_begin(opts = {}) ⇒ Object

Code to execute before the cmd stager stub. This method is designed to be overriden by a module this mixin.

Parameters:

  • opts (Hash) (defaults to: {})

    Hash of configuration options.


337
338
# File 'lib/msf/core/exploit/cmdstager.rb', line 337

def execute_cmdstager_begin(opts = {})
end

#execute_cmdstager_end(opts = {}) ⇒ Object

Code to execute after the cmd stager stub. This method is designed to be overriden by a module this mixin.

Parameters:

  • opts (Hash) (defaults to: {})

    Hash of configuration options.


344
345
# File 'lib/msf/core/exploit/cmdstager.rb', line 344

def execute_cmdstager_end(opts = {})
end

#execute_command(cmd, opts = {}) ⇒ Object

Code called to execute each command via an arbitrary module-defined vector. This method needs to be overriden by modules using this mixin.

Parameters:

  • cmd (String)

    The command to execute.

  • opts (Hash) (defaults to: {})

    Hash of configuration options.

Raises:

  • (NotImplementedError)

352
353
354
# File 'lib/msf/core/exploit/cmdstager.rb', line 352

def execute_command(cmd, opts = {})
  raise NotImplementedError
end

#generate_cmdstager(opts = {}, pl = nil) ⇒ Array

Generates a cmd stub based on the current target's architecture and platform.

Parameters:

  • opts (Hash) (defaults to: {})

    Hash containing configuration options. Also allow to send opts to the Rex::Exploitation::CmdStagerBase constructor.

  • pl (String) (defaults to: nil)

    String containing the payload to execute

Options Hash (opts):

  • :flavor (Symbol)

    The CMD Stager to use.

  • :decoder (Symbol)

    The decoder stub to use.

Returns:

  • (Array)

    The list of commands to execute

Raises:

  • (ArgumentError)

    raised if the exe or cmd stub cannot be generated


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
# File 'lib/msf/core/exploit/cmdstager.rb', line 127

def generate_cmdstager(opts = {}, pl = nil)
  select_cmdstager(opts)

  exe_opts = {code: pl}.merge(
    platform: target_platform,
    arch: target_arch
  )
  self.exe = generate_payload_exe(exe_opts)

  if exe.nil?
    raise ArgumentError, 'The executable could not be generated'
  end

  self.stager_instance = create_stager

  if datastore['CMDSTAGER::TEMP']
    opts[:temp] = datastore['CMDSTAGER::TEMP']
  elsif datastore['WritableDir']
    opts[:temp] = datastore['WritableDir']
  end

  if stager_instance.respond_to?(:http?) && stager_instance.http?
    opts[:ssl] = datastore['CMDSTAGER::SSL'] unless opts.key?(:ssl)
    opts[:payload_uri] = start_service(opts)
  end

  cmd_list = stager_instance.generate(opts_with_decoder(opts))

  if cmd_list.nil? || cmd_list.length.zero?
    raise ArgumentError, 'The command stager could not be generated'
  end

  vprint_status("Generated command stager: #{cmd_list.inspect}")

  cmd_list
end

#guess_flavorSymbol?

Guess the cmd stager flavor to use using information from the module, target or platform.

Returns:

  • (Symbol)

    The cmd stager flavor to use.

  • (nil)

    if the cmd stager flavor cannot be guessed.


260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/msf/core/exploit/cmdstager.rb', line 260

def guess_flavor
  # First try to guess a compatible flavor based on the module & target information.
  unless target_flavor.nil?
    case target_flavor
    when Array
      return target_flavor[0].to_sym
    when String
      return target_flavor.to_sym
    when Symbol
      return target_flavor
    end
  end

  # Second try to guess a compatible flavor based on the target platform.
  return nil unless target_platform.names.length == 1
  c_platform = target_platform.names.first
  case c_platform
  when /linux/i
    :bourne
  when /osx/i
    :bourne
  when /unix/i
    :bourne
  when /win/i
    :vbs
  else
    nil
  end
end

#initialize(info = {}) ⇒ Msf::Module::Exploit

Creates an instance of an exploit that uses an CMD Stager and register the datastore options provided by the mixin.

Parameters:

  • info (Hash) (defaults to: {})

    Hash containing information to initialize the exploit.

Returns:

  • (Msf::Module::Exploit)

    the exploit module.


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/msf/core/exploit/cmdstager.rb', line 51

def initialize(info = {})
  super

  flavors = module_flavors
  flavors = STAGERS.keys if flavors.empty?
  flavors.unshift('auto')

  server_conditions = ['CMDSTAGER::FLAVOR', 'in', %w{certutil tftp wget curl fetch lwprequest psh_invokewebrequest}]
  register_options(
    [
      OptAddressLocal.new('SRVHOST', [true, 'The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.', '0.0.0.0' ], conditions: server_conditions),
      OptPort.new('SRVPORT', [true, "The local port to listen on.", 8080], conditions: server_conditions)
    ])

  register_advanced_options(
    [
      OptEnum.new('CMDSTAGER::FLAVOR', [false, 'The CMD Stager to use.', 'auto', flavors]),
      OptString.new('CMDSTAGER::DECODER', [false, 'The decoder stub to use.']),
      OptString.new('CMDSTAGER::TEMP', [false, 'Writable directory for staged files']),
      OptBool.new('CMDSTAGER::SSL', [false, 'Use SSL/TLS for supported stagers', false])
    ], self.class)
end

#module_flavorsArray

Returns all the compatible stager flavors specified by the module and each of its targets.

Returns:

  • (Array)

    the list of all compatible cmd stager flavors.


294
295
296
297
298
299
300
301
302
# File 'lib/msf/core/exploit/cmdstager.rb', line 294

def module_flavors
  flavors = []
  flavors += Array(module_info['CmdStagerFlavor']) if module_info['CmdStagerFlavor']
  targets.each do |target|
    flavors += Array(target.opts['CmdStagerFlavor']) if target.opts['CmdStagerFlavor']
  end
  flavors.uniq!
  flavors.map { |flavor| flavor.to_s }
end

#opts_with_decoder(opts = {}) ⇒ Hash

Returns a hash with the :decoder option if possible

Parameters:

  • opts (Hash) (defaults to: {})

    Input Hash.

Returns:

  • (Hash)

    Hash with the input data and a :decoder option when possible.


197
198
199
200
201
# File 'lib/msf/core/exploit/cmdstager.rb', line 197

def opts_with_decoder(opts = {})
  return opts if opts.include?(:decoder)
  return opts.merge(:decoder => decoder) if decoder
  opts
end

#progress(total, sent) ⇒ void

This method returns an undefined value.

Show the progress of the upload while cmd staging

Parameters:

  • total (Float)

    The total number of bytes to send.

  • sent (Float)

    The number of bytes sent.


169
170
171
172
173
# File 'lib/msf/core/exploit/cmdstager.rb', line 169

def progress(total, sent)
  done = (sent.to_f / total.to_f) * 100
  percent = "%3.2f%%" % done.to_f
  print_status("Command Stager progress - %7s done (%d/%d bytes)" % [percent, sent, total])
end

#select_cmdstager(opts = {}) ⇒ void

This method returns an undefined value.

Selects the correct cmd stager and decoder stub to use

Parameters:

  • opts (Hash) (defaults to: {})

    Hash containing the options to select the correct cmd stager and decoder.

Options Hash (opts):

  • :flavor (Symbol)

    The cmd stager to use.

  • :decoder (Symbol)

    The decoder stub to use.

Raises:

  • (ArgumentError)

    raised if a cmd stager cannot be selected or it isn't compatible with the target platform.


184
185
186
187
188
189
# File 'lib/msf/core/exploit/cmdstager.rb', line 184

def select_cmdstager(opts = {})
  self.flavor = select_flavor(opts)
  raise ArgumentError, "Unable to select CMD Stager" if flavor.nil?
  raise ArgumentError, "The CMD Stager '#{flavor}' isn't compatible with the target" unless compatible_flavor?(flavor)
  self.decoder = select_decoder(opts)
end

#select_decoder(opts = {}) ⇒ String?

Selects the correct cmd stager decoder to use based on three rules: (1) use the decoder provided in input options, (2) use the decoder provided by the user through datastore options, (3) select the default decoder for the current cmd stager flavor if available.

Parameters:

  • opts (Hash) (defaults to: {})

    Hash containing the options to select the correct decoder.

Options Hash (opts):

  • :decoder (String)

    The decoder stub to use.

Returns:

  • (String)

    The decoder.

  • (nil)

    if a decoder cannot be selected.


232
233
234
235
236
# File 'lib/msf/core/exploit/cmdstager.rb', line 232

def select_decoder(opts = {})
  return opts[:decoder] if opts.include?(:decoder)
  return datastore['CMDSTAGER::DECODER'] unless datastore['CMDSTAGER::DECODER'].blank?
  default_decoder(flavor)
end

#select_flavor(opts = {}) ⇒ Symbol?

Selects the correct cmd stager to use based on three rules: (1) use the flavor provided in options, (2) use the flavor provided by the user through datastore options, (3) guess the flavor using the target platform.

Parameters:

  • opts (Hash) (defaults to: {})

    Hash containing the options to select the correct cmd stager

Options Hash (opts):

  • :flavor (Symbol)

    The cmd stager flavor to use.

Returns:

  • (Symbol)

    The flavor to use.

  • (nil)

    if a flavor cannot be selected.


247
248
249
250
251
252
253
# File 'lib/msf/core/exploit/cmdstager.rb', line 247

def select_flavor(opts = {})
  return opts[:flavor].to_sym if opts.include?(:flavor)
  unless datastore['CMDSTAGER::FLAVOR'].blank? or datastore['CMDSTAGER::FLAVOR'] == 'auto'
    return datastore['CMDSTAGER::FLAVOR'].to_sym
  end
  guess_flavor
end

#target_flavorArray, ...

Returns the compatible stager flavors for the current target or module.

Returns:

  • (Array)

    the list of compatible cmd stager flavors.

  • (Symbol)

    the compatible cmd stager flavor.

  • (String)

    the compatible cmd stager flavor.

  • (nil)

    if there isn't any compatible flavor defined.


310
311
312
313
314
# File 'lib/msf/core/exploit/cmdstager.rb', line 310

def target_flavor
  return target.opts['CmdStagerFlavor'] if target && target.opts['CmdStagerFlavor']
  return module_info['CmdStagerFlavor'] if module_info['CmdStagerFlavor']
  nil
end