Recon modules and the recon event subsystem have been temporarily removed.
The 'auxiliary' system is designed to replace it and recon features will slowly be moved back into the framework git-svn-id: file:///home/svn/incoming/trunk@3438 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
55ba865f30
commit
bdfd2c5152
|
@ -31,7 +31,6 @@ class Flatfile < PersistentStorage
|
||||||
|
|
||||||
begin
|
begin
|
||||||
store_general(framework)
|
store_general(framework)
|
||||||
store_recon(framework)
|
|
||||||
ensure
|
ensure
|
||||||
self.fd.close
|
self.fd.close
|
||||||
end
|
end
|
||||||
|
@ -53,47 +52,6 @@ protected
|
||||||
"Generated: #{Time.now}\n\n")
|
"Generated: #{Time.now}\n\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# This method stores the recon information that has been collected by this
|
|
||||||
# framework instance.
|
|
||||||
#
|
|
||||||
def store_recon(framework)
|
|
||||||
fd.print(
|
|
||||||
"Reconnaissance Information\n" +
|
|
||||||
"==========================\n\n")
|
|
||||||
|
|
||||||
framework.reconmgr.each_host { |address, host|
|
|
||||||
store_recon_host(framework, host)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method stores information about a specific host and its services.
|
|
||||||
#
|
|
||||||
def store_recon_host(framework, host)
|
|
||||||
fd.print(
|
|
||||||
"Host: #{host.address}\n")
|
|
||||||
|
|
||||||
store_recon_host_services(framework, host)
|
|
||||||
|
|
||||||
fd.print("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method stores information about the services running on a host, if
|
|
||||||
# any.
|
|
||||||
#
|
|
||||||
def store_recon_host_services(framework, host)
|
|
||||||
host.services.entities.each { |name, proto|
|
|
||||||
if (proto.kind_of?(Msf::Recon::Entity::Group) == true)
|
|
||||||
proto.entities.each { |name, serv|
|
|
||||||
fd.print(
|
|
||||||
"\tService: #{serv.port} (#{serv.proto})\n")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
Msf::PersistentStorage.add_storage_class('flatfile', self)
|
Msf::PersistentStorage.add_storage_class('flatfile', self)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,8 +27,8 @@ class ReadableText
|
||||||
return dump_basic_module(mod, indent)
|
return dump_basic_module(mod, indent)
|
||||||
when MODULE_EXPLOIT
|
when MODULE_EXPLOIT
|
||||||
return dump_exploit_module(mod, indent)
|
return dump_exploit_module(mod, indent)
|
||||||
when MODULE_RECON
|
when MODULE_AUX
|
||||||
return dump_recon_module(mod, indent)
|
return dump_auxiliary_module(mod, indent)
|
||||||
else
|
else
|
||||||
return dump_generic_module(mod, indent)
|
return dump_generic_module(mod, indent)
|
||||||
end
|
end
|
||||||
|
@ -150,9 +150,9 @@ class ReadableText
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Dumps information about a recon module.
|
# Dumps information about an auxiliary module.
|
||||||
#
|
#
|
||||||
def self.dump_recon_module(mod, indent = '')
|
def self.dump_auxiliary_module(mod, indent = '')
|
||||||
output = "\n"
|
output = "\n"
|
||||||
output += " Name: #{mod.name}\n"
|
output += " Name: #{mod.name}\n"
|
||||||
output += " Version: #{mod.version}\n"
|
output += " Version: #{mod.version}\n"
|
||||||
|
|
|
@ -8,7 +8,7 @@ require 'msf/base/simple/encoder'
|
||||||
require 'msf/base/simple/exploit'
|
require 'msf/base/simple/exploit'
|
||||||
require 'msf/base/simple/nop'
|
require 'msf/base/simple/nop'
|
||||||
require 'msf/base/simple/payload'
|
require 'msf/base/simple/payload'
|
||||||
require 'msf/base/simple/recon'
|
require 'msf/base/simple/auxiliary'
|
||||||
|
|
||||||
# Simplified framework interface
|
# Simplified framework interface
|
||||||
require 'msf/base/simple/framework'
|
require 'msf/base/simple/framework'
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
module Msf
|
||||||
|
module Simple
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# A simplified recon wrapper.
|
||||||
|
#
|
||||||
|
###
|
||||||
|
module Auxiliary
|
||||||
|
|
||||||
|
include Module
|
||||||
|
|
||||||
|
#
|
||||||
|
# Wraps the execution process in a simple wrapper.
|
||||||
|
#
|
||||||
|
def self.run_simple(mod, opts = {})
|
||||||
|
# Initialize user interaction
|
||||||
|
mod.init_ui(
|
||||||
|
opts['LocalInput'],
|
||||||
|
opts['LocalOutput'])
|
||||||
|
|
||||||
|
mod.run()
|
||||||
|
|
||||||
|
# Reset the user interface
|
||||||
|
mod.reset_ui
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Calls the class method.
|
||||||
|
#
|
||||||
|
def run_simple(opts = {})
|
||||||
|
Msf::Simple::Auxiliary.run_simple(self, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -44,7 +44,7 @@ module Framework
|
||||||
MODULE_EXPLOIT => Msf::Simple::Exploit,
|
MODULE_EXPLOIT => Msf::Simple::Exploit,
|
||||||
MODULE_NOP => Msf::Simple::Nop,
|
MODULE_NOP => Msf::Simple::Nop,
|
||||||
MODULE_PAYLOAD => Msf::Simple::Payload,
|
MODULE_PAYLOAD => Msf::Simple::Payload,
|
||||||
MODULE_RECON => Msf::Simple::Recon,
|
MODULE_AUX => Msf::Simple::Auxiliary,
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
module Msf
|
|
||||||
module Simple
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# A simplified recon wrapper.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
module Recon
|
|
||||||
|
|
||||||
include Module
|
|
||||||
|
|
||||||
#
|
|
||||||
# Wraps the discovery process in a simple wrapper.
|
|
||||||
#
|
|
||||||
def self.discover_simple(recon, opts = {})
|
|
||||||
# Initialize user interaction
|
|
||||||
recon.init_ui(
|
|
||||||
opts['LocalInput'],
|
|
||||||
opts['LocalOutput'])
|
|
||||||
|
|
||||||
# Start the discovery process
|
|
||||||
recon.start_discovery
|
|
||||||
|
|
||||||
# Wait for the discovery to complete
|
|
||||||
recon.wait_for_completion
|
|
||||||
|
|
||||||
# Reset the user interface
|
|
||||||
recon.reset_ui
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Calls the class method.
|
|
||||||
#
|
|
||||||
def discover_simple(opts = {})
|
|
||||||
Msf::Simple::Recon.discover_simple(self, opts)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -46,10 +46,10 @@ class Statistics
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns the number of recon modules in the framework.
|
# Returns the number of auxiliary modules in the framework.
|
||||||
#
|
#
|
||||||
def num_recon
|
def num_auxiliary
|
||||||
self.framework.recon.length
|
self.framework.auxiliary.length
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#
|
#
|
||||||
# The core library provides all of the means by which to interact
|
# The core library provides all of the means by which to interact
|
||||||
# with the framework insofar as maniuplating encoders, nops,
|
# with the framework insofar as maniuplating encoders, nops,
|
||||||
# payloads, exploits, recon, and sessions.
|
# payloads, exploits, auxiliary, and sessions.
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ require 'msf/core/encoder'
|
||||||
require 'msf/core/exploit'
|
require 'msf/core/exploit'
|
||||||
require 'msf/core/nop'
|
require 'msf/core/nop'
|
||||||
require 'msf/core/payload'
|
require 'msf/core/payload'
|
||||||
require 'msf/core/recon'
|
require 'msf/core/auxiliary'
|
||||||
|
|
||||||
# Drivers
|
# Drivers
|
||||||
require 'msf/core/exploit_driver'
|
require 'msf/core/exploit_driver'
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
require 'msf/core/module'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# The auxiliary class acts as a base class for all modules that perform
|
||||||
|
# reconnaisance, retrieve data, brute force logins, or any other action
|
||||||
|
# that doesn't fit our concept of an 'exploit' (involving payloads and
|
||||||
|
# targets and whatnot).
|
||||||
|
#
|
||||||
|
###
|
||||||
|
|
||||||
|
class Auxiliary < Msf::Module
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns MODULE_AUX to indicate that this is an auxiliary module.
|
||||||
|
#
|
||||||
|
def self.type
|
||||||
|
MODULE_AUX
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns MODULE_AUX to indicate that this is an auxiliary module.
|
||||||
|
#
|
||||||
|
def type
|
||||||
|
MODULE_AUX
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Creates an instance of the exploit module. Mad skillz.
|
||||||
|
#
|
||||||
|
def initialize(info = {})
|
||||||
|
|
||||||
|
# Call the parent constructor after making any necessary modifications
|
||||||
|
# to the information hash.
|
||||||
|
super(info)
|
||||||
|
|
||||||
|
self.actions = Rex::Transformer.transform(
|
||||||
|
info['Actions'], Array,
|
||||||
|
[ AuxiliaryAction ], 'AuxiliaryAction'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.default_action = info['DefaultAction']
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
print_status("Running the default Auxiliary handler")
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Allow access to the hash table of actions and the string containing
|
||||||
|
# the default action
|
||||||
|
#
|
||||||
|
attr_reader :actions, :default_action
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_writer :actions, :default_action
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -14,7 +14,7 @@ MODULE_ANY = '_any_'
|
||||||
MODULE_ENCODER = 'encoder'
|
MODULE_ENCODER = 'encoder'
|
||||||
MODULE_EXPLOIT = 'exploit'
|
MODULE_EXPLOIT = 'exploit'
|
||||||
MODULE_NOP = 'nop'
|
MODULE_NOP = 'nop'
|
||||||
MODULE_RECON = 'recon'
|
MODULE_AUX = 'aux'
|
||||||
MODULE_PAYLOAD = 'payload'
|
MODULE_PAYLOAD = 'payload'
|
||||||
MODULE_TYPES =
|
MODULE_TYPES =
|
||||||
[
|
[
|
||||||
|
@ -22,7 +22,7 @@ MODULE_TYPES =
|
||||||
MODULE_PAYLOAD,
|
MODULE_PAYLOAD,
|
||||||
MODULE_EXPLOIT,
|
MODULE_EXPLOIT,
|
||||||
MODULE_NOP,
|
MODULE_NOP,
|
||||||
MODULE_RECON
|
MODULE_AUX
|
||||||
]
|
]
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -23,7 +23,7 @@ end
|
||||||
#
|
#
|
||||||
# This class manages subscriber registration and is the entry point
|
# This class manages subscriber registration and is the entry point
|
||||||
# for dispatching various events that occur for modules, such as
|
# for dispatching various events that occur for modules, such as
|
||||||
# recon discovery and exploit success or failure. The framework
|
# exploit results and auxiliary module data. The framework
|
||||||
# and external modules can register themselves as subscribers to
|
# and external modules can register themselves as subscribers to
|
||||||
# various events such that they can perform custom actions when
|
# various events such that they can perform custom actions when
|
||||||
# a specific event or events occur.
|
# a specific event or events occur.
|
||||||
|
@ -35,7 +35,6 @@ class EventDispatcher
|
||||||
self.general_event_subscribers = []
|
self.general_event_subscribers = []
|
||||||
self.exploit_event_subscribers = []
|
self.exploit_event_subscribers = []
|
||||||
self.session_event_subscribers = []
|
self.session_event_subscribers = []
|
||||||
self.recon_event_subscribers = []
|
|
||||||
self.subscribers_rwlock = Rex::ReadWriteLock.new
|
self.subscribers_rwlock = Rex::ReadWriteLock.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -60,23 +59,6 @@ class EventDispatcher
|
||||||
remove_event_subscriber(general_event_subscribers, subscriber)
|
remove_event_subscriber(general_event_subscribers, subscriber)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# This method adds a recon event subscriber. Recon event subscribers
|
|
||||||
# receive notifications when events occur that pertain to recon modules.
|
|
||||||
# The subscriber provided must implement the ReconEvents module methods in
|
|
||||||
# some form.
|
|
||||||
#
|
|
||||||
def add_recon_subscriber(subscriber)
|
|
||||||
add_event_subscriber(recon_event_subscribers, subscriber)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Removes a recon event subscriber.
|
|
||||||
#
|
|
||||||
def remove_recon_subscriber(subscriber)
|
|
||||||
remove_event_subscriber(recon_event_subscribers, subscriber)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# This method adds an exploit event subscriber. Exploit event subscribers
|
# This method adds an exploit event subscriber. Exploit event subscribers
|
||||||
# receive notifications when events occur that pertain to exploits, such as
|
# receive notifications when events occur that pertain to exploits, such as
|
||||||
|
@ -145,46 +127,6 @@ class EventDispatcher
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Recon events
|
|
||||||
#
|
|
||||||
##
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine is called whenever a host's state changes, such as when it's
|
|
||||||
# added, updated, or removed. This event is dispatched by the Recon
|
|
||||||
# Manager once it makes a determination on the accurate state of a host as
|
|
||||||
# provided by one or more host recon modules.
|
|
||||||
#
|
|
||||||
def on_host_changed(context, host, change_type)
|
|
||||||
subscribers_rwlock.synchronize_read {
|
|
||||||
recon_event_subscribers.each { |subscriber|
|
|
||||||
cls = (subscriber.kind_of?(Class)) ? subscriber : subscriber.class
|
|
||||||
|
|
||||||
next if (cls.include?(Msf::ReconEvent::HostSubscriber) == false)
|
|
||||||
|
|
||||||
subscriber.on_host_changed(context, host, change_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine is called whenever a service's state changes, such as when
|
|
||||||
# it's found, updated, or removed. This event is dispatched by the Recon
|
|
||||||
# Manager.
|
|
||||||
#
|
|
||||||
def on_service_changed(context, host, service, change_type)
|
|
||||||
subscribers_rwlock.synchronize_read {
|
|
||||||
recon_event_subscribers.each { |subscriber|
|
|
||||||
cls = (subscriber.kind_of?(Class)) ? subscriber : subscriber.class
|
|
||||||
|
|
||||||
next if (cls.include?(Msf::ReconEvent::ServiceSubscriber) == false)
|
|
||||||
|
|
||||||
subscriber.on_service_changed(context, host, service, change_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
|
@ -269,7 +211,6 @@ protected
|
||||||
attr_accessor :general_event_subscribers # :nodoc:
|
attr_accessor :general_event_subscribers # :nodoc:
|
||||||
attr_accessor :exploit_event_subscribers # :nodoc:
|
attr_accessor :exploit_event_subscribers # :nodoc:
|
||||||
attr_accessor :session_event_subscribers # :nodoc:
|
attr_accessor :session_event_subscribers # :nodoc:
|
||||||
attr_accessor :recon_event_subscribers # :nodoc:
|
|
||||||
attr_accessor :subscribers_rwlock # :nodoc:
|
attr_accessor :subscribers_rwlock # :nodoc:
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,7 +34,6 @@ class Framework
|
||||||
|
|
||||||
require 'msf/core/module_manager'
|
require 'msf/core/module_manager'
|
||||||
require 'msf/core/session_manager'
|
require 'msf/core/session_manager'
|
||||||
require 'msf/core/recon_manager'
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Creates an instance of the framework context.
|
# Creates an instance of the framework context.
|
||||||
|
@ -43,7 +42,6 @@ class Framework
|
||||||
self.events = EventDispatcher.new
|
self.events = EventDispatcher.new
|
||||||
self.modules = ModuleManager.new(self)
|
self.modules = ModuleManager.new(self)
|
||||||
self.sessions = SessionManager.new(self)
|
self.sessions = SessionManager.new(self)
|
||||||
self.reconmgr = ReconManager.new(self)
|
|
||||||
self.datastore = DataStore.new
|
self.datastore = DataStore.new
|
||||||
self.jobs = Rex::JobContainer.new
|
self.jobs = Rex::JobContainer.new
|
||||||
self.plugins = PluginManager.new(self)
|
self.plugins = PluginManager.new(self)
|
||||||
|
@ -78,10 +76,10 @@ class Framework
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns the module set for recon modules
|
# Returns the module set for auxiliary modules
|
||||||
#
|
#
|
||||||
def recon
|
def auxiliary
|
||||||
return modules.recon
|
return modules.auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -111,11 +109,11 @@ class Framework
|
||||||
#
|
#
|
||||||
attr_reader :datastore
|
attr_reader :datastore
|
||||||
#
|
#
|
||||||
# The framework instance's recon manager. The recon manager is responsible
|
# The framework instance's aux manager. The aux manager is responsible
|
||||||
# for collecting and catalogging all recon information that comes in from
|
# for collecting and catalogging all aux information that comes in from
|
||||||
# recon modules.
|
# aux modules.
|
||||||
#
|
#
|
||||||
attr_reader :reconmgr
|
attr_reader :auxmgr
|
||||||
#
|
#
|
||||||
# Background job management specific to things spawned from this instance
|
# Background job management specific to things spawned from this instance
|
||||||
# of the framework.
|
# of the framework.
|
||||||
|
@ -134,7 +132,7 @@ protected
|
||||||
attr_writer :modules # :nodoc:
|
attr_writer :modules # :nodoc:
|
||||||
attr_writer :sessions # :nodoc:
|
attr_writer :sessions # :nodoc:
|
||||||
attr_writer :datastore # :nodoc:
|
attr_writer :datastore # :nodoc:
|
||||||
attr_writer :reconmgr # :nodoc:
|
attr_writer :auxmgr # :nodoc:
|
||||||
attr_writer :jobs # :nodoc:
|
attr_writer :jobs # :nodoc:
|
||||||
attr_writer :plugins # :nodoc:
|
attr_writer :plugins # :nodoc:
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,7 @@ class Module
|
||||||
require 'msf/core/module/platform_list'
|
require 'msf/core/module/platform_list'
|
||||||
require 'msf/core/module/reference'
|
require 'msf/core/module/reference'
|
||||||
require 'msf/core/module/target'
|
require 'msf/core/module/target'
|
||||||
|
require 'msf/core/module/auxiliary_action'
|
||||||
|
|
||||||
#
|
#
|
||||||
# Creates an instance of an abstract module using the supplied information
|
# Creates an instance of an abstract module using the supplied information
|
||||||
|
@ -387,10 +388,10 @@ class Module
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns true if this module is a recon module.
|
# Returns true if this module is an auxiliary module.
|
||||||
#
|
#
|
||||||
def recon?
|
def auxiliary?
|
||||||
return (type == MODULE_RECON)
|
return (type == MODULE_AUX)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# A target for an exploit.
|
||||||
|
#
|
||||||
|
###
|
||||||
|
class Msf::Module::AuxiliaryAction
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Serialize from an array to a Target instance.
|
||||||
|
#
|
||||||
|
def self.from_a(ary)
|
||||||
|
return nil if (ary.length < 2)
|
||||||
|
|
||||||
|
self.new(ary.shift, ary.shift)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Transforms the supplied source into an array of AuxiliaryActions.
|
||||||
|
#
|
||||||
|
def self.transform(src)
|
||||||
|
Rex::Transformer.transform(src, Array, [ self, String ], 'AuxiliaryAction')
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def initialize(name, opts={})
|
||||||
|
self.name = name
|
||||||
|
self.opts = opts
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Index the options directly.
|
||||||
|
#
|
||||||
|
def [](key)
|
||||||
|
opts[key]
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# The name of the action ('info')
|
||||||
|
#
|
||||||
|
attr_reader :name
|
||||||
|
#
|
||||||
|
# Action specific parameters
|
||||||
|
#
|
||||||
|
attr_reader :opts
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_writer :name, :opts # :nodoc:
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -288,10 +288,10 @@ class ModuleManager < ModuleSet
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns the set of loaded recon module classes.
|
# Returns the set of loaded auxiliary module classes.
|
||||||
#
|
#
|
||||||
def recon
|
def auxiliary
|
||||||
return module_sets[MODULE_RECON]
|
return module_sets[MODULE_AUX]
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -639,7 +639,7 @@ protected
|
||||||
# This method automatically subscribes a module to whatever event providers
|
# This method automatically subscribes a module to whatever event providers
|
||||||
# it wishes to monitor. This can be used to allow modules to automatically
|
# it wishes to monitor. This can be used to allow modules to automatically
|
||||||
# execute or perform other tasks when certain events occur. For instance,
|
# execute or perform other tasks when certain events occur. For instance,
|
||||||
# when a new host is detected, other recon modules may wish to run such
|
# when a new host is detected, other aux modules may wish to run such
|
||||||
# that they can collect more information about the host that was detected.
|
# that they can collect more information about the host that was detected.
|
||||||
#
|
#
|
||||||
def auto_subscribe_module(mod)
|
def auto_subscribe_module(mod)
|
||||||
|
@ -653,18 +653,6 @@ protected
|
||||||
# if it subscribes to any particular interfaces.
|
# if it subscribes to any particular interfaces.
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
#
|
|
||||||
# Recon event subscriber check
|
|
||||||
#
|
|
||||||
[
|
|
||||||
Msf::ReconEvent::HostSubscriber,
|
|
||||||
Msf::ReconEvent::ServiceSubscriber,
|
|
||||||
].each { |iface|
|
|
||||||
if (mod.include?(iface) == true)
|
|
||||||
framework.events.add_recon_subscriber((inst) ? inst : (inst = mod.new))
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Exploit event subscriber check
|
# Exploit event subscriber check
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,208 +0,0 @@
|
||||||
require 'msf/core/module'
|
|
||||||
|
|
||||||
module Msf
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This interface is called by recon modules to notify the framework when
|
|
||||||
# network elements, services, or other types of things recon modules
|
|
||||||
# might discovery.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
module ReconEvent
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# The types of changes an entity can undergo.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
module EntityChangeType
|
|
||||||
Add = 1
|
|
||||||
Update = 2
|
|
||||||
Remove = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This module provides methods for handling host entity notifications.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
module HostSubscriber
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine is called when a change is made to a host, such as it being
|
|
||||||
# added, modified, or removed.
|
|
||||||
#
|
|
||||||
def on_host_changed(context, host, change_type)
|
|
||||||
case change_type
|
|
||||||
when EntityChangeType::Add
|
|
||||||
on_new_host(context, host)
|
|
||||||
when EntityChangeType::Update
|
|
||||||
on_updated_host(context, host)
|
|
||||||
when EntityChangeType::Remove
|
|
||||||
on_dead_host(context, host)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine is called whenever a new host is found.
|
|
||||||
#
|
|
||||||
def on_new_host(context, host)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine is called whenever a change is made to an existing
|
|
||||||
# host.
|
|
||||||
#
|
|
||||||
def on_updated_host(context, host)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Called when a host is considered to be dead after having
|
|
||||||
# previously been valid.
|
|
||||||
#
|
|
||||||
def on_dead_host(context, host)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine is called whenever a host attribute is found.
|
|
||||||
#
|
|
||||||
def on_new_host_attribute(context, host, attribute)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This module provides methods for handling notifications that deal with
|
|
||||||
# service entities.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
module ServiceSubscriber
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine is called when a change is made to a service, such as it being
|
|
||||||
# added, modified, or removed.
|
|
||||||
#
|
|
||||||
def on_service_changed(context, host, service, change_type)
|
|
||||||
case change_type
|
|
||||||
when EntityChangeType::Add
|
|
||||||
on_new_service(context, host, service)
|
|
||||||
when EntityChangeType::Update
|
|
||||||
on_updated_service(context, host, service)
|
|
||||||
when EntityChangeType::Remove
|
|
||||||
on_dead_service(context, host, service)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine is called whenever a new service is found.
|
|
||||||
#
|
|
||||||
def on_new_service(context, host, service)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine is called whenever a change is made to an existing
|
|
||||||
# service.
|
|
||||||
#
|
|
||||||
def on_updated_service(context, host, service)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Called when a service is considered to be dead after having
|
|
||||||
# previously been valid.
|
|
||||||
#
|
|
||||||
def on_dead_service(context, host, service)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine is called whenever a service attribute is found.
|
|
||||||
#
|
|
||||||
def on_new_service_attribute(context, host, service, attribute)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# The ReconEvents base mixin includes all methods from the Host and Service
|
|
||||||
# subscriber interfaces.
|
|
||||||
#
|
|
||||||
include HostSubscriber
|
|
||||||
include ServiceSubscriber
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# The recon class acts as a base class for all recon modules. It provides a
|
|
||||||
# common interface for detecting the presence of hosts, services, and the
|
|
||||||
# attributes of everything in between. The type of information that can be
|
|
||||||
# discovered is designed to be generic.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Recon < Msf::Module
|
|
||||||
|
|
||||||
#
|
|
||||||
# The various basic sub-types of recon modules.
|
|
||||||
#
|
|
||||||
module Type
|
|
||||||
|
|
||||||
#
|
|
||||||
# Indicates that this is an unknown recon module. This recon module
|
|
||||||
# does something other than discover and analyze.
|
|
||||||
#
|
|
||||||
Unknown = "unknown"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Indicates that the recon module discovers things. Discoverer recon
|
|
||||||
# modules are responsible for collecting information about the presence
|
|
||||||
# of entities and the attributes of those entities. For instance,
|
|
||||||
# a discoverer module finds hosts and the services running on those
|
|
||||||
# hosts and could also determine more granular information about
|
|
||||||
# the host and service by determining some of their attributes, such
|
|
||||||
# as a host's platform.
|
|
||||||
#
|
|
||||||
Discoverer = "discoverer"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Indicates that the recon module analyzes things. Analyzer recon
|
|
||||||
# modules take information collected by discoverer recon modules and
|
|
||||||
# determine or derived more detailed information about an entity or a
|
|
||||||
# group of entities. For instance, an analyzer module may determine
|
|
||||||
# that five distinct hosts detected by a discoverer module may actually
|
|
||||||
# be on the same machine but just virtual hosted. Also, analyzer
|
|
||||||
# modules might try to do more advanced stuff like crack passwords
|
|
||||||
# collected by recon modules and other such fun things.
|
|
||||||
#
|
|
||||||
Analyzer = "analyzer"
|
|
||||||
end
|
|
||||||
|
|
||||||
require 'msf/core/recon/discoverer'
|
|
||||||
require 'msf/core/recon/entity'
|
|
||||||
require 'msf/core/recon/event_context'
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns MODULE_RECON to indicate that this is a recon module.
|
|
||||||
#
|
|
||||||
def self.type
|
|
||||||
MODULE_RECON
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns MODULE_RECON to indicate that this is a recon module.
|
|
||||||
#
|
|
||||||
def type
|
|
||||||
MODULE_RECON
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns the general type of recon module.
|
|
||||||
#
|
|
||||||
def recon_type
|
|
||||||
Type::Unknown
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,108 +0,0 @@
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
module Attribute
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This mixin provides methods for setting and getting the values
|
|
||||||
# of various attributes. As attributes are defined, aliases methods are added
|
|
||||||
# to the container to make it easier to access the attributes for reading.
|
|
||||||
# This is done to encourage the direct referencing of attributes for reading
|
|
||||||
# by an accessor method rather than through using get_attribute which will
|
|
||||||
# simply return nil if no match was found. By doing it this way, recon
|
|
||||||
# modules can try to access the attributes of a host, service, or other entity
|
|
||||||
# that may not yet be defined and thus lead to an exception being thrown.
|
|
||||||
# This will indicate that not enough information has been gathered yet for the
|
|
||||||
# recon module to proceed.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
module Container
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes the attribute hash.
|
|
||||||
#
|
|
||||||
def initialize_attributes
|
|
||||||
self._attr_hash = Hash.new
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Wraps get_attribute.
|
|
||||||
#
|
|
||||||
def [](key)
|
|
||||||
get_attribute(key)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Wraps set_attribute.
|
|
||||||
#
|
|
||||||
def []=(key, val)
|
|
||||||
set_attribute(key, val)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Sets the value of an attribute with the supplied name.
|
|
||||||
#
|
|
||||||
def set_attribute(name, val)
|
|
||||||
|
|
||||||
# If we've yet to define this method on the container, do so now.
|
|
||||||
#
|
|
||||||
# TODO: evalulate the performance of doing it this way.
|
|
||||||
if (respond_to?(name) == false)
|
|
||||||
begin
|
|
||||||
instance_eval("
|
|
||||||
def #{name}
|
|
||||||
_attr_hash['#{name}']
|
|
||||||
end")
|
|
||||||
rescue SyntaxError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
_attr_hash[name] = val
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Unsets an attribute entirely.
|
|
||||||
#
|
|
||||||
def unset_attribute
|
|
||||||
_attr_hash.delete(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the value associated with the supplied attribute name.
|
|
||||||
#
|
|
||||||
def get_attribute(name)
|
|
||||||
_attr_hash[name]
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns a list of all attributes that have had a value set.
|
|
||||||
#
|
|
||||||
def attributes
|
|
||||||
_attr_hash.keys
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the attribute hash in case direct interaction is necessary.
|
|
||||||
#
|
|
||||||
def attribute_hash
|
|
||||||
_attr_hash
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Serializes from a hash.
|
|
||||||
#
|
|
||||||
def from_hash(hsh)
|
|
||||||
hsh.each_pair { |k,v|
|
|
||||||
set_attribute(k, v)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
attr_accessor :_attr_hash # :nodoc:
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,44 +0,0 @@
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
module Attribute
|
|
||||||
|
|
||||||
require 'msf/core/recon/attribute/container'
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class acts as a symbolic attribute group and is simply used as a
|
|
||||||
# means of containing attributes without being an actual attribute or
|
|
||||||
# an entity itself.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Group
|
|
||||||
include Container
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine defines an attribute by name by creating accessors that
|
|
||||||
# reference the internal hash.
|
|
||||||
#
|
|
||||||
def self.def_attr(*args)
|
|
||||||
args.each { |name|
|
|
||||||
class_eval("
|
|
||||||
def #{name}
|
|
||||||
attribute_hash['#{name}']
|
|
||||||
end
|
|
||||||
def #{name}=(val)
|
|
||||||
attribute_hash['#{name}'] = val
|
|
||||||
end")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes the attribute group which is simply a container of
|
|
||||||
# attributes.
|
|
||||||
#
|
|
||||||
def initialize
|
|
||||||
initialize_attributes
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,26 +0,0 @@
|
||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..', '..'))
|
|
||||||
|
|
||||||
require 'test/unit'
|
|
||||||
require 'msf/core'
|
|
||||||
require 'msf/core/recon/attribute/group'
|
|
||||||
|
|
||||||
class Msf::Recon::Attribute::Group::UnitTest < Test::Unit::TestCase
|
|
||||||
|
|
||||||
Klass = Msf::Recon::Attribute::Group
|
|
||||||
|
|
||||||
class Tester < Klass
|
|
||||||
def_attr :testing
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_target
|
|
||||||
e = Tester.new
|
|
||||||
|
|
||||||
assert_not_nil(e)
|
|
||||||
|
|
||||||
e.testing = 1
|
|
||||||
assert_equal(1, e.testing)
|
|
||||||
assert_equal(1, e.get_attribute('testing'))
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,286 +0,0 @@
|
||||||
require 'thread'
|
|
||||||
require 'rex/sync/event'
|
|
||||||
|
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class acts as a base class for all recon modules that attempt to
|
|
||||||
# discover new entities and attributes of entities. For instance, recon
|
|
||||||
# modules that attempt to discover the presence of a host, service, user, or
|
|
||||||
# other forms of entities are considered sub-classes of discoverer recon
|
|
||||||
# modules. On top of that, recon modules that attempt to discover the
|
|
||||||
# attributes of any of the previously described entities are considered
|
|
||||||
# discoverer recon modules as well.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Discoverer < Msf::Recon
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# The types of discoverer recon modules that are known about by default.
|
|
||||||
#
|
|
||||||
##
|
|
||||||
module Type
|
|
||||||
|
|
||||||
#
|
|
||||||
# Unknown discoverer module type.
|
|
||||||
#
|
|
||||||
Unknown = 'unknown'
|
|
||||||
|
|
||||||
#
|
|
||||||
# Host discoverer.
|
|
||||||
#
|
|
||||||
Host = 'host'
|
|
||||||
|
|
||||||
#
|
|
||||||
# Host attribute discoverer.
|
|
||||||
#
|
|
||||||
HostAttribute = 'host attribute'
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# The set of flags that discoverer modules can use to instruct the
|
|
||||||
# framework (or themselves) on how to operate.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
module Flags
|
|
||||||
#
|
|
||||||
# This flag is used to indicate that a discoverer supports multithreaded
|
|
||||||
# discovery.
|
|
||||||
#
|
|
||||||
Multithreaded = 0x01
|
|
||||||
end
|
|
||||||
|
|
||||||
require 'msf/core/recon/discoverer/host'
|
|
||||||
require 'msf/core/recon/discoverer/service'
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes the base of a recon discoverer module and adds any advanced
|
|
||||||
# options that may be useful, like the number of threads the framework
|
|
||||||
# should use for scanning.
|
|
||||||
#
|
|
||||||
def initialize(info = {})
|
|
||||||
super
|
|
||||||
|
|
||||||
# Attribute initialization
|
|
||||||
self.discovery_threads = Array.new
|
|
||||||
self.discovery_thread_mutex = Mutex.new
|
|
||||||
self.discovery_thread_event = Rex::Sync::Event.new(false, false)
|
|
||||||
|
|
||||||
# If the derived class supports multithreaded scanning, then allow the
|
|
||||||
# user to set an option to control it
|
|
||||||
if ((discoverer_flags & Flags::Multithreaded) != 0)
|
|
||||||
register_advanced_options(
|
|
||||||
[
|
|
||||||
OptInt.new('ScanningThreads', [ 0, 'Number of threads to scan with', 1 ])
|
|
||||||
], Msf::Recon::Discoverer)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Getters/Setters
|
|
||||||
#
|
|
||||||
##
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method indicates that this recon module is a discoverer.
|
|
||||||
#
|
|
||||||
def recon_type
|
|
||||||
Msf::Recon::Type::Discoverer
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns the type of discoverer recon module.
|
|
||||||
#
|
|
||||||
def discoverer_type
|
|
||||||
Type::Unknown
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns the default discoverer flags that are used to drive
|
|
||||||
# the host discovery process.
|
|
||||||
#
|
|
||||||
def discoverer_flags
|
|
||||||
Flags::Multithreaded
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Core discoverer interface
|
|
||||||
#
|
|
||||||
##
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initiates the discovery process in an implementation independent fashion.
|
|
||||||
#
|
|
||||||
def start_discovery
|
|
||||||
# If the module is already discovering, then we don't need to start
|
|
||||||
# again
|
|
||||||
if (is_discovering)
|
|
||||||
raise RuntimeError, "#{self.refname} is already discovering.", caller
|
|
||||||
end
|
|
||||||
|
|
||||||
# Validate that all the options are okay
|
|
||||||
options.validate(datastore)
|
|
||||||
|
|
||||||
# Reset the discovery event
|
|
||||||
discovery_thread_event.reset
|
|
||||||
|
|
||||||
# Get the default number of threads to spawn
|
|
||||||
num_threads = default_scanning_threads;
|
|
||||||
|
|
||||||
# If more scanning threads were supplied through an advanced option,
|
|
||||||
# then let us use those
|
|
||||||
if (datastore['ScanningThreads'] and
|
|
||||||
datastore['ScanningThreads'].to_i > 0)
|
|
||||||
num_threads = datastore['ScanningThreads'].to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
# Call a method that allows the derived class to pre-initialization
|
|
||||||
# before actually starting
|
|
||||||
discovery_startup
|
|
||||||
|
|
||||||
# Spawn as many worker threads as were requested
|
|
||||||
num_threads.times { |x|
|
|
||||||
dlog("#{self.refname}: Spawning worker thread #{x+1}/#{num_threads}...", "core", LEV_3)
|
|
||||||
|
|
||||||
spawn_discovery_thread
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Terminates the discovery process in an implementation independent
|
|
||||||
# fashion.
|
|
||||||
#
|
|
||||||
def stop_discovery
|
|
||||||
remaining = 0
|
|
||||||
|
|
||||||
# Instruct all remaining discovery threads to stop.
|
|
||||||
discovery_thread_mutex.synchronize {
|
|
||||||
remaining = discovery_threads.length
|
|
||||||
|
|
||||||
discovery_threads.each { |thr|
|
|
||||||
thr.stop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Flush out the list of discovery threads
|
|
||||||
discovery_threads.clear
|
|
||||||
|
|
||||||
# Call the discovery complete method before the final wakeup.
|
|
||||||
discovery_complete((remaining > 0) ? true : false)
|
|
||||||
|
|
||||||
# Wake up any other threads that might be waiting for this operation to
|
|
||||||
# complete
|
|
||||||
discovery_thread_event.set
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Waits for the recon discoverer to complete its operation.
|
|
||||||
#
|
|
||||||
def wait_for_completion(timeout = nil)
|
|
||||||
discovery_thread_event.wait(timeout)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns whether or not the recon module is discovering.
|
|
||||||
#
|
|
||||||
def is_discovering
|
|
||||||
(discovery_threads.length > 0) ? true : false
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Defaults
|
|
||||||
#
|
|
||||||
##
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns the default number of scanning threads for this
|
|
||||||
# discoverer.
|
|
||||||
#
|
|
||||||
def default_scanning_threads
|
|
||||||
1
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Overridable protected methods
|
|
||||||
#
|
|
||||||
##
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method is called when discovery is about to begin as the result of a
|
|
||||||
# call being made to start_discovery.
|
|
||||||
#
|
|
||||||
def discovery_startup
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method is called when discovery is finished, whether it was aborted
|
|
||||||
# or finished as normal. If it was aborted, the first parameter will
|
|
||||||
# indicate that fact by passing true.
|
|
||||||
#
|
|
||||||
def discovery_complete(aborted)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# The entry point for all discovery threads. This method should be
|
|
||||||
# overridden by derived classes.
|
|
||||||
#
|
|
||||||
def discovery_thread
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Internal routines
|
|
||||||
#
|
|
||||||
##
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method spawns a worker thread and adds it to the list of active
|
|
||||||
# workers.
|
|
||||||
#
|
|
||||||
def spawn_discovery_thread
|
|
||||||
# Synchronize the addition of the thread to the list of threads
|
|
||||||
discovery_thread_mutex.synchronize {
|
|
||||||
self.discovery_threads << Thread.new {
|
|
||||||
begin
|
|
||||||
# Perform the arbitrary discovery task.
|
|
||||||
discovery_thread
|
|
||||||
|
|
||||||
# Synchronize the removal of ourself from the list of threads.
|
|
||||||
discovery_thread_mutex.synchronize {
|
|
||||||
discovery_threads.delete(Thread.current)
|
|
||||||
|
|
||||||
# If we detect that there are no more threads running, set the
|
|
||||||
# event to indicate that we've reached completion.
|
|
||||||
if (discovery_threads.length == 0)
|
|
||||||
# Call the discovery complete method
|
|
||||||
discovery_complete(false)
|
|
||||||
|
|
||||||
discovery_thread_event.set
|
|
||||||
end
|
|
||||||
}
|
|
||||||
rescue
|
|
||||||
elog("Exception in discovery thread: #{$!}\n#{$@.join("\n")}")
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_accessor :discovery_threads # :nodoc:
|
|
||||||
attr_accessor :discovery_thread_mutex # :nodoc:
|
|
||||||
attr_accessor :discovery_thread_event # :nodoc:
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,231 +0,0 @@
|
||||||
require 'thread'
|
|
||||||
require 'rex/socket/subnet_walker'
|
|
||||||
|
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
class Discoverer
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class provides a base class for all recon modules that attempt to
|
|
||||||
# discover the presence of a host.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Host < Msf::Recon::Discoverer
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes an instance of a host discoverer recon module and adds
|
|
||||||
# options that are common to all host discoverers, like subnet and netmask.
|
|
||||||
#
|
|
||||||
def initialize(info = {})
|
|
||||||
super
|
|
||||||
|
|
||||||
# Initialize the mutex that we'll use to synchronize the subnet walker
|
|
||||||
# instance that's created during discovery
|
|
||||||
self.swalker_mutex = Mutex.new
|
|
||||||
|
|
||||||
# TODO - support random scan
|
|
||||||
#register_advanced_options(
|
|
||||||
# [
|
|
||||||
# OptBool.new('RandomScan', [ 0, 'Scan the subnet in a random order', 'false' ])
|
|
||||||
# ], Msf::Recon::Discoverer::Host)
|
|
||||||
|
|
||||||
# Register the options that this particular discovery module uses
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
OptAddress.new('SUBNET', [ 1, 'The subnet to scan' ]),
|
|
||||||
OptAddress.new('NETMASK', [ 1, 'The netmask of the subnet' ])
|
|
||||||
], Msf::Recon::Discoverer::Host)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns that this is a host discoverer recon module.
|
|
||||||
#
|
|
||||||
def discoverer_type
|
|
||||||
Type::Host
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method is called when a host should be probed to determine whether
|
|
||||||
# or not it is alive. If the host is found to be alive, HostState::Alive
|
|
||||||
# should be returned. Otherwise, if a host was found to be dead, then
|
|
||||||
# HostState::Dead should be returned. If its state could not be
|
|
||||||
# determined, HostState::Unknown should be returned.
|
|
||||||
#
|
|
||||||
# This method can also return a hash that contains information that will be
|
|
||||||
# passed as part of the event context to the reporting subsystem of the
|
|
||||||
# recon manager. This EventContext instance will, in turn, be passed to
|
|
||||||
# any subscribers of recon-related events. For instance, if a port scanner
|
|
||||||
# connects to a port on a given host, it can pass the connection around to
|
|
||||||
# other recon modules to give them a chance to work with it. The following
|
|
||||||
# keys are special in a hash returned from probe_host:
|
|
||||||
#
|
|
||||||
# state - Equivalent to one of the three HostState values.
|
|
||||||
# connection - The connection associated with the host (TCP, UDP, etc).
|
|
||||||
#
|
|
||||||
def probe_host(address)
|
|
||||||
HostState::Unknown
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method acts the same as the probe_host method except it takes as an
|
|
||||||
# argument an array of IP addresses to probe and expects an array of
|
|
||||||
# address statuses to be returned to that corresponds to the array of
|
|
||||||
# addresses passed in as arguments. This method is only called if
|
|
||||||
# hosts_per_block is not one.
|
|
||||||
#
|
|
||||||
# The array elements can also take the form of a hash as described in the
|
|
||||||
# probe_host method description.
|
|
||||||
#
|
|
||||||
def probe_host_block(addresses)
|
|
||||||
addresses.map { HostState::Unknown }
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Allows a derived class to cleanup anything, like a socket, that may have
|
|
||||||
# been used during the probe operation. The state parameter is equivalent
|
|
||||||
# to the return value from probe_host (or probe_host_block for each entry
|
|
||||||
# in the array).
|
|
||||||
#
|
|
||||||
def probe_host_cleanup(address, state)
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method initializes the subnet walker for this instance and gets the
|
|
||||||
# ball rolling.
|
|
||||||
#
|
|
||||||
def discovery_startup
|
|
||||||
# Create the subnet walker instance
|
|
||||||
self.swalker = Rex::Socket::SubnetWalker.new(
|
|
||||||
datastore['SUBNET'], datastore['NETMASK'])
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This is the entry point for any number of threads that may be spawned to
|
|
||||||
# discover hosts for this module.
|
|
||||||
#
|
|
||||||
def discovery_thread
|
|
||||||
# If we're processing one IP address per block, then do a singular probe
|
|
||||||
# by calling probe_host for each address.
|
|
||||||
if (hosts_per_block == 1)
|
|
||||||
while (ip = next_ip)
|
|
||||||
report_host_state(ip, probe_host(ip))
|
|
||||||
end
|
|
||||||
# Otherwise, get up to the number of hosts per block defined and call
|
|
||||||
# probe_host_block.
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
addresses = []
|
|
||||||
|
|
||||||
# Fill up the array of addresses as high as we can go
|
|
||||||
while (ip = next_ip)
|
|
||||||
addresses << ip
|
|
||||||
end
|
|
||||||
|
|
||||||
# If we have no addresses to process, then break out of the loop
|
|
||||||
break if (addresses.length == 0)
|
|
||||||
|
|
||||||
# Probe the host block and get the statuses
|
|
||||||
statuses = probe_host_block(addresses)
|
|
||||||
|
|
||||||
# If no statuses were returned, something odd happened, break out.
|
|
||||||
if (statuses.length == 0)
|
|
||||||
wlog("#{self.refname}: probe of #{addresses.length} addresses returned no status")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
# Report the status associated with each address
|
|
||||||
addresses.each_with_index { |address, idx|
|
|
||||||
report_host_state(address, statuses[idx])
|
|
||||||
}
|
|
||||||
|
|
||||||
end while (true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the next IP address to the caller in a synchronized fashion. If
|
|
||||||
# no IPs are left to be enumerated, nil is returned.
|
|
||||||
#
|
|
||||||
def next_ip
|
|
||||||
swalker_mutex.synchronize {
|
|
||||||
swalker.next_ip
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method reports host state information to the recon manager, possibly
|
|
||||||
# including an event context.
|
|
||||||
#
|
|
||||||
def report_host_state(ip, istate)
|
|
||||||
# Create a nil context
|
|
||||||
context = nil
|
|
||||||
state = istate
|
|
||||||
|
|
||||||
# If a hash was returned, we should create an event context to
|
|
||||||
# pass to the notification.
|
|
||||||
if (istate.kind_of?(Hash))
|
|
||||||
context = Msf::Recon::EventContext.new
|
|
||||||
|
|
||||||
# Serialize the context from the hash
|
|
||||||
context.from_hash(state)
|
|
||||||
|
|
||||||
# Grab the real state from the hash
|
|
||||||
state = istate['state']
|
|
||||||
end
|
|
||||||
|
|
||||||
# Report the host's state to the recon manager.
|
|
||||||
framework.reconmgr.report_host_state(
|
|
||||||
self, ip, state, context)
|
|
||||||
|
|
||||||
# Perform cleanup as necessary (only if istate was a Hash)
|
|
||||||
if (context)
|
|
||||||
probe_host_cleanup(ip, istate)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Defaults that can be overridden by derived classes
|
|
||||||
#
|
|
||||||
##
|
|
||||||
|
|
||||||
#
|
|
||||||
# The default number of hosts to process per-block. If this number is one,
|
|
||||||
# the probe_host method will be called. Otherwise, the probe_block method
|
|
||||||
# will be called which takes an array of IP addresses to probe.
|
|
||||||
#
|
|
||||||
def hosts_per_block
|
|
||||||
1
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_accessor :swalker # :nodoc:
|
|
||||||
attr_accessor :swalker_mutex # :nodoc:
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# HostAttribute
|
|
||||||
# -------------
|
|
||||||
#
|
|
||||||
# This class provides a base class for all recon modules that attempt to
|
|
||||||
# discover specific attributes about a host that was detected through a Host
|
|
||||||
# discoverer recon module.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class HostAttribute < Msf::Recon::Discoverer
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns Type::HostAttribute.
|
|
||||||
#
|
|
||||||
def discoverer_type
|
|
||||||
Type::HostAttribute
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,98 +0,0 @@
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
class Discoverer
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class provides a base class for all recon modules that attempt to
|
|
||||||
# discover the presence of a service on a host.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Service < Msf::Recon::Discoverer
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes a service discoverer recon module that is responsible for
|
|
||||||
# locating running services or information about services that are running
|
|
||||||
# on hosts.
|
|
||||||
#
|
|
||||||
def initialize(info = {})
|
|
||||||
super
|
|
||||||
|
|
||||||
# Register the options that this particular discovery module uses
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
Opt::RHOST
|
|
||||||
], Msf::Recon::Discoverer::Service)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns that this is a service discoverer recon module.
|
|
||||||
#
|
|
||||||
def discoverer_type
|
|
||||||
Type::Service
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# By default, service discoverer recon modules do no support
|
|
||||||
# multi-threading.
|
|
||||||
#
|
|
||||||
def discoverer_flags
|
|
||||||
0
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Probes a host entity to see what services it has open. Extended modules
|
|
||||||
# should report service state changes directly via the report_service_state
|
|
||||||
# instance method.
|
|
||||||
#
|
|
||||||
def probe_host(host)
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
#
|
|
||||||
# Wraps the probing of a host.
|
|
||||||
#
|
|
||||||
def discovery_thread
|
|
||||||
if ((host = framework.reconmgr.get_host(datastore['RHOST'])) == nil)
|
|
||||||
host = Msf::Recon::Entity::Host.new(datastore['RHOST'])
|
|
||||||
end
|
|
||||||
|
|
||||||
probe_host(host)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method reports the state of a service to the recon manager so that
|
|
||||||
# it can be tracked appropriately.
|
|
||||||
#
|
|
||||||
def report_service_state(host, proto, port, istate)
|
|
||||||
state = istate
|
|
||||||
context = nil
|
|
||||||
|
|
||||||
# If the state passed in as an argument is a hash, then create an event
|
|
||||||
# context that we'll pass along to the recon manager in case other
|
|
||||||
# subscribers might be able to make use of it.
|
|
||||||
if (istate.kind_of?(Hash))
|
|
||||||
context = Msf::Recon::EventContext.new
|
|
||||||
|
|
||||||
context.from_hash(istate)
|
|
||||||
|
|
||||||
state = istate['state']
|
|
||||||
end
|
|
||||||
|
|
||||||
# Log that we detected an up service
|
|
||||||
if (state == ServiceState::Up)
|
|
||||||
dlog("Found port #{port} (#{proto}) open on #{host.address}.", "core",
|
|
||||||
LEV_2)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Pass the normalized service state notifications to the recon manager.
|
|
||||||
framework.reconmgr.report_service_state(self, host, proto, port,
|
|
||||||
state, context)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,55 +0,0 @@
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class represents an abstract entity that can be discovered during the
|
|
||||||
# recon process, such as a host, a service, a user, or some other formal
|
|
||||||
# and distinct thing. All entities can have zero or may attributes and
|
|
||||||
# may contain zero or more entities of various types. This is pretty
|
|
||||||
# abstract, like woah.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Entity
|
|
||||||
|
|
||||||
require 'msf/core/recon/attribute/group'
|
|
||||||
require 'msf/core/recon/entity/group'
|
|
||||||
|
|
||||||
#
|
|
||||||
# Entities are all offspring of the framework
|
|
||||||
#
|
|
||||||
include Framework::Offspring
|
|
||||||
#
|
|
||||||
# All entities can contain attributes
|
|
||||||
#
|
|
||||||
include Attribute::Container
|
|
||||||
#
|
|
||||||
# All entities can contain zero or more entities
|
|
||||||
#
|
|
||||||
include Entity::Container
|
|
||||||
|
|
||||||
require 'msf/core/recon/entity/host'
|
|
||||||
require 'msf/core/recon/entity/service'
|
|
||||||
require 'msf/core/recon/entity/user'
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes the entity's attributes and sub-entities.
|
|
||||||
#
|
|
||||||
def initialize
|
|
||||||
initialize_attributes
|
|
||||||
initialize_entities
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the entity's type.
|
|
||||||
#
|
|
||||||
def entity_type
|
|
||||||
'unknown'
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_accessor :needs_register # :nodoc:
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,26 +0,0 @@
|
||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
|
||||||
|
|
||||||
require 'test/unit'
|
|
||||||
require 'msf/core'
|
|
||||||
require 'msf/core/recon/entity'
|
|
||||||
|
|
||||||
class Msf::Recon::Entity::UnitTest < Test::Unit::TestCase
|
|
||||||
|
|
||||||
Klass = Msf::Recon::Entity
|
|
||||||
|
|
||||||
def test_target
|
|
||||||
e = Klass.new
|
|
||||||
|
|
||||||
assert_not_nil(e)
|
|
||||||
|
|
||||||
e.set_attribute('foo', 4)
|
|
||||||
assert_not_nil(e.foo)
|
|
||||||
assert_equal(4, e.foo)
|
|
||||||
assert_equal(4, e.get_attribute('foo'))
|
|
||||||
e.set_attribute('foo', 5)
|
|
||||||
assert_equal(5, e.foo)
|
|
||||||
assert_equal(5, e.get_attribute('foo'))
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,90 +0,0 @@
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
class Entity
|
|
||||||
|
|
||||||
class Group
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This mixin is included when something wishes to be capable of containing
|
|
||||||
# entities of an arbitrary type.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
module Container
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes the array of entities.
|
|
||||||
#
|
|
||||||
def initialize_entities
|
|
||||||
self._entity_hash = Hash.new
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This routine adds a sub-container of entities to this entity container.
|
|
||||||
#
|
|
||||||
def add_entity_subcontainer(name, container = Group.new)
|
|
||||||
if (self._entity_hash[name] == nil)
|
|
||||||
add_entity(name, container)
|
|
||||||
end
|
|
||||||
|
|
||||||
self._entity_hash[name]
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Adds an entity to the container.
|
|
||||||
#
|
|
||||||
def <<(entity)
|
|
||||||
add_entity(entity)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Adds an entity to the container.
|
|
||||||
#
|
|
||||||
def add_entity(name, entity)
|
|
||||||
self._entity_hash[name] = entity
|
|
||||||
|
|
||||||
if (respond_to?(name) == false)
|
|
||||||
instance_eval("
|
|
||||||
def #{name}
|
|
||||||
_entity_hash[#{name}]
|
|
||||||
end
|
|
||||||
")
|
|
||||||
end
|
|
||||||
|
|
||||||
entity
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the entity associated with the supplied name.
|
|
||||||
#
|
|
||||||
def get_entity(name)
|
|
||||||
_entity_hash[name]
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Removes an entity from the hash of entities.
|
|
||||||
#
|
|
||||||
def delete_entity(entity)
|
|
||||||
self._entity_hash.delete(entity)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the hash of entities to the caller.
|
|
||||||
#
|
|
||||||
def entities
|
|
||||||
_entity_hash
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
#
|
|
||||||
# The protected entity hash itself.
|
|
||||||
#
|
|
||||||
attr_accessor :_entity_hash
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,72 +0,0 @@
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
class Entity
|
|
||||||
|
|
||||||
require 'msf/core/recon/entity/container'
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class acts as a symbolic entity group and is simply used to group
|
|
||||||
# entities together without itself being an entity. This is analagous to the
|
|
||||||
# Attribute::Group class.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Group
|
|
||||||
|
|
||||||
include Container
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes an entity group which is simply an entity container.
|
|
||||||
#
|
|
||||||
def initialize
|
|
||||||
initialize_entities
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class extends the Group base class to provide some default protocol
|
|
||||||
# group sub-containers for entities that are specific to a given service
|
|
||||||
# protocol.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class ServiceGroup < Group
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes a group of services and breaks them down into their
|
|
||||||
# sub-protocols which can be accessed through the 'tcp' and 'udp'
|
|
||||||
# attributes.
|
|
||||||
#
|
|
||||||
def initialize
|
|
||||||
super
|
|
||||||
|
|
||||||
# Add protocol-specific subcontainer groups
|
|
||||||
self.tcp = Group.new
|
|
||||||
self.udp = Group.new
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This attribute is a sub-group that contains all TCP services.
|
|
||||||
#
|
|
||||||
attr_reader :tcp
|
|
||||||
#
|
|
||||||
# This attribute is a sub-group that contains all UDP services.
|
|
||||||
#
|
|
||||||
attr_reader :udp
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
attr_writer :tcp, :udp # :nodoc:
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Aliased class names for now.
|
|
||||||
#
|
|
||||||
HostGroup = Group
|
|
||||||
UserGroup = Group
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,88 +0,0 @@
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
class Entity
|
|
||||||
|
|
||||||
require 'msf/core/recon/entity/group'
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class represents a logical host entity. Hosts symbolize a machine that
|
|
||||||
# may have zero or more services running on it. Information about the host,
|
|
||||||
# such as platform, architecture, and other attributes may be gathered and
|
|
||||||
# populated over time after its initialize discovery through a host discoverer
|
|
||||||
# recon module.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Host < Entity
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class defines some of the standard system attributes that a host
|
|
||||||
# would have.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class SystemAttributeGroup < Attribute::Group
|
|
||||||
|
|
||||||
#
|
|
||||||
# The platform that the host is running.
|
|
||||||
#
|
|
||||||
def_attr :platform
|
|
||||||
#
|
|
||||||
# The architecture that the host is running.
|
|
||||||
#
|
|
||||||
def_attr :arch
|
|
||||||
#
|
|
||||||
# The time on the host machine.
|
|
||||||
#
|
|
||||||
def_attr :time
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes a host entity with the supplied address after being found
|
|
||||||
# during recon.
|
|
||||||
#
|
|
||||||
def initialize(address)
|
|
||||||
super()
|
|
||||||
|
|
||||||
# Holds the address of the host that this entity instance is associated
|
|
||||||
# with.
|
|
||||||
self.address = address
|
|
||||||
|
|
||||||
# Add an attribute group that will contain system information for this
|
|
||||||
# host.
|
|
||||||
self.sys = SystemAttributeGroup.new
|
|
||||||
|
|
||||||
# Create a service group instance for this host.
|
|
||||||
self.services = ServiceGroup.new
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns a pretty string representing this host.
|
|
||||||
#
|
|
||||||
def pretty
|
|
||||||
"#{address}"
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# The address that the host instance is associated with.
|
|
||||||
#
|
|
||||||
attr_reader :address
|
|
||||||
#
|
|
||||||
# The system attributes for this host.
|
|
||||||
#
|
|
||||||
attr_reader :sys
|
|
||||||
#
|
|
||||||
# The services known to be running on this host.
|
|
||||||
#
|
|
||||||
attr_reader :services
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
attr_writer :address, :sys, :services # :nodoc:
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,27 +0,0 @@
|
||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..', '..'))
|
|
||||||
|
|
||||||
require 'test/unit'
|
|
||||||
require 'msf/core'
|
|
||||||
require 'msf/core/recon/entity'
|
|
||||||
|
|
||||||
class Msf::Recon::Entity::Host::UnitTest < Test::Unit::TestCase
|
|
||||||
|
|
||||||
Klass = Msf::Recon::Entity::Host
|
|
||||||
|
|
||||||
def test_target
|
|
||||||
e = Klass.new
|
|
||||||
|
|
||||||
assert_not_nil(e)
|
|
||||||
assert_not_nil(e.sys)
|
|
||||||
assert_not_nil(e.services)
|
|
||||||
|
|
||||||
e.sys.platform = 4
|
|
||||||
assert_equal(4, e.sys.platform)
|
|
||||||
e.sys.arch = 4
|
|
||||||
assert_equal(4, e.sys.arch)
|
|
||||||
e.sys.time = 4
|
|
||||||
assert_equal(4, e.sys.time)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,53 +0,0 @@
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
class Entity
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class represents a logical service entity. Services symbolize remote
|
|
||||||
# functionality provided by a host by means of some network-based protocol,
|
|
||||||
# such as TCP over IP. Information about a service, such as its protocol,
|
|
||||||
# port, banner, and other information is conveyed through attributes of the
|
|
||||||
# service entity.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Service < Entity
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initializes a service entity that has been found to be running on a host.
|
|
||||||
#
|
|
||||||
def initialize(proto, port = nil)
|
|
||||||
super()
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize the local attributes
|
|
||||||
#
|
|
||||||
self.proto = proto
|
|
||||||
self.port = port
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns a pretty string representation of the service.
|
|
||||||
#
|
|
||||||
def pretty
|
|
||||||
"#{port} (#{proto})"
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# The protocol this service is using, such as 'tcp'.
|
|
||||||
#
|
|
||||||
attr_reader :proto
|
|
||||||
#
|
|
||||||
# The port this service is listening on, if applicable.
|
|
||||||
#
|
|
||||||
attr_reader :port
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
attr_writer :proto, :port # :nodoc:
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,28 +0,0 @@
|
||||||
module Msf
|
|
||||||
class Recon
|
|
||||||
|
|
||||||
require 'msf/core/recon/attribute/group'
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This mixin provides an abstract interface to the ``context'' parameter that
|
|
||||||
# is passed around to the recon event handlers. Instances of this are meant
|
|
||||||
# to contain data that is specific to the event being reported and is meant to
|
|
||||||
# be conveyed in a form that allows other recon modules to only pay attention
|
|
||||||
# to the things that it cares about. For instance, one recon module may wish
|
|
||||||
# to allow other recon modules to re-use the TCP connection it established to
|
|
||||||
# a host for future probing. This connection instance would be conveyed
|
|
||||||
# through the event context in a known attribute.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class EventContext < Attribute::Group
|
|
||||||
|
|
||||||
#
|
|
||||||
# This named attribute can be used to pass a connection handle between
|
|
||||||
# recon modules when certain events occur.
|
|
||||||
#
|
|
||||||
def_attr :connection
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,21 +0,0 @@
|
||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
|
||||||
|
|
||||||
require 'test/unit'
|
|
||||||
require 'msf/core'
|
|
||||||
require 'msf/core/recon/event_context'
|
|
||||||
|
|
||||||
class Msf::Recon::EventContext::UnitTest < Test::Unit::TestCase
|
|
||||||
|
|
||||||
Klass = Msf::Recon::EventContext
|
|
||||||
|
|
||||||
def test_target
|
|
||||||
e = Klass.new
|
|
||||||
|
|
||||||
assert_not_nil(e)
|
|
||||||
e.connection = 4
|
|
||||||
assert_equal(4, e.connection)
|
|
||||||
assert_equal(4, e.get_attribute('connection'))
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,219 +0,0 @@
|
||||||
require 'thread'
|
|
||||||
require 'msf/core/recon'
|
|
||||||
|
|
||||||
module Msf
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# The states that a host can be in.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
module HostState
|
|
||||||
#
|
|
||||||
# The host is alive.
|
|
||||||
#
|
|
||||||
Alive = "alive"
|
|
||||||
#
|
|
||||||
# The host is dead.
|
|
||||||
#
|
|
||||||
Dead = "down"
|
|
||||||
#
|
|
||||||
# The host state is unknown.
|
|
||||||
#
|
|
||||||
Unknown = "unknown"
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# The states that a service can be in.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
module ServiceState
|
|
||||||
#
|
|
||||||
# The service is alive.
|
|
||||||
#
|
|
||||||
Up = "up"
|
|
||||||
#
|
|
||||||
# The service is dead.
|
|
||||||
#
|
|
||||||
Dead = "down"
|
|
||||||
#
|
|
||||||
# The service state is unknown.
|
|
||||||
#
|
|
||||||
Unknown = "unknown"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This class manages the tracking of entities and the dispatching of events
|
|
||||||
# pertaining to recon information collection. When hosts are discovered, the
|
|
||||||
# recon module tracks them and dispatches the appropriate events to the
|
|
||||||
# framework event manager so that subscribers can be notified.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class ReconManager
|
|
||||||
|
|
||||||
include Framework::Offspring
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This mixin is used to extend Host entity instances such that the recon
|
|
||||||
# manager can track internal state information.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
module ExtendedHostState
|
|
||||||
#
|
|
||||||
# Tracks the number of manager state unknowns returned.
|
|
||||||
#
|
|
||||||
attr_accessor :_mgr_state_unknown
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(framework)
|
|
||||||
self.framework = framework;
|
|
||||||
self.host_hash = Hash.new
|
|
||||||
self.host_hash_mutex = Mutex.new
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Host reporting
|
|
||||||
#
|
|
||||||
##
|
|
||||||
|
|
||||||
#
|
|
||||||
# Reports a host as being in a given state by address.
|
|
||||||
#
|
|
||||||
def report_host_state(mod, address, state, context = nil)
|
|
||||||
# TODO: use the current thread's Comm as part of the hash key to support
|
|
||||||
# conflicting addresses in different networks (established through
|
|
||||||
# different comms).
|
|
||||||
hash_key = host_hash_key(address)
|
|
||||||
|
|
||||||
# If a host already exists with this information, then check to see what
|
|
||||||
# status we received.
|
|
||||||
if (host = host_hash[hash_key])
|
|
||||||
if (state == HostState::Unknown)
|
|
||||||
host._mgr_state_unknown += 1
|
|
||||||
elsif (state == HostState::Dead)
|
|
||||||
dead_host(host, context)
|
|
||||||
else
|
|
||||||
host._mgr_state_unknown = 0
|
|
||||||
end
|
|
||||||
# Otherwise, if we have no host yet, get one and start handling it.
|
|
||||||
elsif (state == HostState::Alive)
|
|
||||||
host = Recon::Entity::Host.new(address)
|
|
||||||
|
|
||||||
new_host(hash_key, host, context)
|
|
||||||
end
|
|
||||||
|
|
||||||
# TODO: evalulate _mgr_state_unknown to determine if the host should be
|
|
||||||
# dead
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method reports a host's service state.
|
|
||||||
#
|
|
||||||
def report_service_state(mod, host, proto, port, state, context = nil)
|
|
||||||
|
|
||||||
# If the supplied host object has not yet been registered, do so now.
|
|
||||||
# This occurs when a service module happens to discover a host that was
|
|
||||||
# not originally thought to have existed
|
|
||||||
if (host.needs_register != false and
|
|
||||||
state == ServiceState::Up)
|
|
||||||
new_host(host_hash_key(host.address), host, context)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Define the service entity name
|
|
||||||
ename = "port_#{port}"
|
|
||||||
|
|
||||||
# Get the proto subcontainer for this entity, or add it if it isn't
|
|
||||||
# already defined.
|
|
||||||
p = host.services.add_entity_subcontainer(proto.downcase)
|
|
||||||
|
|
||||||
# Now that we have the protocol subcontainer, get the service instance
|
|
||||||
# associated witht he port (if one has been defined).
|
|
||||||
if (service = p.get_entity(ename))
|
|
||||||
# TODO: update
|
|
||||||
elsif (state == ServiceState::Up)
|
|
||||||
service = Recon::Entity::Service.new(proto, port)
|
|
||||||
|
|
||||||
p.add_entity("port_#{ename}", service)
|
|
||||||
|
|
||||||
# TODO: Notify
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns the host object associated with the supplied address.
|
|
||||||
# If one does not exist, it is created.
|
|
||||||
#
|
|
||||||
def get_host(address)
|
|
||||||
host_hash[host_hash_key(address)]
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method iterates the host hash calling the supplied block with the
|
|
||||||
# address and host instances of each entry in the host hash.
|
|
||||||
#
|
|
||||||
def each_host(&block)
|
|
||||||
host_hash.each_pair { |k, host|
|
|
||||||
block.call(host.address, host)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
#
|
|
||||||
# This method returns the hash key to use with the supplied address.
|
|
||||||
#
|
|
||||||
# TODO: make this use comm info
|
|
||||||
#
|
|
||||||
def host_hash_key(address)
|
|
||||||
address
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Called when a new host is detected.
|
|
||||||
#
|
|
||||||
def new_host(hash_key, host, context)
|
|
||||||
# Extend the host and initialize it properly
|
|
||||||
host.extend(ExtendedHostState)
|
|
||||||
|
|
||||||
host._mgr_state_unknown = 0
|
|
||||||
|
|
||||||
# Add the host tot he host hash
|
|
||||||
host_hash_mutex.synchronize {
|
|
||||||
self.host_hash[hash_key] = host
|
|
||||||
}
|
|
||||||
|
|
||||||
ilog("recon: New host discoverered: #{host.pretty}", "core",
|
|
||||||
LEV_1)
|
|
||||||
|
|
||||||
# Now that the host has registered, we can't flag it up.
|
|
||||||
host.needs_register = false
|
|
||||||
|
|
||||||
# Notify any host event subscribes of our new found fate.
|
|
||||||
framework.events.on_host_changed(
|
|
||||||
context, host, ReconEvent::EntityChangeType::Add)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Processes cleanup necessary when a dead host is encountered.
|
|
||||||
#
|
|
||||||
def dead_host(host, context)
|
|
||||||
host_hash_mutex.synchronize {
|
|
||||||
self.host_hash.delete(host)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Notify any host event subscribers that the host has died.
|
|
||||||
framework.events.on_host_changed(
|
|
||||||
context, host, ReconEvent::EntityChangeType::Remove)
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_accessor :host_hash
|
|
||||||
attr_accessor :host_hash_mutex
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
module Msf
|
||||||
|
module Ui
|
||||||
|
module Console
|
||||||
|
module CommandDispatcher
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# Recon module command dispatcher.
|
||||||
|
#
|
||||||
|
###
|
||||||
|
class Auxiliary
|
||||||
|
|
||||||
|
include Msf::Ui::Console::ModuleCommandDispatcher
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns the hash of commands specific to auxiliary modules.
|
||||||
|
#
|
||||||
|
def commands
|
||||||
|
{
|
||||||
|
"run" => "Initiates the auxiliary module",
|
||||||
|
}.merge( (mod ? mod.auxiliary_commands : {}) )
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Allow modules to define their own commands :-)
|
||||||
|
#
|
||||||
|
def method_missing(meth, *args)
|
||||||
|
if (mod and mod.respond_to?(meth.to_s))
|
||||||
|
return mod.send(meth.to_s, *args)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Returns the command dispatcher name.
|
||||||
|
#
|
||||||
|
def name
|
||||||
|
"Auxiliary"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Executes the standard 'run' command
|
||||||
|
#
|
||||||
|
def cmd_run(*args)
|
||||||
|
begin
|
||||||
|
mod.run_simple(
|
||||||
|
'LocalInput' => driver.input,
|
||||||
|
'LocalOutput' => driver.output)
|
||||||
|
rescue
|
||||||
|
log_error("Auxiliary failed: #{$!}")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end end end end
|
|
@ -2,7 +2,7 @@ require 'msf/ui/console/command_dispatcher/encoder'
|
||||||
require 'msf/ui/console/command_dispatcher/exploit'
|
require 'msf/ui/console/command_dispatcher/exploit'
|
||||||
require 'msf/ui/console/command_dispatcher/nop'
|
require 'msf/ui/console/command_dispatcher/nop'
|
||||||
require 'msf/ui/console/command_dispatcher/payload'
|
require 'msf/ui/console/command_dispatcher/payload'
|
||||||
require 'msf/ui/console/command_dispatcher/recon'
|
require 'msf/ui/console/command_dispatcher/auxiliary'
|
||||||
|
|
||||||
module Msf
|
module Msf
|
||||||
module Ui
|
module Ui
|
||||||
|
@ -107,7 +107,7 @@ class Core
|
||||||
banner += "#{framework.stats.num_encoders} encoders - "
|
banner += "#{framework.stats.num_encoders} encoders - "
|
||||||
banner += "#{framework.stats.num_nops} nops\n"
|
banner += "#{framework.stats.num_nops} nops\n"
|
||||||
banner += " =[ "
|
banner += " =[ "
|
||||||
banner += "#{framework.stats.num_recon} recon\n"
|
banner += "#{framework.stats.num_auxiliary} aux\n"
|
||||||
banner += "\n"
|
banner += "\n"
|
||||||
|
|
||||||
# Display the banner
|
# Display the banner
|
||||||
|
@ -756,7 +756,7 @@ class Core
|
||||||
show_nops
|
show_nops
|
||||||
show_exploits
|
show_exploits
|
||||||
show_payloads
|
show_payloads
|
||||||
show_recon
|
show_auxiliary
|
||||||
show_plugins
|
show_plugins
|
||||||
when 'encoders'
|
when 'encoders'
|
||||||
show_encoders
|
show_encoders
|
||||||
|
@ -766,8 +766,8 @@ class Core
|
||||||
show_exploits
|
show_exploits
|
||||||
when 'payloads'
|
when 'payloads'
|
||||||
show_payloads
|
show_payloads
|
||||||
when 'recon'
|
when 'aux'
|
||||||
show_recon
|
show_auxiliary
|
||||||
when 'options'
|
when 'options'
|
||||||
if (mod)
|
if (mod)
|
||||||
show_options(mod)
|
show_options(mod)
|
||||||
|
@ -802,7 +802,7 @@ class Core
|
||||||
# Tab completion for the show command
|
# Tab completion for the show command
|
||||||
#
|
#
|
||||||
def cmd_show_tabs(str, words)
|
def cmd_show_tabs(str, words)
|
||||||
res = %w{all encoders nops exploits payloads recon plugins}
|
res = %w{all encoders nops exploits payloads aux plugins}
|
||||||
if (active_module)
|
if (active_module)
|
||||||
res.concat(%w{ options advanced evasion targets })
|
res.concat(%w{ options advanced evasion targets })
|
||||||
end
|
end
|
||||||
|
@ -943,8 +943,8 @@ class Core
|
||||||
dispatcher = Nop
|
dispatcher = Nop
|
||||||
when MODULE_PAYLOAD
|
when MODULE_PAYLOAD
|
||||||
dispatcher = Payload
|
dispatcher = Payload
|
||||||
when MODULE_RECON
|
when MODULE_AUX
|
||||||
dispatcher = Recon
|
dispatcher = Auxiliary
|
||||||
else
|
else
|
||||||
print_error("Unsupported module type: #{mod.type}")
|
print_error("Unsupported module type: #{mod.type}")
|
||||||
return false
|
return false
|
||||||
|
@ -1153,8 +1153,8 @@ protected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_recon # :nodoc:
|
def show_auxiliary # :nodoc:
|
||||||
show_module_set("Recon", framework.recon)
|
show_module_set("Auxiliary", framework.auxiliary)
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_options(mod) # :nodoc:
|
def show_options(mod) # :nodoc:
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
module Msf
|
|
||||||
module Ui
|
|
||||||
module Console
|
|
||||||
module CommandDispatcher
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Recon module command dispatcher.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Recon
|
|
||||||
|
|
||||||
include Msf::Ui::Console::ModuleCommandDispatcher
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the hash of commands specific to recon modules.
|
|
||||||
#
|
|
||||||
def commands
|
|
||||||
{
|
|
||||||
"discover" => "Initiates the recon discovery process for this module",
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Returns the command dispatcher name.
|
|
||||||
#
|
|
||||||
def name
|
|
||||||
"Recon"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Starts discovering like a good recon module should.
|
|
||||||
#
|
|
||||||
def cmd_discover(*args)
|
|
||||||
begin
|
|
||||||
mod.discover_simple(
|
|
||||||
'LocalInput' => driver.input,
|
|
||||||
'LocalOutput' => driver.output)
|
|
||||||
rescue
|
|
||||||
log_error("Recon failed: #{$!}")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end end end end
|
|
|
@ -189,10 +189,11 @@ module DispatcherShell
|
||||||
entries = dispatcher_stack.length
|
entries = dispatcher_stack.length
|
||||||
|
|
||||||
dispatcher_stack.each { |dispatcher|
|
dispatcher_stack.each { |dispatcher|
|
||||||
begin
|
next if not dispatcher.respond_to?('commands')
|
||||||
if (dispatcher.respond_to?('cmd_' + method))
|
|
||||||
run_command(dispatcher, method, arguments)
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
if (dispatcher.commands.has_key?(method))
|
||||||
|
run_command(dispatcher, method, arguments)
|
||||||
found = true
|
found = true
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
|
@ -225,7 +226,7 @@ module DispatcherShell
|
||||||
# Runs the supplied command on the given dispatcher.
|
# Runs the supplied command on the given dispatcher.
|
||||||
#
|
#
|
||||||
def run_command(dispatcher, method, arguments)
|
def run_command(dispatcher, method, arguments)
|
||||||
eval("dispatcher.#{'cmd_' + method}(*arguments)")
|
dispatcher.send('cmd_' + method, *arguments)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
Loading…
Reference in New Issue