Class: Msf::Evasion

Inherits:
Module show all
Includes:
Auxiliary::Report
Defined in:
lib/msf/core/evasion.rb

Defined Under Namespace

Classes: Complete, Failed

Constant Summary

Constants inherited from Module

Module::REPLICANT_EXTENSION_DS_KEY

Constants included from Module::ModuleInfo

Module::ModuleInfo::UpdateableOptions

Instance Attribute Summary collapse

Attributes inherited from Module

#error, #job_id, #license, #platform, #privileged, #references, #user_data

Attributes included from Framework::Offspring

#framework

Attributes included from Module::UUID

#uuid

Attributes included from Rex::Ui::Subscriber::Input

#user_input

Attributes included from Rex::Ui::Subscriber::Output

#user_output

Attributes included from Module::Privileged

#priveli, #privileged

Attributes included from Module::Options

#options

Attributes included from Module::ModuleStore

#module_store

Attributes included from Module::ModuleInfo

#module_info

Attributes included from Module::FullName

#aliased_as

Attributes included from Module::DataStore

#datastore

Attributes included from Module::Author

#author

Attributes included from Module::Arch

#arch

Attributes included from Module::Alert

#alerts, #you_have_been_warned

Class Method Summary collapse

Instance Method Summary collapse

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 inherited from Module

#adapted_refname, #adapter_refname, #black_listed_auth_filenames, cached?, #debugging?, #default_cred?, #file_path, #framework, #has_check?, #orig_cls, #owner, #perform_extensions, #platform?, #platform_to_s, #post_auth?, #register_extensions, #register_parent, #replicant, #required_cred_options, #set_defaults, #stage_refname, #stager_refname, #workspace

Methods included from Module::Reliability

#reliability, #reliability_to_s

Methods included from Module::Stability

#stability, #stability_to_s

Methods included from Module::SideEffects

#side_effects, #side_effects_to_s

Methods included from Module::UUID

#generate_uuid

Methods included from Module::UI

#init_ui

Methods included from Module::UI::Message

#print_error, #print_good, #print_prefix, #print_status, #print_warning

Methods included from Module::UI::Message::Verbose

#vprint_error, #vprint_good, #vprint_status, #vprint_warning

Methods included from Module::UI::Line

#print_line, #print_line_prefix

Methods included from Module::UI::Line::Verbose

#vprint_line

Methods included from Rex::Ui::Subscriber

#copy_ui, #init_ui, #reset_ui

Methods included from Rex::Ui::Subscriber::Input

#gets

Methods included from Rex::Ui::Subscriber::Output

#flush, #print, #print_blank_line, #print_error, #print_good, #print_line, #print_status, #print_warning

Methods included from Module::Type

#auxiliary?, #encoder?, #evasion?, #exploit?, #nop?, #payload?, #post?

Methods included from Module::Ranking

#rank, #rank_to_h, #rank_to_s

Methods included from Module::Privileged

#privileged?

Methods included from Module::Options

#deregister_option_group, #deregister_options, #register_advanced_options, #register_evasion_options, #register_option_group, #register_options, #validate

Methods included from Module::Network

#comm, #support_ipv6?, #target_host, #target_port

Methods included from Module::ModuleStore

#[], #[]=

Methods included from Module::ModuleInfo

#alias, #description, #disclosure_date, #info_fixups, #merge_check_key, #merge_info, #merge_info_advanced_options, #merge_info_alias, #merge_info_description, #merge_info_evasion_options, #merge_info_name, #merge_info_options, #merge_info_string, #merge_info_version, #name, #notes, #update_info

Methods included from Module::FullName

#aliases, #fullname, #promptname, #realname, #refname, #shortname

Methods included from Module::DataStore

#import_defaults, #import_target_defaults, #share_datastore

Methods included from Module::Compatibility

#compat, #compatible?, #init_compat

Methods included from Module::Author

#author_to_s, #each_author

Methods included from Module::Auth

#store_valid_credential

Methods included from Module::Arch

#arch?, #arch_to_s, #each_arch

Methods included from Module::Alert

#add_alert, #add_error, #add_info, #add_warning, #alert_user, #errors, #get_alerts, included, #infos, #is_usable?, #warnings, #without_prompt

Constructor Details

#initialize(info = {}) ⇒ Evasion

Returns a new instance of Evasion.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/msf/core/evasion.rb', line 11

def initialize(info={})
  if (info['Payload'] and info['Payload']['Compat'])
    info['Compat'] = Hash.new if (info['Compat'] == nil)
    info['Compat']['Payload'] = Hash.new if (info['Compat']['Payload'] == nil)
    info['Compat']['Payload'].update(info['Payload']['Compat'])
  end

  super(info)

  self.payload_info = info['Payload'] || {}
  self.targets = Rex::Transformer.transform(info['Targets'], Array, [ Target ], 'Targets')

  if info.key? 'DefaultTarget'
    self.default_target = info['DefaultTarget']
  else
    self.default_target = 0
    # Add an auto-target to the evasion if it doesn't have one
    if info['Targets'] && info['Targets'].count > 1 && !has_auto_target?(info['Targets'])
      # Finally, only add the target if there is a remote host option
      if self.respond_to?(:rhost) && self.respond_to?(:auto_targeted_index)
        auto = ["Automatic", {'AutoGenerated' => true}.merge(info['Targets'][self.default_target][1])]
        info['Targets'].unshift(auto)
      end
    end
  end

  if (info['Payload'] and info['Payload']['ActiveTimeout'])
    self.active_timeout = info['Payload']['ActiveTimeout'].to_i
  end

  register_options([
    OptString.new(
      'FILENAME',
        [
          true,
          'Filename for the evasive file (default: random)',
          "#{Rex::Text.rand_text_alpha(3..10)}.exe"
        ])
  ], self.class)
end

Instance Attribute Details

#default_targetObject

Returns the value of attribute default_target.



327
328
329
# File 'lib/msf/core/evasion.rb', line 327

def default_target
  @default_target
end

#payloadObject

Returns the value of attribute payload.



337
338
339
# File 'lib/msf/core/evasion.rb', line 337

def payload
  @payload
end

#payload_infoObject

Returns the value of attribute payload_info.



331
332
333
# File 'lib/msf/core/evasion.rb', line 331

def payload_info
  @payload_info
end

#payload_instanceObject

Returns the value of attribute payload_instance.



335
336
337
# File 'lib/msf/core/evasion.rb', line 335

def payload_instance
  @payload_instance
end

#targetsObject

Returns the value of attribute targets.



329
330
331
# File 'lib/msf/core/evasion.rb', line 329

def targets
  @targets
end

Class Method Details

.typeObject



52
53
54
# File 'lib/msf/core/evasion.rb', line 52

def self.type
  Msf::MODULE_EVASION
end

Instance Method Details

#aggressive?Boolean

Returns:

  • (Boolean)


169
170
171
# File 'lib/msf/core/evasion.rb', line 169

def aggressive?
  false
end

#cleanupObject



150
151
# File 'lib/msf/core/evasion.rb', line 150

def cleanup
end

#compatible_payloads(excluded_platforms: [], excluded_archs: []) ⇒ Object

Returns a list of compatible payloads based on platform, architecture, and size requirements.



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/msf/core/evasion.rb', line 125

def compatible_payloads(excluded_platforms: [], excluded_archs: [])
  payloads = []

  c_platform, c_arch = normalize_platform_arch

  # The "All" platform name represents generic payloads
  results = Msf::Modules::Metadata::Cache.instance.find(
    'type'     => [['payload'], []],
    'platform' => [[*c_platform.names, 'All'], excluded_platforms],
    'arch'     => [c_arch, excluded_archs]
  )

  results.each do |res|
    if is_payload_compatible?(res.ref_name)
      payloads << [res.ref_name, framework.payloads[res.ref_name]]
    end
  end

  payloads
end

#define_context_encoding_reqs(reqs) ⇒ Object



261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/msf/core/evasion.rb', line 261

def define_context_encoding_reqs(reqs)
  return unless datastore['EnableContextEncoding']

  # At present, we don't support any automatic methods of obtaining
  # context information.  In the future, we might support obtaining
  # temporal information remotely.

  # Pass along the information specified in our evasion datastore as
  # encoder options
  reqs['EncoderOptions'] = {} if reqs['EncoderOptions'].nil?
  reqs['EncoderOptions']['EnableContextEncoding']  = datastore['EnableContextEncoding']
  reqs['EncoderOptions']['ContextInformationFile'] = datastore['ContextInformationFile']
end

#encode_begin(real_payload, reqs) ⇒ Object



275
276
# File 'lib/msf/core/evasion.rb', line 275

def encode_begin(real_payload, reqs)
end

#encode_end(real_payload, reqs, encoded) ⇒ Object



278
279
280
# File 'lib/msf/core/evasion.rb', line 278

def encode_end(real_payload, reqs, encoded)
  encoded
end

#evasion_commandsObject



157
158
159
# File 'lib/msf/core/evasion.rb', line 157

def evasion_commands
  {}
end

#fail_with(reason, msg = nil) ⇒ Object



153
154
155
# File 'lib/msf/core/evasion.rb', line 153

def fail_with(reason, msg=nil)
  raise Msf::Evasion::Failed, "#{reason}: #{msg}"
end

#file_create(data) ⇒ Object



68
69
70
71
72
73
# File 'lib/msf/core/evasion.rb', line 68

def file_create(data)
  fname = file_format_filename
  ltype = "evasion.fileformat.#{self.shortname}"
  full_path = store_local(ltype, nil, data, fname)
  print_good "#{fname} stored at #{full_path}"
end

#file_format_filenameObject



64
65
66
# File 'lib/msf/core/evasion.rb', line 64

def file_format_filename
  datastore['FILENAME']
end

#generate_payload(pinst = nil) ⇒ Object

Generates the encoded version of the supplied payload using the payload requirements specific to this evasion module. The encoded instance is returned to the caller. This method is exposed in the manner that it is such that passive evasions and re-generate an encoded payload on the fly rather than having to use the pre-generated one.



178
179
180
181
182
183
184
185
186
# File 'lib/msf/core/evasion.rb', line 178

def generate_payload(pinst = nil)
  # Set the encoded payload to the result of the encoding process
  self.payload = generate_single_payload(pinst)

  # Save the payload instance
  self.payload_instance = (pinst) ? pinst : self.payload_instance

  return self.payload
end

#generate_single_payload(pinst = nil, platform = nil, arch = nil, explicit_target = nil) ⇒ Object



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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/msf/core/evasion.rb', line 188

def generate_single_payload(pinst = nil, platform = nil, arch = nil, explicit_target = nil)
  explicit_target ||= target

  # If a payload instance was supplied, use it, otherwise
  # use the active payload instance
  real_payload = (pinst) ? pinst : self.payload_instance

  if (real_payload == nil)
    raise MissingPayloadError, "No payload has been selected.",
      caller
  end

  # If this is a generic payload, then we should specify the platform
  # and architecture so that it knows how to pass things on.
  if real_payload.kind_of?(Msf::Payload::Generic)
    # Convert the architecture specified into an array.
    if arch and arch.kind_of?(String)
      arch = [ arch ]
    end

    # Define the explicit platform and architecture information only if
    # it's been specified.
    if platform
      real_payload.explicit_platform = Msf::Module::PlatformList.transform(platform)
    end

    if arch
      real_payload.explicit_arch = arch
    end

    # Force it to reset so that it will find updated information.
    real_payload.reset
  end

  # Duplicate the evasion payload requirements
  reqs = self.payload_info.dup

  # Pass save register requirements to the NOP generator
  reqs['Space']           = payload_info['Space'] ? payload_info['Space'].to_i : nil
  reqs['SaveRegisters']   = module_info['SaveRegisters']
  reqs['Prepend']         = payload_info['Prepend']
  reqs['PrependEncoder']  = payload_info['PrependEncoder']
  reqs['BadChars']        = payload_info['BadChars']
  reqs['Append']          = payload_info['Append']
  reqs['AppendEncoder']   = payload_info['AppendEncoder']
  reqs['DisableNops']     = payload_info['DisableNops']
  reqs['MaxNops']         = payload_info['MaxNops']
  reqs['MinNops']         = payload_info['MinNops']
  reqs['Encoder']         = datastore['ENCODER'] || payload_info['Encoder']
  reqs['Nop']             = datastore['NOP'] || payload_info['Nop']
  reqs['EncoderType']     = payload_info['EncoderType']
  reqs['EncoderOptions']  = payload_info['EncoderOptions']
  reqs['ExtendedOptions'] = payload_info['ExtendedOptions']
  reqs['ForceEncode']     = payload_info['ForceEncode']
  reqs['Evasion']         = self

  # Pass along the encoder don't fall through flag
  reqs['EncoderDontFallThrough'] = datastore['EncoderDontFallThrough']

  # Incorporate any context encoding requirements that are needed
  define_context_encoding_reqs(reqs)

  # Call the encode begin routine.
  encode_begin(real_payload, reqs)

  # Generate the encoded payload.
  encoded = EncodedPayload.create(real_payload, reqs)

  # Call the encode end routine which is expected to return the actual
  # encoded payload instance.
  return encode_end(real_payload, reqs, encoded)
end

#has_auto_target?(targets = []) ⇒ Boolean

Returns:

  • (Boolean)


319
320
321
322
323
324
325
# File 'lib/msf/core/evasion.rb', line 319

def has_auto_target?(targets=[])
  target_names = targets.collect { |target| target.first}
  target_names.each do |target|
    return true if target =~ /Automatic/
  end
  return false
end

#is_payload_compatible?(name) ⇒ Boolean

Returns whether the requested payload is compatible with the module

Parameters:

  • name (String)

    The payload name

Returns:

  • (Boolean)

    True if the payload is compatible, False if not.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/msf/core/evasion.rb', line 101

def is_payload_compatible?(name)
  p = framework.payloads[name]
  return false unless p

  begin
    pi = p.new
  rescue ::Exception, ::LoadError => e
    wlog("Module #{name} failed to initialize payload when checking evasion compatibility: #{e}", 'core', LEV_0)
    return false
  end

  # Are we compatible in terms of conventions and connections and
  # what not?
  return false if !compatible?(pi)

  # If the payload is privileged but the evasion does not give
  # privileged access, then fail it.
  return false if !self.privileged && pi.privileged

  return true
end

#normalize_platform_archObject



90
91
92
93
94
95
# File 'lib/msf/core/evasion.rb', line 90

def normalize_platform_arch
  c_platform = (target && target.platform) ? target.platform : platform
  c_arch     = (target && target.arch)     ? target.arch     : (arch == []) ? nil : arch
  c_arch   ||= [ ARCH_X86 ]
  return c_platform, c_arch
end

#passive?Boolean

Returns:

  • (Boolean)


165
166
167
# File 'lib/msf/core/evasion.rb', line 165

def passive?
  true
end

#runObject

Raises:

  • (NotImplementedError)


146
147
148
# File 'lib/msf/core/evasion.rb', line 146

def run
  raise NotImplementedError
end

#setupObject



60
61
62
# File 'lib/msf/core/evasion.rb', line 60

def setup
  alert_user
end

#stanceObject



161
162
163
# File 'lib/msf/core/evasion.rb', line 161

def stance
  'passive'
end

#targetObject



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/msf/core/evasion.rb', line 282

def target
  if self.respond_to?(:auto_targeted_index)
    if auto_target?
      auto_idx = auto_targeted_index
      if auto_idx.present?
        datastore['TARGET'] = auto_idx
      else
        # If our inserted Automatic Target was selected but we failed to
        # find a suitable target, we just grab the original first target.
        datastore['TARGET'] = 1
      end
    end
  end

  target_idx = target_index
  return (target_idx) ? targets[target_idx.to_i] : nil
end

#target_archObject

Returns the target's architecture, or the one assigned to the module itself.



86
87
88
# File 'lib/msf/core/evasion.rb', line 86

def target_arch
  (target and target.arch) ? target.arch : (arch == []) ? nil : arch
end

#target_indexObject



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/msf/core/evasion.rb', line 300

def target_index
  target_idx =
    begin
      Integer(datastore['TARGET'])
    rescue TypeError, ArgumentError
      datastore['TARGET']
    end

  default_idx = default_target || 0
  # Use the default target if one was not supplied.
  if (target_idx == nil and default_idx and default_idx >= 0)
    target_idx = default_idx
  elsif target_idx.is_a?(String)
    target_idx = targets.index { |target| target.name == target_idx }
  end

  return (target_idx) ? target_idx.to_i : nil
end

#target_platformObject

Returns the target's platform, or the one assigned to the module itself.



78
79
80
# File 'lib/msf/core/evasion.rb', line 78

def target_platform
  (target and target.platform) ? target.platform : platform
end

#typeObject



56
57
58
# File 'lib/msf/core/evasion.rb', line 56

def type
  Msf::MODULE_EVASION
end