Pivot session stability, display and handling

bug/bundler_fix
OJ 2017-07-18 20:57:46 +10:00 committed by Brent Cook
parent fdc9864b61
commit 7acd772c10
16 changed files with 65 additions and 92 deletions

View File

@ -17,7 +17,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.3.1)
metasploit-payloads (= 1.3.3)
metasploit_data_models
metasploit_payloads-mettle (= 0.2.2)
msgpack
@ -150,7 +150,7 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.3.1)
metasploit-payloads (1.3.3)
metasploit_data_models (2.0.15)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)

View File

@ -40,12 +40,19 @@ class Meterpreter < Rex::Post::Meterpreter::Client
true
end
def tunnel_to_s
if self.pivot_session
"Pivot via [#{self.pivot_session.tunnel_to_s}]"
else
super
end
end
#
# Initializes a meterpreter session instance using the supplied rstream
# that is to be used as the client's connection to the server.
#
def initialize(rstream, opts={})
STDERR.puts("init in meterpreter\n")
super
opts[:capabilities] = {
@ -327,14 +334,14 @@ class Meterpreter < Rex::Post::Meterpreter::Client
#
# Terminates the session
#
def kill
def kill(reason='')
begin
cleanup_meterpreter
self.sock.close if self.sock
rescue ::Exception
end
# deregister will actually trigger another cleanup
framework.sessions.deregister(self)
framework.sessions.deregister(self, reason)
end
#

View File

@ -205,8 +205,6 @@ protected
if self.session.respond_to?('create_session')
s = self.session.create_session(conn, opts)
else
STDERR.puts("create_session caller: #{caller.inspect}\n")
STDERR.puts("create_session opts: #{opts.inspect}\n")
s = self.session.new(conn, opts)
end
rescue ::Exception => e
@ -242,15 +240,12 @@ protected
# new session.
#
def register_session(session)
STDERR.puts("Registering session\n")
# Register the session with the framework
framework.sessions.register(session)
STDERR.puts("Calling on_session\n")
# Call the handler's on_session() method
on_session(session)
session.bootstrap(datastore)
STDERR.puts("Called on_session\n")
# If there is an exploit associated with this payload, then let's notify
# anyone who is interested that this exploit succeeded

View File

@ -89,7 +89,6 @@ module Msf::Payload::Stager
#
# @return [String,nil]
def stage_payload(opts = {})
STDERR.puts("In stager stage_payload: #{opts.inspect}\n")
if module_info['Stage']
return module_info['Stage']['Payload']
end

View File

@ -68,8 +68,6 @@ module Payload::Windows::MeterpreterLoader
end
def stage_payload(opts={})
STDERR.puts("In stage_payload: #{opts.inspect}\n")
stage_meterpreter(opts) + generate_config(opts)
end

View File

@ -74,8 +74,8 @@ module Payload::Windows::ReverseNamedPipe
#{asm_reverse_named_pipe(opts)}
^
"\xCC" + Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
#Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
#"\xCC" + Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
end
#

View File

@ -59,8 +59,6 @@ private
session_guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
end
STDERR.puts("**** Session config expiration: #{opts[:expiration]}\n")
session_data = [
0, # comms socket, patched in by the stager
exit_func, # exit function identifer

View File

@ -81,7 +81,6 @@ class Client
# which communication with the server will be performed.
#
def initialize(sock, opts={})
STDERR.puts("init in client\n")
init_meterpreter(sock, opts)
end
@ -89,6 +88,16 @@ class Client
# Cleans up the meterpreter instance, terminating the dispatcher thread.
#
def cleanup_meterpreter
self.pivots.keys.each do |k|
pivot = self.pivots[k]
pivot.pivoted_session.kill('Pivot closed')
pivot.pivoted_session.shutdown_passive_dispatcher
end
if self.pivot_session
self.pivot_session.remove_pivot(self.session_guid)
end
if not self.skip_cleanup
ext.aliases.each_value do | extension |
extension.cleanup if extension.respond_to?( 'cleanup' )
@ -108,7 +117,6 @@ class Client
# Initializes the meterpreter client instance
#
def init_meterpreter(sock,opts={})
STDERR.puts("init_meterpreter in client.rb\n")
self.sock = sock
self.parser = PacketParser.new
self.ext = ObjectAliases.new
@ -137,11 +145,6 @@ class Client
self.passive_dispatcher = opts[:passive_dispatcher]
end
STDERR.puts("Expr; #{self.expiration.inspect}\n")
STDERR.puts("Comm: #{self.comm_timeout.inspect}\n")
STDERR.puts("TOT: #{self.retry_total.inspect}\n")
STDERR.puts("Wait: #{self.retry_wait.inspect}\n")
self.response_timeout = opts[:timeout] || self.class.default_timeout
self.send_keepalives = true

View File

@ -734,30 +734,21 @@ class ClientCore < Extension
# Negotiates the use of encryption at the TLV level
#
def negotiate_tlv_encryption
STDERR.puts("negotiate_tlv_encryption entry: #{client.inspect}\n")
sym_key = nil
rsa_key = OpenSSL::PKey::RSA.new(2048)
rsa_pub_key = rsa_key.public_key
STDERR.puts("negotiate_tlv_encryption 1\n")
request = Packet.create_request('core_negotiate_tlv_encryption')
STDERR.puts("negotiate_tlv_encryption 2\n")
request.add_tlv(TLV_TYPE_RSA_PUB_KEY, rsa_pub_key.to_pem)
STDERR.puts("negotiate_tlv_encryption 3\n")
begin
response = client.send_request(request)
STDERR.puts("negotiate_tlv_encryption 4\n")
key_enc = response.get_tlv_value(TLV_TYPE_ENC_SYM_KEY)
STDERR.puts("negotiate_tlv_encryption 5\n")
key_type = response.get_tlv_value(TLV_TYPE_SYM_KEY_TYPE)
STDERR.puts("negotiate_tlv_encryption 6\n")
if key_enc
STDERR.puts("negotiate_tlv_encryption 7\n")
sym_key = rsa_key.private_decrypt(key_enc, OpenSSL::PKey::RSA::PKCS1_PADDING)
else
STDERR.puts("negotiate_tlv_encryption 8\n")
sym_key = response.get_tlv_value(TLV_TYPE_SYM_KEY)
end
rescue OpenSSL::PKey::RSAError, Rex::Post::Meterpreter::RequestError

View File

@ -80,7 +80,6 @@ class Kiwi < Extension
elsif output =~ /^ERROR.*SamLookupNamesInDomain/m
result[:error] = 'Invalid user.'
else
STDERR.puts(output)
result[:error] = 'Unknown error.'
end
else

View File

@ -236,6 +236,11 @@ class Tlv
when TLV_TYPE_SYM_KEY; "SYM-KEY"
when TLV_TYPE_ENC_SYM_KEY; "ENC-SYM-KEY"
when TLV_TYPE_PIVOT_ID; "PIVOT-ID"
when TLV_TYPE_PIVOT_STAGE_DATA; "PIVOT-STAGE-DATA"
when TLV_TYPE_PIVOT_STAGE_DATA_SIZE; "PIVOT-STAGE-DATA-SIZE"
when TLV_TYPE_PIVOT_NAMED_PIPE_NAME; "PIVOT-NAMED-PIPE-NAME"
#when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface'
#when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address'
#when Extensions::Stdapi::TLV_TYPE_NETMASK; 'netmask'

View File

@ -161,7 +161,6 @@ module PacketDispatcher
if self.pivot_session
opts[:session_guid] = self.session_guid
opts[:tlv_enc_key] = self.tlv_enc_key
STDERR.puts("Pivot session, setting guid: #{self.session_guid.unpack('H*')[0]}...\n")
return self.pivot_session.send_packet(packet, opts)
end
@ -178,16 +177,10 @@ module PacketDispatcher
tlv_enc_key = opts[:tlv_enc_key]
end
STDERR.puts(" Current Session GUID: #{self.session_guid.unpack('H*')[0]}\n")
STDERR.puts("Provided Session GUID: #{session_guid.unpack('H*')[0]}\n")
STDERR.puts("Using tlv_enc_key: #{tlv_enc_key.inspect}\n")
bytes = 0
raw = packet.to_r(session_guid, tlv_enc_key)
err = nil
STDERR.puts("Outgoing packet is #{raw.length} bytes\n")
# Short-circuit send when using a passive dispatcher
if self.passive_service
send_queue.push(raw)
@ -249,45 +242,35 @@ module PacketDispatcher
# @param timeout [Integer,nil] number of seconds to wait, or nil to wait
# forever
def send_packet_wait_response(packet, timeout)
STDERR.puts("send_packet_wait_response entry\n")
# First, add the waiter association for the supplied packet
waiter = add_response_waiter(packet)
STDERR.puts("send_packet_wait_response 1\n")
bytes_written = send_packet(packet)
STDERR.puts("send_packet_wait_response 2\n")
# Transmit the packet
if (bytes_written.to_i <= 0)
STDERR.puts("send_packet_wait_response 3\n")
# Remove the waiter if we failed to send the packet.
remove_response_waiter(waiter)
return nil
end
STDERR.puts("send_packet_wait_response 4\n")
if not timeout
return nil
end
STDERR.puts("send_packet_wait_response 5 #{waiter.inspect}\n")
# Wait for the supplied time interval
response = waiter.wait(timeout)
STDERR.puts("send_packet_wait_response 6\n")
# Remove the waiter from the list of waiters in case it wasn't
# removed. This happens if the waiter timed out above.
remove_response_waiter(waiter)
STDERR.puts("send_packet_wait_response 7\n")
# wire in the UUID for this, as it should be part of every response
# packet
if response && !self.payload_uuid
STDERR.puts("send_packet_wait_response 8\n")
uuid = response.get_tlv_value(TLV_TYPE_UUID)
self.payload_uuid = Msf::Payload::UUID.new({:raw => uuid}) if uuid
end
STDERR.puts("send_packet_wait_response 9\n")
# Return the response packet, if any
return response
@ -493,11 +476,9 @@ module PacketDispatcher
#
def add_response_waiter(request, completion_routine = nil, completion_param = nil)
if self.pivot_session
STDERR.puts("Adding waiter in pivoted session: #{self.pivot_session}\n")
return self.pivot_session.add_response_waiter(request, completion_routine, completion_param)
end
STDERR.puts("Adding waiting in current session: #{self.inspect}\n")
waiter = PacketResponseWaiter.new(request.rid, completion_routine, completion_param)
self.waiters << waiter
@ -559,17 +540,12 @@ module PacketDispatcher
def dispatch_inbound_packet(packet)
handled = false
STDERR.puts("Inbound packet: #{packet.session_guid.unpack('H*')[0]}\n")
pivot = self.find_pivot(packet.session_guid)
STDERR.puts("Pivot is: #{pivot.inspect}\n")
tlv_enc_key = self.tlv_enc_key
STDERR.puts("Getting enc key\n")
tlv_enc_key = pivot.pivoted_session.tlv_enc_key if pivot
STDERR.puts("Got enc key #{tlv_enc_key.inspect}\n")
packet.from_r(tlv_enc_key)
STDERR.puts("Decrypted packet: #{packet.inspect}\n")
# Update our last reply time
self.last_checkin = Time.now
@ -577,7 +553,6 @@ module PacketDispatcher
# If the packet is a response, try to notify any potential
# waiters
STDERR.puts("Notifying response waiter for packet")
if packet.response? && notify_response_waiter(packet)
return true
end

View File

@ -12,9 +12,12 @@ class PivotListener
attr_accessor :session_class
def initialize(session_class)
attr_accessor :display_name
def initialize(session_class, display_name)
self.id = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
self.session_class = session_class
self.display_name = display_name
end
end
@ -25,11 +28,8 @@ class Pivot
#
attr_accessor :client
attr_accessor :pivot_session_guid
attr_accessor :pivoted_session
# Class modifications to support global pivot message
# dispatching without having to register a per-instance handler
class << self
@ -39,17 +39,35 @@ class Pivot
# to the appropriate class instance's DIO handler
def request_handler(client, packet)
if packet.method == 'core_pivot_session_new'
STDERR.puts("Received pivot packet! #{packet.inspect}\n")
session_guid = packet.get_tlv_value(TLV_TYPE_SESSION_GUID)
listener_id = packet.get_tlv_value(TLV_TYPE_PIVOT_ID)
Pivot.new(client, session_guid, listener_id)
client.add_pivot(Pivot.new(client, session_guid, listener_id))
elsif packet.method == 'core_pivot_session_died'
session_guid = packet.get_tlv_value(TLV_TYPE_SESSION_GUID)
pivot = client.find_pivot(session_guid)
if pivot
pivot.pivoted_session.kill('Died')
client.remove_pivot(session_guid)
end
end
true
end
end
def Pivot.get_listeners(client)
client.pivot_listeners
end
def Pivot.remove_listener(client, listener_id)
if client.find_pivot_listener(listener_id)
request = Packet.create_request('core_pivot_remove')
request.add_tlv(TLV_TYPE_PIVOT_ID, listener_id)
client.send_request(request)
client.remove_pivot_listener(listener_id)
end
end
def Pivot.create_named_pipe_listener(client, opts={})
STDERR.puts("Create listener: #{opts}\n")
request = Packet.create_request('core_pivot_add')
request.add_tlv(TLV_TYPE_PIVOT_NAMED_PIPE_NAME, opts[:pipe_name])
@ -63,25 +81,15 @@ class Pivot
when 'windows'
# Include the appropriate reflective dll injection module for the target process architecture...
if opts[:arch] == ARCH_X86
STDERR.puts("Including Meterp Loader x86\n")
c.include(::Msf::Payload::Windows::MeterpreterLoader)
elsif opts[:arch] == ARCH_X64
STDERR.puts("Including Meterp Loader x64\n")
c.include(::Msf::Payload::Windows::MeterpreterLoader_x64)
else
STDERR.puts("Not including a loader for #{opts[:arch]}\n")
STDERR.puts("Not including a loader for '#{opts[:arch]}'\n")
end
end
# TODO: should we be generating configuration inside Meterpreter like
# we do for migration, or just having a fixed one like we are now?
#uuid = Msf::Payload::UUID.new({
# arch: opts[:arch],
# platform: opts[:platform]
#})
stage_opts = {
#uuid: uuid,
arch: opts[:arch],
force_write_handle: true,
null_session_guid: true,
@ -100,11 +108,10 @@ class Pivot
stager = c.new()
stage_opts[:transport_config] = [stager.transport_config_reverse_named_pipe(stage_opts)]
#STDERR.puts("Stager: #{stager.inspect}\n")
stage = stager.stage_payload(stage_opts)
#STDERR.puts("Stage: #{stage.inspect}\n")
pivot_listener = PivotListener.new(::Msf::Sessions::Meterpreter_x86_Win)
display_name = "pipe://#{opts[:pipe_host]}/#{opts[:pipe_name]} (#{opts[:arch]}/#{opts[:platform]})"
pivot_listener = PivotListener.new(::Msf::Sessions::Meterpreter_x86_Win, display_name)
request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA, stage)
request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA_SIZE, stage.length)
@ -113,11 +120,12 @@ class Pivot
client.send_request(request)
client.add_pivot_listener(pivot_listener)
pivot_listener
end
def initialize(client, session_guid, listener_id)
self.client = client
self.pivot_session_guid = session_guid
opts = {
pivot_session: client,
@ -127,17 +135,9 @@ class Pivot
listener = client.find_pivot_listener(listener_id)
self.pivoted_session = listener.session_class.new(nil, opts)
STDERR.puts("pivoted session instance created: #{self.pivoted_session.inspect}\n")
self.client.add_pivot(self)
STDERR.puts("Setting the framework instance\n")
self.pivoted_session.framework = self.client.framework
STDERR.puts("Invoking the on_session method\n")
self.pivoted_session.bootstrap({'AutoVerifySessionTimeout' => 30})
STDERR.puts("Registering the session with the framework\n")
self.client.framework.sessions.register(self.pivoted_session)
STDERR.puts("done!\n")
end
protected

View File

@ -25,7 +25,7 @@ module PivotContainer
# session guid.
#
def add_pivot(pivot)
self.pivots[pivot.pivot_session_guid] = pivot
self.pivots[pivot.pivoted_session.session_guid] = pivot
end
def add_pivot_listener(listener)
@ -50,6 +50,10 @@ module PivotContainer
return self.pivots.delete(pivot_session_guid)
end
def remove_pivot_listener(listener_id)
return self.pivot_listeners.delete(listener_id)
end
#
# The hash of pivots.
#

View File

@ -903,7 +903,6 @@ class Console::CommandDispatcher::Stdapi::Sys
)
privs = client.sys.config.getprivs
STDERR.puts(privs.inspect+"\n")
client.sys.config.getprivs.each do |priv|
table << [priv[:priv], priv[:enabled].to_s]
end

View File

@ -70,7 +70,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '1.3.1'
spec.add_runtime_dependency 'metasploit-payloads', '1.3.3'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.2.2'
# Needed by msfgui and other rpc components