Class: Msf::Payload

Inherits:
Module show all
Defined in:
lib/msf/core/payload.rb

Overview

This class represents the base class for a logical payload. The framework automatically generates payload combinations at runtime which are all extended for this Payload as a base class.

Defined Under Namespace

Modules: Aix, Bsd, Dalvik, Firefox, Generic, JSP, Java, Linux, Netware, NodeJS, Osx, Php, Ruby, Single, Solaris, Stager, Type, Windows

Instance Attribute Summary collapse

Attributes inherited from Module

#arch, #author, #datastore, #error, #job_id, #license, #module_store, #options, #platform, #privileged, #references, #uuid

Attributes included from Framework::Offspring

#framework

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

#user_input

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

#user_output

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Module

#[], #[]=, #alias, #arch?, #arch_to_s, #author_to_s, #auxiliary?, cached?, #check, #comm, #compat, #compatible?, #debugging?, #description, #disclosure_date, #each_arch, #each_author, #encoder?, #exploit?, #fail_with, #file_path, #framework, #fullname, fullname, #import_defaults, is_usable, #name, #nop?, #orig_cls, #owner, #payload?, #platform?, #platform_to_s, #post?, #print_error, #print_good, #print_line, #print_line_prefix, #print_prefix, #print_status, #print_warning, #privileged?, #rank, rank, #rank_to_h, rank_to_h, #rank_to_s, rank_to_s, #refname, #register_parent, #replicant, #search_filter, #share_datastore, shortname, #shortname, #support_ipv6?, #target_host, #target_port, #validate, #vprint_debug, #vprint_error, #vprint_good, #vprint_line, #vprint_status, #vprint_warning, #workspace

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_debug, #print_error, #print_good, #print_line, #print_status, #print_warning

Constructor Details

#initialize(info = {}) ⇒ Payload

Creates an instance of a payload module using the supplied information.


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/msf/core/payload.rb', line 64

def initialize(info = {})
  super

  # If this is a staged payload but there is no stage information,
  # then this is actually a stager + single combination.  Set up the
  # information hash accordingly.
  if self.class.include?(Msf::Payload::Single) and
    self.class.include?(Msf::Payload::Stager)
    self.module_info['Stage'] = {}

    if self.module_info['Payload']
      self.module_info['Stage']['Payload']  = self.module_info['Payload']['Payload'] || ""
      self.module_info['Stage']['Assembly'] = self.module_info['Payload']['Assembly'] || ""
      self.module_info['Stage']['Offsets']  = self.module_info['Payload']['Offsets'] || {}
    else
      self.module_info['Stage']['Payload']  = ""
      self.module_info['Stage']['Assembly'] = ""
      self.module_info['Stage']['Offsets']  = {}
    end

    @staged = true
  else
    @staged = false
  end

  # Update the module info hash with the connection type
  # that is derived from the handler for this payload.  This is
  # used for compatibility filtering purposes.
  self.module_info['ConnectionType'] = connection_type
end

Instance Attribute Details

#appendObject

This attribute holds the string that should be appended to the buffer when it's generated.


491
492
493
# File 'lib/msf/core/payload.rb', line 491

def append
  @append
end

#assoc_exploitObject

If this payload is associated with an exploit, the assoc_exploit attribute will point to that exploit instance.


502
503
504
# File 'lib/msf/core/payload.rb', line 502

def assoc_exploit
  @assoc_exploit
end

#prependObject

This attribute holds the string that should be prepended to the buffer when it's generated.


486
487
488
# File 'lib/msf/core/payload.rb', line 486

def prepend
  @prepend
end

#prepend_encoderObject

This attribute holds the string that should be prepended to the encoded version of the payload (in front of the encoder as well).


496
497
498
# File 'lib/msf/core/payload.rb', line 496

def prepend_encoder
  @prepend_encoder
end

Class Method Details

.typeObject

Returns MODULE_PAYLOAD to indicate that this is a payload module.


104
105
106
# File 'lib/msf/core/payload.rb', line 104

def self.type
  return MODULE_PAYLOAD
end

Instance Method Details

#assemblyObject

Returns the assembly string that describes the payload if one exists.


186
187
188
# File 'lib/msf/core/payload.rb', line 186

def assembly
  return module_info['Payload'] ? module_info['Payload']['Assembly'] : nil
end

#assembly=(asm) ⇒ Object

Sets the assembly string that describes the payload If this method is used to define the payload, a payload with no offsets will be created


194
195
196
197
# File 'lib/msf/core/payload.rb', line 194

def assembly=(asm)
  module_info['Payload'] ||= {'Offsets' => {} }
  module_info['Payload']['Assembly'] = asm
end

#badcharsObject

Returns the string of bad characters for this payload, if any.


118
119
120
# File 'lib/msf/core/payload.rb', line 118

def badchars
  return self.module_info['BadChars']
end

#compatible_convention?(conv) ⇒ Boolean

Checks to see if the supplied convention is compatible with this payload's convention.


236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/msf/core/payload.rb', line 236

def compatible_convention?(conv)
  # If we ourself don't have a convention or our convention is equal to
  # the one supplied, then we know we are compatible.
  if ((self.convention == nil) or
      (self.convention == conv))
    true
  # On the flip side, if we are a stager and the supplied convention is
  # nil, then we know it's compatible.
  elsif ((payload_type == Type::Stager) and
         (conv == nil))
    true
  # Otherwise, the conventions don't match in some way or another, and as
  # such we deem ourself as not being compatible with the supplied
  # convention.
  else
    false
  end
end

#compatible_encodersObject

Returns the array of compatible encoders for this payload instance.


413
414
415
416
417
418
419
420
421
422
# File 'lib/msf/core/payload.rb', line 413

def compatible_encoders
  encoders = []

  framework.encoders.each_module_ranked(
    'Arch' => self.arch, 'Platform' => self.platform) { |name, mod|
    encoders << [ name, mod ]
  }

  return encoders
end

#compatible_nopsObject

Returns the array of compatible nops for this payload instance.


427
428
429
430
431
432
433
434
435
436
# File 'lib/msf/core/payload.rb', line 427

def compatible_nops
  nops = []

  framework.nops.each_module_ranked(
    'Arch' => self.arch) { |name, mod|
    nops << [ name, mod ]
  }

  return nops
end

#connection_typeObject

Returns the module's connection type, such as reverse, bind, noconn, or whatever else the case may be.


220
221
222
# File 'lib/msf/core/payload.rb', line 220

def connection_type
  handler_klass.general_handler_type
end

#conventionObject

Returns the staging convention that the payload uses, if any. This is used to make sure that only compatible stagers and stages are built (where assumptions are made about register/environment initialization state and hand-off).


212
213
214
# File 'lib/msf/core/payload.rb', line 212

def convention
  module_info['Convention']
end

#generateObject

Generates the payload and returns the raw buffer to the caller.


280
281
282
# File 'lib/msf/core/payload.rb', line 280

def generate
  internal_generate
end

#handler_klassObject

Return the connection associated with this payload, or none if there isn't one.


259
260
261
# File 'lib/msf/core/payload.rb', line 259

def handler_klass
  return module_info['Handler'] || Msf::Handler::None
end

#offsetsObject

Returns the offsets to variables that must be substitute, if any.


202
203
204
# File 'lib/msf/core/payload.rb', line 202

def offsets
  return module_info['Payload'] ? module_info['Payload']['Offsets'] : nil
end

#on_session(session) ⇒ Object

Once an exploit completes and a session has been created on behalf of the payload, the framework will call the payload's on_session notification routine to allow it to manipulate the session prior to handing off control to the user.


450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
# File 'lib/msf/core/payload.rb', line 450

def on_session(session)


  # If this payload is associated with an exploit, inform the exploit
  # that a session has been created and potentially shut down any
  # open sockets. This allows active exploits to continue hammering
  # on a service until a session is created.
  if (assoc_exploit)

    # Signal that a new session is created by calling the exploit's
    # on_new_session handler. The default behavior is to set an
    # instance variable, which the exploit will have to check.
    begin
      assoc_exploit.on_new_session(session)
    rescue ::Exception => e
      dlog("#{assoc_exploit.refname}: on_new_session handler triggered exception: #{e.class} #{e} #{e.backtrace}", 'core', LEV_1)	rescue nil
    end

    # Set the abort sockets flag only if the exploit is not passive
    # and the connection type is not 'find'
    if (
      (assoc_exploit.exploit_type == Exploit::Type::Remote) and
      (assoc_exploit.passive? == false) and
      (connection_type != 'find')
       )
       assoc_exploit.abort_sockets
    end

  end

end

#payloadObject

Returns the raw payload that has not had variable substitution occur.


179
180
181
# File 'lib/msf/core/payload.rb', line 179

def payload
  return module_info['Payload'] ? module_info['Payload']['Payload'] : nil
end

#payload_typeObject

Returns the type of payload, either single or staged. Stage is the default because singles and stagers are encouraged to include the Single and Stager mixin which override the payload_type.


135
136
137
# File 'lib/msf/core/payload.rb', line 135

def payload_type
  return Type::Stage
end

#payload_type_sObject

Returns the string version of the payload type


142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/msf/core/payload.rb', line 142

def payload_type_s
  case payload_type
    when Type::Stage
      return "stage"
    when Type::Stager
      return "stager"
    when Type::Single
      return "single"
    else
      return "unknown"
  end
end

#replace_var(raw, name, offset, pack) ⇒ Object

Replaces an individual variable in the supplied buffer at an offset using the given pack type. This is here to allow derived payloads the opportunity to replace advanced variables.


399
400
401
# File 'lib/msf/core/payload.rb', line 399

def replace_var(raw, name, offset, pack)
  return false
end

#save_registersObject

The list of registers that should be saved by any NOP generators or encoders, if possible.


126
127
128
# File 'lib/msf/core/payload.rb', line 126

def save_registers
  return self.module_info['SaveRegisters']
end

#sessionObject

Returns the session class that is associated with this payload and will be used to create a session as necessary.


267
268
269
# File 'lib/msf/core/payload.rb', line 267

def session
  return module_info['Session']
end

#sizeObject

Returns the payload's size. If the payload is staged, the size of the first stage is returned.


166
167
168
169
170
171
172
173
174
# File 'lib/msf/core/payload.rb', line 166

def size
  pl = nil
  begin
    pl = generate()
  rescue NoCompatiblePayloadError
  end
  pl ||= ''
  pl.length
end

#staged?Boolean

This method returns whether or not this payload uses staging.


158
159
160
# File 'lib/msf/core/payload.rb', line 158

def staged?
  (@staged or payload_type == Type::Stager or payload_type == Type::Stage)
end

#substitute_vars(raw, offsets) ⇒ Object

Substitutes variables with values from the module's datastore in the supplied raw buffer for a given set of named offsets. For instance, RHOST is substituted with the RHOST value from the datastore which will have been populated by the framework.

Supprted packing types:

  • ADDR (foo.com, 1.2.3.4)

  • ADDR6 (foo.com, fe80::1234:5678:8910:1234)

  • ADDR16MSB, ADD16LSB, ADDR22MSB, ADD22LSB (foo.com, 1.2.3.4) Advanced packing types for 16/16 and 22/10 bits substitution. The 16 bits types uses two offsets indicating where the 16 bits pair will be substituted, while the 22 bits types uses two offsets indicating the instructions where the 22/10 bits pair will be substituted. Normally these are offsets to “sethi” and “or” instructions on SPARC architecture.

  • HEX (0x12345678, “x41x42x43x44”)

  • RAW (raw bytes)


303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
# File 'lib/msf/core/payload.rb', line 303

def substitute_vars(raw, offsets)
  offsets.each_pair { |name, info|
    offset, pack = info

    # Give the derived class a chance to substitute this variable
    next if (replace_var(raw, name, offset, pack) == true)

    # Now it's our turn...
    if ((val = datastore[name]))
      if (pack == 'ADDR')
        val = Rex::Socket.resolv_nbo(val)

        # Someone gave us a funky address (ipv6?)
        if(val.length == 16)
          raise RuntimeError, "IPv6 address specified for IPv4 payload."
        end
      elsif (pack == 'ADDR6')
        val = Rex::Socket.resolv_nbo(val)

        # Convert v4 to the v6ish address
        if(val.length == 4)
          nip = "fe80::5efe:" + val.unpack("C*").join(".")
          val = Rex::Socket.resolv_nbo(nip)
        end
      elsif (['ADDR16MSB', 'ADDR16LSB', 'ADDR22MSB', 'ADDR22LSB'].include?(pack))
        val = Rex::Socket.resolv_nbo(val)

        # Someone gave us a funky address (ipv6?)
        if(val.length == 16)
          raise RuntimeError, "IPv6 address specified for IPv4 payload."
        end
      elsif (pack == 'RAW')
        # Just use the raw value...
      else
        # Check to see if the value is a hex string.  If so, convert
        # it.
        if val.kind_of?(String)
          if val =~ /^\\x/n
            val = [ val.gsub(/\\x/n, '') ].pack("H*").unpack(pack)[0]
          elsif val =~ /^0x/n
            val = val.hex
          end
        end

        # NOTE:
        # Packing assumes integer format at this point, should fix...
        val = [ val.to_i ].pack(pack)
      end

      # Substitute it
      if (['ADDR16MSB', 'ADDR16LSB'].include?(pack))
        if (offset.length != 2)
          raise RuntimeError, "Missing value for payload offset, there must be two offsets."
        end

        if (pack == 'ADDR16LSB')
          val = val.unpack('N').pack('V')
        end

        raw[offset[0], 2] = val[0, 2]
        raw[offset[1], 2] = val[2, 2]

      elsif (['ADDR22MSB', 'ADDR22LSB'].include?(pack))
        if (offset.length != 2)
          raise RuntimeError, "Missing value for payload offset, there must be two offsets."
        end

        if (pack == 'ADDR22LSB')
          val = val.unpack('N').pack('V')
        end

        hi = (0xfffffc00 & val) >> 10
        lo = 0x3ff & val

        ins = raw[offset[0], 4]
        raw[offset[0], 4] = ins | hi

        ins = raw[offset[1], 4]
        raw[offset[1], 4] = ins | lo

      else
        raw[offset, val.length] = val

      end
    else
      wlog("Missing value for payload offset #{name}, skipping.",
        'core', LEV_3)
    end
  }
end

#symbol_lookupObject

Returns the method used by the payload to resolve symbols for the purpose of calling functions, such as ws2ord.


228
229
230
# File 'lib/msf/core/payload.rb', line 228

def symbol_lookup
  module_info['SymbolLookup']
end

#typeObject

Returns MODULE_PAYLOAD to indicate that this is a payload module.


111
112
113
# File 'lib/msf/core/payload.rb', line 111

def type
  return MODULE_PAYLOAD
end