Class: Msf::Evasion

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

Defined Under Namespace

Classes: Complete, Failed

Instance Attribute Summary collapse

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

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_target ⇒ Object

Returns the value of attribute default_target.



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

def default_target
  @default_target
end

#payload ⇒ Object

Returns the value of attribute payload.



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

def payload
  @payload
end

#payload_info ⇒ Object

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_instance ⇒ Object

Returns the value of attribute payload_instance.



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

def payload_instance
  @payload_instance
end

#targets ⇒ Object

Returns the value of attribute targets.



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

def targets
  @targets
end

Class Method Details

.type ⇒ Object



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

#cleanup ⇒ Object



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_commands ⇒ Object



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_filename ⇒ Object



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_arch ⇒ Object



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

#run ⇒ Object

Raises:

  • (NotImplementedError)


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

def run
  raise NotImplementedError
end

#setup ⇒ Object



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

def setup
  alert_user
end

#stance ⇒ Object



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

def stance
  'passive'
end

#target ⇒ Object



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_arch ⇒ Object

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_index ⇒ Object



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_platform ⇒ Object

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

#type ⇒ Object



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

def type
  Msf::MODULE_EVASION
end