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

#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, #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_options, #register_advanced_options, #register_evasion_options, #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_warning, #alert_user, #errors, #get_alerts, included, #is_usable?, #warnings

Constructor Details

#initialize(info = {}) ⇒ Evasion

Returns a new instance of Evasion.


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
51
# File 'lib/msf/core/evasion.rb', line 12

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


321
322
323
# File 'lib/msf/core/evasion.rb', line 321

def default_target
  @default_target
end

#payloadObject

Returns the value of attribute payload


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

def payload
  @payload
end

#payload_infoObject

Returns the value of attribute payload_info


325
326
327
# File 'lib/msf/core/evasion.rb', line 325

def payload_info
  @payload_info
end

#payload_instanceObject

Returns the value of attribute payload_instance


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

def payload_instance
  @payload_instance
end

#targetsObject

Returns the value of attribute targets


323
324
325
# File 'lib/msf/core/evasion.rb', line 323

def targets
  @targets
end

Class Method Details

.typeObject


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

def self.type
  Msf::MODULE_EVASION
end

Instance Method Details

#aggressive?Boolean

Returns:

  • (Boolean)

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

def aggressive?
  false
end

#cleanupObject


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

def cleanup
end

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

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


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/msf/core/evasion.rb', line 121

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


255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/msf/core/evasion.rb', line 255

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


269
270
# File 'lib/msf/core/evasion.rb', line 269

def encode_begin(real_payload, reqs)
end

#encode_end(real_payload, reqs, encoded) ⇒ Object


272
273
274
# File 'lib/msf/core/evasion.rb', line 272

def encode_end(real_payload, reqs, encoded)
  encoded
end

#evasion_commandsObject


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

def evasion_commands
  {}
end

#fail_with(reason, msg = nil) ⇒ Object


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

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

#file_create(data) ⇒ Object


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

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


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

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.


174
175
176
177
178
179
180
181
182
# File 'lib/msf/core/evasion.rb', line 174

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


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

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'].to_i
  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['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['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)

313
314
315
316
317
318
319
# File 'lib/msf/core/evasion.rb', line 313

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

  • Payload (TrueClass)

    is compatible.

  • Payload (FlaseClass)

    is not compatible.

Returns:

  • (Boolean)

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

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

  pi = p.new

  # 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


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

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)

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

def passive?
  true
end

#runObject

Raises:

  • (NotImplementedError)

142
143
144
# File 'lib/msf/core/evasion.rb', line 142

def run
  raise NotImplementedError
end

#setupObject


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

def setup
  alert_user
end

#stanceObject


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

def stance
  'passive'
end

#targetObject


276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/msf/core/evasion.rb', line 276

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.


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

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

#target_indexObject


294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/msf/core/evasion.rb', line 294

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.


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

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

#typeObject


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

def type
  Msf::MODULE_EVASION
end