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
}
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.



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

def cmd_list
  @cmd_list
end

#decoderObject

Returns the value of attribute decoder.



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

def decoder
  @decoder
end

#exeObject

Returns the value of attribute exe.



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

def exe
  @exe
end

#flavorObject

Returns the value of attribute flavor.



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

def flavor
  @flavor
end

#stager_instanceObject

Returns the value of attribute stager_instance.



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

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.



312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/msf/core/exploit/cmdstager.rb', line 312

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.



200
201
202
# File 'lib/msf/core/exploit/cmdstager.rb', line 200

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.



210
211
212
# File 'lib/msf/core/exploit/cmdstager.rb', line 210

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.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/msf/core/exploit/cmdstager.rb', line 76

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.



329
330
# File 'lib/msf/core/exploit/cmdstager.rb', line 329

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.



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

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)


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

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



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

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.



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/msf/core/exploit/cmdstager.rb', line 252

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.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/msf/core/exploit/cmdstager.rb', line 50

def initialize(info = {})
  super

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

  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.



286
287
288
289
290
291
292
293
294
# File 'lib/msf/core/exploit/cmdstager.rb', line 286

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.



189
190
191
192
193
# File 'lib/msf/core/exploit/cmdstager.rb', line 189

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.



161
162
163
164
165
# File 'lib/msf/core/exploit/cmdstager.rb', line 161

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.



176
177
178
179
180
181
# File 'lib/msf/core/exploit/cmdstager.rb', line 176

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.



224
225
226
227
228
# File 'lib/msf/core/exploit/cmdstager.rb', line 224

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.



239
240
241
242
243
244
245
# File 'lib/msf/core/exploit/cmdstager.rb', line 239

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.



302
303
304
305
306
# File 'lib/msf/core/exploit/cmdstager.rb', line 302

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