Files
metasploit-gs/lib/msf/core/handler.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

317 lines
7.9 KiB
Ruby
Raw Normal View History

# -*- coding: binary -*-
2005-07-11 02:03:48 +00:00
module Msf
###
#
# This module acts as a base for all handler pseudo-modules. They aren't
# really modules, so don't get the wrong idea champs! They're merely
# mixed into dynamically generated payloads to handle monitoring for
# a connection. Handlers are layered in between the base payload
# class and any other payload class. A super cool ASCII diagram would
# look something like this
#
# Module
# ^
# |
# Payload
# ^
# |
# Handler
# ^
# |
# Stager
# ^
# |
# Stage
#
###
module Handler
2005-11-15 15:11:43 +00:00
##
2005-07-15 23:46:05 +00:00
#
# Constants used with the ``handler'' method to indicate whether or not the
2005-11-15 15:11:43 +00:00
# connection was used.
#
##
2013-08-30 16:28:33 -05:00
2005-11-15 15:11:43 +00:00
#
# Returned by handlers to indicate that a socket has been claimed for use
# by the payload.
2005-07-15 23:46:05 +00:00
#
Claimed = "claimed"
2005-11-15 15:11:43 +00:00
#
# Returned by handlers to indicate that a socket has not been claimed for
# use.
#
2005-07-15 23:46:05 +00:00
Unused = "unused"
2013-08-30 16:28:33 -05:00
2005-07-11 04:07:52 +00:00
#
2005-11-15 15:11:43 +00:00
# Returns the handler type.
2005-07-11 04:07:52 +00:00
#
def self.handler_type
return "none"
end
2013-08-30 16:28:33 -05:00
#
# Returns the transport-independent handler type.
#
def self.general_handler_type
"none"
end
2013-08-30 16:28:33 -05:00
#
# Returns the handler's name, if any.
#
def handler_name
module_info['HandlerName']
end
2013-08-30 16:28:33 -05:00
#
# Initializes the session waiter event and other fun stuff.
#
def initialize(info = {})
super
2013-08-30 16:28:33 -05:00
# Initialize the pending_connections counter to 0
self.pending_connections = 0
2013-08-30 16:28:33 -05:00
# Initialize the sessions counter to 0
self.sessions = 0
# Create the waiter event with auto_reset set to false so that
# if a session is ever created, waiting on it returns immediately.
self.session_waiter_event = Rex::Sync::Event.new(false, false)
end
2013-08-30 16:28:33 -05:00
2005-07-11 02:03:48 +00:00
#
2005-11-15 15:11:43 +00:00
# Sets up the connection handler.
2005-07-11 02:03:48 +00:00
#
def setup_handler
end
2013-08-30 16:28:33 -05:00
2005-07-11 02:03:48 +00:00
#
2005-11-15 15:11:43 +00:00
# Terminates the connection handler.
2005-07-11 02:03:48 +00:00
#
def cleanup_handler
end
2013-08-30 16:28:33 -05:00
2005-07-11 02:03:48 +00:00
#
2005-11-15 15:11:43 +00:00
# Start monitoring for a connection.
2005-07-11 02:03:48 +00:00
#
def start_handler
end
2013-08-30 16:28:33 -05:00
#
# Start another connection monitor
#
def add_handler(opts={})
end
2013-08-30 16:28:33 -05:00
2005-07-11 02:03:48 +00:00
#
2005-11-15 15:11:43 +00:00
# Stop monitoring for a connection.
2005-07-11 02:03:48 +00:00
#
def stop_handler
end
2013-08-30 16:28:33 -05:00
2005-07-15 23:46:05 +00:00
#
# Checks to see if a payload connection has been established on
# the supplied connection. This is necessary for find-sock style
2005-07-15 23:46:05 +00:00
# payloads.
#
def handler(sock)
end
2013-08-30 16:28:33 -05:00
2005-07-11 02:03:48 +00:00
#
# Handles an established connection supplied in the in and out
2005-07-11 02:03:48 +00:00
# handles. The handles are passed as parameters in case this
# handler is capable of handling multiple simultaneous
2005-07-18 05:13:21 +00:00
# connections. The default behavior is to attempt to create a session for
2009-11-09 00:11:47 +00:00
# the payload. This path will not be taken for multi-staged payloads.
#
2010-04-03 05:21:15 +00:00
def handle_connection(conn, opts={})
create_session(conn, opts)
end
2013-08-30 16:28:33 -05:00
2005-07-11 02:03:48 +00:00
#
# The amount of time to wait for a session to come in.
#
def wfs_delay
2005-07-17 07:43:24 +00:00
2
2005-07-11 02:03:48 +00:00
end
2013-08-30 16:28:33 -05:00
2005-07-11 02:03:48 +00:00
#
# Waits for a session to be created as the result of a handler connection
# coming in. The return value is a session object instance on success or
2005-11-15 15:11:43 +00:00
# nil if the timeout expires.
2005-07-11 02:03:48 +00:00
#
def wait_for_session(t = wfs_delay)
session = nil
2013-08-30 16:28:33 -05:00
begin
session = session_waiter_event.wait(t)
rescue ::Timeout::Error
end
2013-08-30 16:28:33 -05:00
# If a connection has arrived, wait longer...
if (pending_connections > 0)
2005-11-11 01:27:57 +00:00
session = session_waiter_event.wait
end
2013-08-30 16:28:33 -05:00
return session
2005-07-11 02:03:48 +00:00
end
2013-08-30 16:28:33 -05:00
2016-04-01 14:43:16 -05:00
#
# Interrupts a wait_for_session call by notifying with a nil event
#
def interrupt_wait_for_session
return unless session_waiter_event
session_waiter_event.notify(nil)
end
2006-07-29 22:37:39 +00:00
#
# Set by the exploit module to configure handler
#
attr_accessor :exploit_config
2013-08-30 16:28:33 -05:00
2006-08-26 02:13:25 +00:00
#
# This will be non-nil if the handler has a parent payload that it
# was spawned from. Right now, this is only the case with generic
# payloads. The parent payload is used to create a session
# rather than using the instance itself.
#
attr_accessor :parent_payload
2005-07-11 02:03:48 +00:00
protected
2005-07-18 05:13:21 +00:00
#
# Creates a session, if necessary, for the connection that's been handled.
# Sessions are only created if the payload that's been mixed in has an
# associated session.
#
2010-04-03 05:21:15 +00:00
def create_session(conn, opts={})
2006-08-26 02:13:25 +00:00
# If there is a parent payload, then use that in preference.
2010-04-03 05:21:15 +00:00
return parent_payload.create_session(conn, opts) if (parent_payload)
2013-08-30 16:28:33 -05:00
# If the payload we merged in with has an associated session factory,
2005-07-18 05:13:21 +00:00
# allocate a new session.
if (self.session)
2015-11-16 17:17:20 -06:00
begin
# if there's a create_session method then use it, as this
# can form a factory for arb session types based on the
# payload.
if self.session.respond_to?('create_session')
s = self.session.create_session(conn, opts)
else
s = self.session.new(conn, opts)
end
2015-11-16 17:17:20 -06:00
rescue ::Exception => e
# We just wanna show and log the error, not trying to swallow it.
print_error("#{e.class} #{e.message}")
elog('Could not allocate a new Session.', error: e)
2015-11-16 17:17:20 -06:00
raise e
end
2013-08-30 16:28:33 -05:00
2005-07-18 05:13:21 +00:00
# Pass along the framework context
s.framework = framework
2013-08-30 16:28:33 -05:00
# Associate this system with the original exploit
# and any relevant information
s.set_from_exploit(assoc_exploit)
2013-08-30 16:28:33 -05:00
2019-12-02 16:13:05 -06:00
# set injected workspace value if db is active
2019-11-26 16:42:43 -06:00
if framework.db.active && wspace = framework.db.find_workspace(s.workspace)
framework.db.workspace = wspace
end
# Pass along any associated payload uuid if specified
if opts[:payload_uuid]
s.payload_uuid = opts[:payload_uuid]
s.payload_uuid.registered = false
if framework.db.active
2020-11-25 20:07:00 +08:00
payload_info = { uuid: s.payload_uuid.puid_hex, workspace: framework.db.workspace }
uuid_info = framework.db.payloads(payload_info).first
2020-12-04 11:26:01 +08:00
else
print_warning('Without a database connected that payload UUID tracking will not work!')
2020-11-25 20:07:00 +08:00
end
if s.payload_uuid.respond_to?(:puid_hex) && uuid_info
s.payload_uuid.registered = true
s.payload_uuid.name = uuid_info['name']
s.payload_uuid.timestamp = uuid_info['timestamp']
else
s.payload_uuid.registered = false
end
end
2005-07-18 05:13:21 +00:00
# If the session is valid, register it with the framework and
# notify any waiters we may have.
if (s)
# Defer the session registration to the Session Manager scheduler
registration = Proc.new do
register_session(s)
end
framework.sessions.schedule registration
end
2013-08-30 16:28:33 -05:00
2005-12-30 06:49:25 +00:00
return s
2005-07-18 05:13:21 +00:00
end
nil
2005-07-18 05:13:21 +00:00
end
2013-08-30 16:28:33 -05:00
#
# Registers a session with the framework and notifies any waiters of the
# new session.
#
def register_session(session)
2005-07-16 08:12:58 +00:00
# Register the session with the framework
framework.sessions.register(session)
2013-08-30 16:28:33 -05:00
# Call the handler's on_session() method
if session.respond_to?(:bootstrap)
session.bootstrap(datastore, self)
return unless session.alive
end
# Process the auto-run scripts for this session
if session.respond_to?(:process_autoruns)
session.process_autoruns(datastore)
end
2013-08-30 16:28:33 -05:00
# Tell the handler that we have a session
on_session(session)
2021-04-14 18:04:11 -04:00
# Notify the framework that we have a new session opening up...
# Don't let errant event handlers kill our session
begin
framework.events.on_session_open(session)
rescue ::Exception => e
wlog("Exception in on_session_open event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
# If there is an exploit associated with this payload, then let's notify
# anyone who is interested that this exploit succeeded
if assoc_exploit
2007-02-26 03:11:51 +00:00
framework.events.on_exploit_success(assoc_exploit, session)
end
2013-08-30 16:28:33 -05:00
2005-07-16 08:12:58 +00:00
# Notify waiters that they should be ready to rock
session_waiter_event.notify(session)
2013-08-30 16:28:33 -05:00
# Decrement the pending connections counter now that we've processed
# one session.
self.pending_connections -= 1
# Count the number of sessions we have registered
self.sessions += 1
end
2013-08-30 16:28:33 -05:00
2005-10-19 03:37:22 +00:00
attr_accessor :session_waiter_event # :nodoc:
attr_accessor :pending_connections # :nodoc:
attr_accessor :sessions # :nodoc:
2005-07-11 02:03:48 +00:00
end
end