Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/msf/core/handler.rb
Views: 11780
# -*- coding: binary -*-12module Msf34###5#6# This module acts as a base for all handler pseudo-modules. They aren't7# really modules, so don't get the wrong idea champs! They're merely8# mixed into dynamically generated payloads to handle monitoring for9# a connection. Handlers are layered in between the base payload10# class and any other payload class. A super cool ASCII diagram would11# look something like this12#13# Module14# ^15# |16# Payload17# ^18# |19# Handler20# ^21# |22# Stager23# ^24# |25# Stage26#27###28module Handler2930##31#32# Constants used with the ``handler'' method to indicate whether or not the33# connection was used.34#35##3637#38# Returned by handlers to indicate that a socket has been claimed for use39# by the payload.40#41Claimed = "claimed"42#43# Returned by handlers to indicate that a socket has not been claimed for44# use.45#46Unused = "unused"4748#49# Returns the handler type.50#51def self.handler_type52return "none"53end5455#56# Returns the transport-independent handler type.57#58def self.general_handler_type59"none"60end6162#63# Returns the handler's name, if any.64#65def handler_name66module_info['HandlerName']67end6869#70# Initializes the session waiter event and other fun stuff.71#72def initialize(info = {})73super7475# Initialize the pending_connections counter to 076self.pending_connections = 07778# Initialize the sessions counter to 079self.sessions = 08081# Create the waiter event with auto_reset set to false so that82# if a session is ever created, waiting on it returns immediately.83self.session_waiter_event = Rex::Sync::Event.new(false, false)84end8586#87# Sets up the connection handler.88#89def setup_handler90end9192#93# Terminates the connection handler.94#95def cleanup_handler96end9798#99# Start monitoring for a connection.100#101def start_handler102end103104#105# Start another connection monitor106#107def add_handler(opts={})108end109110#111# Stop monitoring for a connection.112#113def stop_handler114end115116#117# Checks to see if a payload connection has been established on118# the supplied connection. This is necessary for find-sock style119# payloads.120#121def handler(sock)122end123124#125# Handles an established connection supplied in the in and out126# handles. The handles are passed as parameters in case this127# handler is capable of handling multiple simultaneous128# connections. The default behavior is to attempt to create a session for129# the payload. This path will not be taken for multi-staged payloads.130#131def handle_connection(conn, opts={})132create_session(conn, opts)133end134135#136# The amount of time to wait for a session to come in.137#138def wfs_delay1392140end141142#143# Waits for a session to be created as the result of a handler connection144# coming in. The return value is a session object instance on success or145# nil if the timeout expires.146#147def wait_for_session(t = wfs_delay)148session = nil149150begin151session = session_waiter_event.wait(t)152rescue ::Timeout::Error153end154155# If a connection has arrived, wait longer...156if (pending_connections > 0)157session = session_waiter_event.wait158end159160return session161end162163#164# Interrupts a wait_for_session call by notifying with a nil event165#166def interrupt_wait_for_session167return unless session_waiter_event168session_waiter_event.notify(nil)169end170171#172# Set by the exploit module to configure handler173#174attr_accessor :exploit_config175176#177# This will be non-nil if the handler has a parent payload that it178# was spawned from. Right now, this is only the case with generic179# payloads. The parent payload is used to create a session180# rather than using the instance itself.181#182attr_accessor :parent_payload183184protected185186#187# Creates a session, if necessary, for the connection that's been handled.188# Sessions are only created if the payload that's been mixed in has an189# associated session.190#191def create_session(conn, opts={})192# If there is a parent payload, then use that in preference.193return parent_payload.create_session(conn, opts) if (parent_payload)194195# If the payload we merged in with has an associated session factory,196# allocate a new session.197if (self.session)198begin199# if there's a create_session method then use it, as this200# can form a factory for arb session types based on the201# payload.202if self.session.respond_to?('create_session')203s = self.session.create_session(conn, opts)204else205s = self.session.new(conn, opts)206end207rescue ::Exception => e208# We just wanna show and log the error, not trying to swallow it.209print_error("#{e.class} #{e.message}")210elog('Could not allocate a new Session.', error: e)211raise e212end213214# Pass along the framework context215s.framework = framework216217# Associate this system with the original exploit218# and any relevant information219s.set_from_exploit(assoc_exploit)220221# set injected workspace value if db is active222if framework.db.active && wspace = framework.db.find_workspace(s.workspace)223framework.db.workspace = wspace224end225226# Pass along any associated payload uuid if specified227if opts[:payload_uuid]228s.payload_uuid = opts[:payload_uuid]229s.payload_uuid.registered = false230if framework.db.active231payload_info = { uuid: s.payload_uuid.puid_hex, workspace: framework.db.workspace }232uuid_info = framework.db.payloads(payload_info).first233else234print_warning('Without a database connected that payload UUID tracking will not work!')235end236if s.payload_uuid.respond_to?(:puid_hex) && uuid_info237s.payload_uuid.registered = true238s.payload_uuid.name = uuid_info['name']239s.payload_uuid.timestamp = uuid_info['timestamp']240else241s.payload_uuid.registered = false242end243end244245# If the session is valid, register it with the framework and246# notify any waiters we may have.247if (s)248# Defer the session registration to the Session Manager scheduler249registration = Proc.new do250register_session(s)251end252framework.sessions.schedule registration253end254255return s256end257nil258end259260#261# Registers a session with the framework and notifies any waiters of the262# new session.263#264def register_session(session)265# Register the session with the framework266framework.sessions.register(session)267268# Call the handler's on_session() method269if session.respond_to?(:bootstrap)270session.bootstrap(datastore, self)271272return unless session.alive273end274275# Process the auto-run scripts for this session276if session.respond_to?(:process_autoruns)277session.process_autoruns(datastore)278end279280# Tell the handler that we have a session281on_session(session)282283# Notify the framework that we have a new session opening up...284# Don't let errant event handlers kill our session285begin286framework.events.on_session_open(session)287rescue ::Exception => e288wlog("Exception in on_session_open event handler: #{e.class}: #{e}")289wlog("Call Stack\n#{e.backtrace.join("\n")}")290end291292# If there is an exploit associated with this payload, then let's notify293# anyone who is interested that this exploit succeeded294if assoc_exploit295framework.events.on_exploit_success(assoc_exploit, session)296end297298# Notify waiters that they should be ready to rock299session_waiter_event.notify(session)300301# Decrement the pending connections counter now that we've processed302# one session.303self.pending_connections -= 1304305# Count the number of sessions we have registered306self.sessions += 1307end308309attr_accessor :session_waiter_event # :nodoc:310attr_accessor :pending_connections # :nodoc:311attr_accessor :sessions # :nodoc:312313end314315end316317318