Module: Msf::Payload::Stager

Includes:
TransportConfig
Included in:
Osx::ReverseTcp_x64
Defined in:
lib/msf/core/payload/stager.rb

Overview

Base mixin interface for use by stagers.

Constant Summary

Constants included from Rex::Payloads::Meterpreter::UriChecksum

Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_CONN, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_CONN_MAX_LEN, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITJ, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITN, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITP, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITW, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INIT_CONN, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_MIN_LEN, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_MODES, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_UUID_MIN_LEN

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from TransportConfig

#transport_config_bind_named_pipe, #transport_config_bind_tcp, #transport_config_reverse_http, #transport_config_reverse_https, #transport_config_reverse_ipv6_tcp, #transport_config_reverse_named_pipe, #transport_config_reverse_tcp, #transport_config_reverse_udp, #transport_uri_components

Methods included from UUID::Options

#generate_payload_uuid, #generate_uri_uuid_mode, #record_payload_uuid, #record_payload_uuid_url

Methods included from Rex::Payloads::Meterpreter::UriChecksum

#generate_uri_checksum, #generate_uri_uuid, #process_uri_resource, #uri_checksum_lookup

Instance Attribute Details

#stage_prefixObject

A value that should be prefixed to a stage, such as a tag.


319
320
321
# File 'lib/msf/core/payload/stager.rb', line 319

def stage_prefix
  @stage_prefix
end

Instance Method Details

#assemblyString?

Return the stager payload's assembly text, if any.

Returns:

  • (String, nil)

67
68
69
# File 'lib/msf/core/payload/stager.rb', line 67

def assembly
  return module_info['Stager']['Assembly']
end

#encode_stage(stg) ⇒ String

Encodes the stage prior to transmission

Returns:

  • (String)

    Encoded version of stg


264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/msf/core/payload/stager.rb', line 264

def encode_stage(stg)
  return stg unless encode_stage?
  stage_enc_mod = nil

  # Handle StageEncoder if specified by the user
  if datastore['StageEncoder'].to_s.length > 0
    stage_enc_mod = datastore["StageEncoder"]
  end

  # Allow the user to specify additional registers to preserve
  saved_registers =
    datastore['StageEncoderSaveRegisters'].to_s +
    " " +
    encode_stage_preserved_registers
  saved_registers.strip!

  estg = nil
  begin
    # Generate an encoded version of the stage.  We tell the encoding system
    # to save certain registers to ensure that it does not get clobbered.
    encp = Msf::EncodedPayload.create(
      self,
      'Raw'                => stg,
      'Encoder'            => stage_enc_mod,
      'EncoderOptions'     => { 'SaveRegisters' => saved_registers },
      'ForceSaveRegisters' => true,
      'ForceEncode'        => true)

    if encp.encoder
      if stage_enc_mod
        print_status("Encoded stage with #{stage_enc_mod}")
      else
        print_status("Encoded stage with #{encp.encoder.refname}")
      end
      estg = encp.encoded
    end
  rescue
    if datastore['StageEncodingFallback'] && estg.nil?
      print_warning("StageEncoder failed, falling back to no encoding")
      estg = stg
    else
      raise RuntimeError, "Stage encoding failed and StageEncodingFallback is disabled"
    end
  end

  estg
end

#encode_stage?Boolean

Whether to use an Encoder on the second stage

Returns:

  • (Boolean)

131
132
133
# File 'lib/msf/core/payload/stager.rb', line 131

def encode_stage?
  !!(datastore['EnableStageEncoding'])
end

#encode_stage_preserved_registersObject

Takes an educated guess at the list of registers an encoded stage would need to preserve based on the Convention


256
257
258
259
260
# File 'lib/msf/core/payload/stager.rb', line 256

def encode_stage_preserved_registers
  module_info['Convention'].to_s.scan(/\bsock([a-z]{3,}+)\b/).
    map {|reg| reg.first }.
    join(" ")
end

#format_uuid(uuid_raw) ⇒ Object


159
160
161
162
163
164
165
# File 'lib/msf/core/payload/stager.rb', line 159

def format_uuid(uuid_raw)
  if sends_hex_uuid?
    return uuid_raw
  end

  return Msf::Payload::UUID.new({raw: uuid_raw})
end

#generate_stage(opts = {}) ⇒ String

Generates the stage payload and substitutes all offsets.

Returns:

  • (String)

    The generated payload stage, as a string.


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

def generate_stage(opts={})
  # XXX: This is nearly identical to Payload#internal_generate

  # Compile the stage as necessary
  if stage_assembly and !stage_assembly.empty?
    raw = build(stage_assembly, stage_offsets)
  else
    raw = stage_payload(opts)
  end

  # Substitute variables in the stage
  substitute_vars(raw, stage_offsets) if (stage_offsets)

  return raw
end

#handle_connection(conn, opts = {}) ⇒ Object

Transmit the associated stage.


172
173
174
175
176
177
178
179
180
181
182
183
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
# File 'lib/msf/core/payload/stager.rb', line 172

def handle_connection(conn, opts={})
  # If the stage should be sent over the client connection that is
  # established (which is the default), then go ahead and transmit it.
  if (stage_over_connection?)
    if respond_to? :include_send_uuid
      if include_send_uuid
        uuid_raw = conn.get_once(16, 1)
        if uuid_raw
          opts[:uuid] = format_uuid(uuid_raw)
        end
      end
    end

    p = generate_stage(opts)

    # Encode the stage if stage encoding is enabled
    begin
      p = encode_stage(p)
    rescue ::RuntimeError
      warning_msg = "Failed to stage"
      warning_msg << " (#{conn.peerhost})"  if conn.respond_to? :peerhost
      warning_msg << ": #{$!}"
      print_warning warning_msg
      if conn.respond_to? :close && !conn.closed?
        conn.close
      end
      return
    end

    # Give derived classes an opportunity to an intermediate state before
    # the stage is sent.  This gives derived classes an opportunity to
    # augment the stage and the process through which it is read on the
    # remote machine.
    #
    # If we don't use an intermediate stage, then we need to prepend the
    # stage prefix, such as a tag
    if handle_intermediate_stage(conn, p) == false
      p = (self.stage_prefix || '') + p
    end

    sending_msg = "Sending #{encode_stage? ? "encoded ":""}stage"
    sending_msg << " (#{p.length} bytes)"
    # The connection should always have a peerhost (even if it's a
    # tunnel), but if it doesn't, erroring out here means losing the
    # session, so make sure it does, just to be safe.
    if conn.respond_to? :peerhost
      sending_msg << " to #{conn.peerhost}"
    end
    print_status(sending_msg)

    # Send the stage
    conn.put(p)
  end

  # Give the stages a chance to handle the connection
  handle_connection_stage(conn, opts)
end

#handle_connection_stage(conn, opts = {}) ⇒ Object

Allow the stage to process whatever it is it needs to process.

Override to deal with sending the final stage in cases where #generate_stage is not the whole picture, such as when uploading an executable. The default is to simply attempt to create a session on the given conn socket with Handler#create_session.


240
241
242
# File 'lib/msf/core/payload/stager.rb', line 240

def handle_connection_stage(conn, opts={})
  create_session(conn, opts)
end

#handle_intermediate_stage(conn, payload) ⇒ Object

Gives derived classes an opportunity to alter the stage and/or encapsulate its transmission.


248
249
250
# File 'lib/msf/core/payload/stager.rb', line 248

def handle_intermediate_stage(conn, payload)
  false
end

#initialize(info = {}) ⇒ Object


11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/msf/core/payload/stager.rb', line 11

def initialize(info={})
  super

  register_advanced_options(
    [
      Msf::OptBool.new("EnableStageEncoding", [ false, "Encode the second stage payload", false ]),
      Msf::OptString.new("StageEncoder", [ false, "Encoder to use if EnableStageEncoding is set", nil ]),
      Msf::OptString.new("StageEncoderSaveRegisters", [ false, "Additional registers to preserve in the staged payload if EnableStageEncoding is set", "" ]),
      Msf::OptBool.new("StageEncodingFallback", [ false, "Fallback to no encoding if the selected StageEncoder is not compatible", true ])
    ], Msf::Payload::Stager)

end

#offsetsHash Also known as: stager_offsets

Return the stager payload's offsets.

These will be used for substitutions during stager generation.

Returns:

  • (Hash)

77
78
79
# File 'lib/msf/core/payload/stager.rb', line 77

def offsets
  return module_info['Stager']['Offsets']
end

#payloadString? Also known as: stager_payload

Return the stager payload's raw payload.

Can be nil if the stager is not pre-assembled.

Returns:

  • (String, nil)

59
60
61
# File 'lib/msf/core/payload/stager.rb', line 59

def payload
  return module_info['Stager']['Payload']
end

#payload_typeObject

Sets the payload type to a stager.


49
50
51
# File 'lib/msf/core/payload/stager.rb', line 49

def payload_type
  return Msf::Payload::Type::Stager
end

#sends_hex_uuid?Boolean

Returns:

  • (Boolean)

155
156
157
# File 'lib/msf/core/payload/stager.rb', line 155

def sends_hex_uuid?
  false
end

#stage_assemblyString

Returns the assembly text of the stage payload.

Returns:

  • (String)

98
99
100
101
102
103
# File 'lib/msf/core/payload/stager.rb', line 98

def stage_assembly
  if module_info['Stage']
    return module_info['Stage']['Assembly']
  end
  nil
end

#stage_offsetsHash

Returns variable offsets within the stage payload.

These will be used for substitutions during generation of the final stage.

Returns:

  • (Hash)

112
113
114
115
116
117
# File 'lib/msf/core/payload/stager.rb', line 112

def stage_offsets
  if module_info['Stage']
    return module_info['Stage']['Offsets']
  end
  nil
end

#stage_over_connection?Boolean

Whether or not any stages associated with this stager should be sent over the connection that is established.

Returns:

  • (Boolean)

123
124
125
# File 'lib/msf/core/payload/stager.rb', line 123

def stage_over_connection?
  true
end

#stage_payload(opts = {}) ⇒ String?

Returns the raw stage payload.

Can be nil if the final stage is not pre-assembled.

Returns:

  • (String, nil)

87
88
89
90
91
92
# File 'lib/msf/core/payload/stager.rb', line 87

def stage_payload(opts = {})
  if module_info['Stage']
    return module_info['Stage']['Payload']
  end
  nil
end

#transport_config(opts = {}) ⇒ Object

Perform attempt at detecting the appropriate transport config. Call the determined config with passed options. Override this in stages/stagers to use specific transports


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/msf/core/payload/stager.rb', line 29

def transport_config(opts={})
  if self.refname =~ /reverse_/
      direction = 'reverse'
  else
      direction = 'bind'
  end

  if self.refname =~ /_tcp/
      proto = 'tcp'
  elsif self.refname =~ /_https/
      proto = 'https'
  else
      proto = 'http'
  end
  send("transport_config_#{direction}_#{proto}", opts)
end