lib/rex/post/meterpreter/packet_dispatcher.rb in librex-0.0.38 vs lib/rex/post/meterpreter/packet_dispatcher.rb in librex-0.0.39
- old
+ new
@@ -27,13 +27,13 @@
# The method that failed.
attr_reader :method
# The error result that occurred, typically a windows error message.
attr_reader :result
-
+
# The error result that occurred, typically a windows error code.
- attr_reader :code
+ attr_reader :code
end
###
#
# Handles packet transmission, reception, and correlation,
@@ -44,10 +44,88 @@
PacketTimeout = 600
##
#
+ # Synchronization
+ #
+ ##
+ attr_accessor :comm_mutex
+
+
+ ##
+ #
+ #
+ # Passive Dispatching
+ #
+ ##
+ attr_accessor :passive_service, :send_queue, :recv_queue
+
+ def initialize_passive_dispatcher
+ self.send_queue = []
+ self.recv_queue = []
+ self.waiters = []
+ self.alive = true
+
+ self.passive_service = self.passive_dispatcher
+ self.passive_service.remove_resource("/" + self.conn_id + "/")
+ self.passive_service.add_resource("/" + self.conn_id + "/",
+ 'Proc' => Proc.new { |cli, req| on_passive_request(cli, req) },
+ 'VirtualDirectory' => true
+ )
+ end
+
+ def shutdown_passive_dispatcher
+ return if not self.passive_service
+ self.passive_service.remove_resource("/" + self.conn_id + "/")
+
+ self.alive = false
+ self.send_queue = []
+ self.recv_queue = []
+ self.waiters = []
+
+ self.passive_service = nil
+ end
+
+ def on_passive_request(cli, req)
+
+ begin
+
+ resp = Rex::Proto::Http::Response.new(200, "OK")
+ resp['Content-Type'] = 'application/octet-stream'
+ resp['Connection'] = 'close'
+
+ # If the first 4 bytes are "RECV", return the oldest packet from the outbound queue
+ if req.body[0,4] == "RECV"
+ rpkt = send_queue.pop
+ resp.body = rpkt || ''
+ begin
+ cli.send_response(resp)
+ rescue ::Exception => e
+ send_queue.unshift(rpkt) if rpkt
+ elog("Exception sending a reply to the reader request: #{cli.inspect} #{e.class} #{e} #{e.backtrace}")
+ end
+ else
+ resp.body = ""
+ if req.body and req.body.length > 0
+ packet = Packet.new(0)
+ packet.from_r(req.body)
+ dispatch_inbound_packet(packet)
+ end
+ cli.send_response(resp)
+ end
+
+ # Force a closure for older WinInet implementations
+ self.passive_service.close_client( cli )
+
+ rescue ::Exception => e
+ elog("Exception handling request: #{cli.inspect} #{req.inspect} #{e.class} #{e} #{e.backtrace}")
+ end
+ end
+
+ ##
+ #
# Transmission
#
##
#
@@ -60,43 +138,54 @@
bytes = 0
raw = packet.to_r
err = nil
+ # Short-circuit send when using a passive dispatcher
+ if self.passive_service
+ send_queue.push(raw)
+ return raw.size # Lie!
+ end
+
if (raw)
-
- begin
- bytes = self.sock.write(raw)
- rescue ::Exception => e
- err = e
+
+ # This mutex is used to lock out new commands during an
+ # active migration.
+
+ self.comm_mutex.synchronize do
+ begin
+ bytes = self.sock.write(raw)
+ rescue ::Exception => e
+ err = e
+ end
end
-
+
if bytes.to_i == 0
# Mark the session itself as dead
self.alive = false
-
+
# Indicate that the dispatcher should shut down too
@finish = true
-
+
# Reraise the error to the top-level caller
- raise err if err
+ raise err if err
end
end
return bytes
end
#
# Sends a packet and waits for a timeout for the given time interval.
#
def send_request(packet, t = self.response_timeout)
-
+
if not t
send_packet(packet)
return nil
end
-
+
response = send_packet_wait_response(packet, t)
if (response == nil)
raise TimeoutError.new("Send timed out")
elsif (response.result != 0)
@@ -144,10 +233,16 @@
#
# Monitors the PacketDispatcher's sock for data in its own
# thread context and parsers all inbound packets.
#
def monitor_socket
+
+ # Skip if we are using a passive dispatcher
+ return if self.passive_service
+
+ self.comm_mutex = ::Mutex.new
+
self.waiters = []
@pqueue = []
@finish = false
@last_recvd = Time.now
@@ -301,10 +396,11 @@
def monitor_stop
if(self.receiver_thread)
self.receiver_thread.kill
self.receiver_thread = nil
end
+
if(self.dispatcher_thread)
self.dispatcher_thread.kill
self.dispatcher_thread = nil
end
end
@@ -382,10 +478,9 @@
if ((resp = packet.response?))
if (notify_response_waiter(packet))
return true
end
end
-
# Enumerate all of the inbound packet handlers until one handles
# the packet
@inbound_handlers.each { |handler|