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.


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

def stage_prefix
  @stage_prefix
end

Instance Method Details

#assemblyString?

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

Returns:

  • (String, nil)

71
72
73
# File 'lib/msf/core/payload/stager.rb', line 71

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

#encode_stage(stg) ⇒ String

Encodes the stage prior to transmission

Returns:

  • (String)

    Encoded version of stg


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
311
312
313
314
# File 'lib/msf/core/payload/stager.rb', line 268

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)

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

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


260
261
262
263
264
# File 'lib/msf/core/payload/stager.rb', line 260

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


163
164
165
166
167
168
169
# File 'lib/msf/core/payload/stager.rb', line 163

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.


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/msf/core/payload/stager.rb', line 143

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.


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
229
230
231
232
# File 'lib/msf/core/payload/stager.rb', line 176

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.


244
245
246
# File 'lib/msf/core/payload/stager.rb', line 244

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.


252
253
254
# File 'lib/msf/core/payload/stager.rb', line 252

def handle_intermediate_stage(conn, payload)
  false
end

#initialize(info = {}) ⇒ Object


15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/msf/core/payload/stager.rb', line 15

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)

81
82
83
# File 'lib/msf/core/payload/stager.rb', line 81

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)

63
64
65
# File 'lib/msf/core/payload/stager.rb', line 63

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

#payload_typeObject

Sets the payload type to a stager.


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

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

#sends_hex_uuid?Boolean

Returns:

  • (Boolean)

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

def sends_hex_uuid?
  false
end

#stage_assemblyString

Returns the assembly text of the stage payload.

Returns:

  • (String)

102
103
104
105
106
107
# File 'lib/msf/core/payload/stager.rb', line 102

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)

116
117
118
119
120
121
# File 'lib/msf/core/payload/stager.rb', line 116

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)

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

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)

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

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


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/msf/core/payload/stager.rb', line 33

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