From d8a089a1b39bbc986b27b547aeea52091270b548 Mon Sep 17 00:00:00 2001 From: passbe Date: Wed, 24 Aug 2011 09:33:22 +0000 Subject: [PATCH] Reworked timed API system. You now must use the BeEF::API::Registra.register() to hook into timed API calls. This will speed up the framework and allow paramater matching for API hooks. git-svn-id: https://beef.googlecode.com/svn/trunk@1235 b87d56ec-f9c0-11de-8c8a-61c5e9addfc9 --- beef | 4 +- core/api.rb | 107 ++++++++++++++++++++------- core/core.rb | 1 + core/extensions.rb | 2 +- core/main/configuration.rb | 2 +- core/main/handlers/hookedbrowsers.rb | 2 +- core/main/migration.rb | 2 +- core/main/network_stack/api.rb | 6 +- core/main/server.rb | 4 +- core/module.rb | 8 +- core/modules.rb | 2 +- extensions/admin_ui/api/handler.rb | 4 +- extensions/demos/api.rb | 3 +- extensions/events/api.rb | 5 +- extensions/initialization/api.rb | 6 +- extensions/proxy/api.rb | 7 +- extensions/requester/api.rb | 5 +- extensions/xssrays/api.rb | 8 +- 18 files changed, 118 insertions(+), 60 deletions(-) diff --git a/beef b/beef index a21cf4adb..34ec744d9 100755 --- a/beef +++ b/beef @@ -89,8 +89,6 @@ BeEF::Core::Migration.instance.update_db! http_hook_server = BeEF::Core::Server.instance http_hook_server.prepare - - # prints information back to the user before running the server BeEF::Extension::Console::Banners.print_loaded_extensions @@ -99,7 +97,7 @@ BeEF::Extension::Console::Banners.print_network_interfaces_count BeEF::Extension::Console::Banners.print_network_interfaces_routes # We dynamically get the list of all browser hook handler using the API and register them -BeEF::API.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) +BeEF::API::Registra.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) # We check now for whether we load the Console Shell or not if config.get("beef.extension.console.shell.enable") == true diff --git a/core/api.rb b/core/api.rb index 11c7995f7..f15724304 100644 --- a/core/api.rb +++ b/core/api.rb @@ -17,37 +17,92 @@ module BeEF module API - # - # Calls a API fire against a certain class / module (c) method (m) with n parameters (*args) - # - def self.fire(c, m, *args) - mods = c.extended_in_modules - if mods.length > 0 - if self.verify_api_path(c, m) and c.ancestors[0].to_s > "BeEF::API" - method = self.get_api_path(c, m) - mods.each do |mod| - begin - #Only used for API Development - #print_info "API: #{mod} fired #{method}" - mod.send method, *args - rescue Exception => e - print_error "API Fire Error: #{e.message} in #{mod.to_s}.#{method.to_s}()" - end - end + # Registra class to handle all registered timed API calls + class Registra + + include Singleton + + def initialize + @registry = [] + end + + # Register owner, c, method and matching params + def register(owner, c, method, params = []) + if not self.registered?(owner, c, method) + @registry << { + 'owner' => owner, + 'class' => c, + 'method' => method, + 'params' => params + } else - print_error "API Path not defined for Class: "+c.to_s+" Method: "+m.to_s + print_debug "API Registra: Attempting to re-register API call #{c.to_s} :#{method.to_s}" end end - end + + # returns boolean whether or not any owner has registered + def registered?(owner, c, method) + @registry.each{|r| + if r['owner'] == owner and r['class'] == c and r['method'] == method + return true + end + } + return false + end - # Verifies that the api_path has been regitered - def self.verify_api_path(c, m) - return (c.const_defined?('API_PATHS') and c.const_get('API_PATHS').has_key?(m)) - end + # unregister API call from owner, class and method + def unregister(owner, c, method) + @registry.delete_if{|r| + r['owner'] == owner and r['class'] == c and r['method'] == method + } + end + + # gets all owners registered to an API call + def get_owners(c, method, params = []) + owners = [] + @registry.each{|r| + if r['class'] == c and r['method'] == method + if r['params'].length == 0 or r['params'] == params + owners << r['owner'] + end + end + } + return owners + end + + # Verifies that the api_path has been regitered + def verify_api_path(c, m) + return (c.const_defined?('API_PATHS') and c.const_get('API_PATHS').has_key?(m)) + end + + # Gets the sym set to the api_path + def get_api_path(c, m) + return (self.verify_api_path(c, m)) ? c.const_get('API_PATHS')[m] : nil; + end + + # + # Calls a API fire against a certain class / module (c) method (m) with n parameters (*args) + # + def fire(c, m, *args) + mods = self.get_owners(c, m, args) + if mods.length > 0 + if self.verify_api_path(c, m) and c.ancestors[0].to_s > "BeEF::API" + method = self.get_api_path(c, m) + mods.each do |mod| + begin + #Only used for API Development + #print_info "API: #{mod} fired #{method}" + mod.send method, *args + rescue Exception => e + print_error "API Fire Error: #{e.message} in #{mod.to_s}.#{method.to_s}()" + end + end + else + print_error "API Path not defined for Class: "+c.to_s+" Method: "+m.to_s + end + end + end - # Gets the sym set to the api_path - def self.get_api_path(c, m) - return (self.verify_api_path(c, m)) ? c.const_get('API_PATHS')[m] : nil; end end diff --git a/core/core.rb b/core/core.rb index 191ff526c..1e5cfd58e 100644 --- a/core/core.rb +++ b/core/core.rb @@ -68,3 +68,4 @@ require 'core/main/network_stack/api' # Include the distributed engine require 'core/main/distributed_engine/models/rules' + diff --git a/core/extensions.rb b/core/extensions.rb index a7fad2438..656e0173d 100644 --- a/core/extensions.rb +++ b/core/extensions.rb @@ -33,7 +33,7 @@ module Extensions BeEF::Extension.load(k) } # API post extension load - BeEF::API.fire(BeEF::API::Extensions, 'post_load') + BeEF::API::Registra.instance.fire(BeEF::API::Extensions, 'post_load') end end diff --git a/core/main/configuration.rb b/core/main/configuration.rb index a22f434a7..a4feababf 100644 --- a/core/main/configuration.rb +++ b/core/main/configuration.rb @@ -115,7 +115,7 @@ module Core y['beef']['module'][y['beef']['module'].keys.first]['path'] = cf.gsub(/config\.yaml/, '').gsub(/#{$root_dir}\//, '') @config = y.deep_merge(@config) # API call for post module config load - BeEF::API.fire(BeEF::API::Configuration, 'module_configuration_load', y['beef']['module'].keys.first) + BeEF::API::Registra.instance.fire(BeEF::API::Configuration, 'module_configuration_load', y['beef']['module'].keys.first) end end end diff --git a/core/main/handlers/hookedbrowsers.rb b/core/main/handlers/hookedbrowsers.rb index e01700f73..9c9fffa9e 100644 --- a/core/main/handlers/hookedbrowsers.rb +++ b/core/main/handlers/hookedbrowsers.rb @@ -84,7 +84,7 @@ module Handlers # # We dynamically get the list of all browser hook handler using the API and register them # - BeEF::API.fire(BeEF::API::Server::Hook, 'pre_hook_send', hooked_browser, @body, @params, @request, @response) + BeEF::API::Registra.instance.fire(BeEF::API::Server::Hook, 'pre_hook_send', hooked_browser, @body, @params, @request, @response) end # set response headers and body diff --git a/core/main/migration.rb b/core/main/migration.rb index 70300bf7e..5124e2e59 100644 --- a/core/main/migration.rb +++ b/core/main/migration.rb @@ -51,7 +51,7 @@ module Core } # Call Migration method - BeEF::API.fire(BeEF::API::Migration, 'migrate_commands') + BeEF::API::Registra.instance.fire(BeEF::API::Migration, 'migrate_commands') end end diff --git a/core/main/network_stack/api.rb b/core/main/network_stack/api.rb index 6b9b0223d..955db5c69 100644 --- a/core/main/network_stack/api.rb +++ b/core/main/network_stack/api.rb @@ -18,9 +18,6 @@ module Core module NetworkStack module RegisterHttpHandler - # use of the API right here - extend BeEF::API::Server - # # Register the http handler for the network stack # @@ -31,6 +28,9 @@ module NetworkStack end + # Register core API calls + BeEF::API::Registra.instance.register(BeEF::Core::NetworkStack::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') + end end end diff --git a/core/main/server.rb b/core/main/server.rb index 07101cb4d..dfb20f830 100644 --- a/core/main/server.rb +++ b/core/main/server.rb @@ -96,7 +96,7 @@ module Core # # We dynamically get the list of all http handler using the API and register them # - BeEF::API.fire(BeEF::API::Server, 'mount_handler', self) + BeEF::API::Registra.instance.fire(BeEF::API::Server, 'mount_handler', self) end end @@ -150,12 +150,14 @@ module Core else @http_server.mount url, http_handler_class, *args end + print_debug("Server: mounted handler '#{url}'") else if args == nil mounts[url] = http_handler_class else mounts[url] = http_handler_class, *args end + print_debug("Server: mounted handler '#{url}'") end end diff --git a/core/module.rb b/core/module.rb index b14e61cf1..e3a219e00 100644 --- a/core/module.rb +++ b/core/module.rb @@ -54,7 +54,7 @@ module Module # Soft Load, loads the module without requiring the module.rb file def self.soft_load(mod) # API call for pre-soft-load module - BeEF::API.fire(BeEF::API::Module, 'pre_soft_load', mod) + BeEF::API::Registra.instance.fire(BeEF::API::Module, 'pre_soft_load', mod) config = BeEF::Core::Configuration.instance if not config.get("beef.module.#{mod}.loaded") if File.exists?(config.get('beef.module.'+mod+'.path')+'/module.rb') @@ -62,7 +62,7 @@ module Module self.parse_targets(mod) print_debug "Soft Load module: '#{mod}'" # API call for post-soft-load module - BeEF::API.fire(BeEF::API::Module, 'post_soft_load', mod) + BeEF::API::Registra.instance.fire(BeEF::API::Module, 'post_soft_load', mod) return true else print_debug "Unable to locate module file: #{config.get('beef.module.'+mod+'.path')}module.rb" @@ -75,7 +75,7 @@ module Module # Hard Load, loads a pre-soft-loaded module by requiring the module.rb def self.hard_load(mod) # API call for pre-hard-load module - BeEF::API.fire(BeEF::API::Module, 'pre_hard_load', mod) + BeEF::API::Registra.instance.fire(BeEF::API::Module, 'pre_hard_load', mod) config = BeEF::Core::Configuration.instance if self.is_enabled(mod) begin @@ -87,7 +87,7 @@ module Module BeEF::Core::Configuration.instance.set('beef.module.'+mod+'.loaded', true) print_debug "Hard Load module: '#{mod.to_s}'" # API call for post-hard-load module - BeEF::API.fire(BeEF::API::Module, 'post_hard_load', mod) + BeEF::API::Registra.instance.fire(BeEF::API::Module, 'post_hard_load', mod) return true else print_error "Hard loaded module '#{mod.to_s}' but the class BeEF::Core::Commands::#{mod.capitalize} does not exist" diff --git a/core/modules.rb b/core/modules.rb index c4a15f965..0996c79c8 100644 --- a/core/modules.rb +++ b/core/modules.rb @@ -47,7 +47,7 @@ module Modules self.get_enabled.each { |k,v| BeEF::Module.soft_load(k) } - BeEF::API.fire(BeEF::API::Modules, 'post_soft_load') + BeEF::API::Registra.instance.fire(BeEF::API::Modules, 'post_soft_load') end end end diff --git a/extensions/admin_ui/api/handler.rb b/extensions/admin_ui/api/handler.rb index 42281e05d..28a293db7 100644 --- a/extensions/admin_ui/api/handler.rb +++ b/extensions/admin_ui/api/handler.rb @@ -23,8 +23,7 @@ module API # module Handler - # use of the API right here - extend BeEF::API::Server + BeEF::API::Registra.instance.register(BeEF::Extension::AdminUI::API::Handler, BeEF::API::Server, 'mount_handler') # # This function gets called automatically by the server. @@ -37,7 +36,6 @@ module API Dir["#{$root_dir}/extensions/admin_ui/controllers/**/*.rb"].each { |http_module| require http_module mod_name = File.basename http_module, '.rb' - print_debug("Registering controller [#{mod_name}] for extension [AdminUI]") beef_server.mount("/ui/#{mod_name}", true, BeEF::Extension::AdminUI::Handlers::UI, mod_name) } diff --git a/extensions/demos/api.rb b/extensions/demos/api.rb index cb9ed748d..1bd691982 100644 --- a/extensions/demos/api.rb +++ b/extensions/demos/api.rb @@ -19,7 +19,7 @@ module Demos module RegisterHttpHandlers - extend BeEF::API::Server + BeEF::API::Registra.instance.register(BeEF::Extension::Demos::RegisterHttpHandlers, BeEF::API::Server, 'mount_handler') def self.mount_handler(beef_server) # mount the handler to support the demos @@ -29,6 +29,7 @@ module Demos end end + end end diff --git a/extensions/events/api.rb b/extensions/events/api.rb index b61aa4327..e76794614 100644 --- a/extensions/events/api.rb +++ b/extensions/events/api.rb @@ -18,8 +18,9 @@ module Extension module Events module RegisterHttpHandler - # use of the API right here - extend BeEF::API::Server + + # Register API calls + BeEF::API::Registra.instance.register(BeEF::Extension::Events::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') # # Mounts the http handlers for the events extension. We use that to retrieve stuff diff --git a/extensions/initialization/api.rb b/extensions/initialization/api.rb index cf0312efd..92760b163 100644 --- a/extensions/initialization/api.rb +++ b/extensions/initialization/api.rb @@ -18,8 +18,9 @@ module Extension module Initialization module RegisterHttpHandler - # use of the API right here - extend BeEF::API::Server + + # Register API calls + BeEF::API::Registra.instance.register(BeEF::Extension::Initialization::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') # # Register the http handler for the initialization script that retrieves @@ -30,6 +31,7 @@ module Initialization end end + end end diff --git a/extensions/proxy/api.rb b/extensions/proxy/api.rb index 220c77108..f245de516 100644 --- a/extensions/proxy/api.rb +++ b/extensions/proxy/api.rb @@ -19,9 +19,9 @@ module Proxy module API module RegisterHttpHandler - - # use of the API - extend BeEF::API::Server + + BeEF::API::Registra.instance.register(BeEF::Extension::Proxy::API::RegisterHttpHandler, BeEF::API::Server, 'pre_http_start') + BeEF::API::Registra.instance.register(BeEF::Extension::Proxy::API::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') def self.pre_http_start(http_hook_server) proxy = BeEF::Extension::Proxy::HttpProxyZombie.instance @@ -36,6 +36,7 @@ module API end + end end end diff --git a/extensions/requester/api.rb b/extensions/requester/api.rb index 1bc12d65c..6bfb6adc8 100644 --- a/extensions/requester/api.rb +++ b/extensions/requester/api.rb @@ -19,8 +19,7 @@ module Requester module RegisterHttpHandler - # use of the API - extend BeEF::API::Server + BeEF::API::Registra.instance.register(BeEF::Extension::Requester::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') # We register the http handler for the requester. # This http handler will retrieve the http responses for all requests @@ -32,7 +31,7 @@ module Requester module RegisterPreHookCallback - extend BeEF::API::Server::Hook + BeEF::API::Registra.instance.register(BeEF::Extension::Requester::RegisterPreHookCallback, BeEF::API::Server::Hook, 'pre_hook_send') def self.pre_hook_send(hooked_browser, body, params, request, response) dhook = BeEF::Extension::Requester::API::Hook.new diff --git a/extensions/xssrays/api.rb b/extensions/xssrays/api.rb index 7302c2bf6..03879c8b7 100644 --- a/extensions/xssrays/api.rb +++ b/extensions/xssrays/api.rb @@ -18,9 +18,8 @@ module Extension module Xssrays module RegisterHttpHandler - - # use of the API - extend BeEF::API::Server + + BeEF::API::Registra.instance.register(BeEF::Extension::Xssrays::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') # We register the http handler for the requester. # This http handler will retrieve the http responses for all requests @@ -30,9 +29,10 @@ module Xssrays end + module RegisterPreHookCallback - extend BeEF::API::Server::Hook + BeEF::API::Registra.instance.register(BeEF::Extension::Xssrays::RegisterPreHookCallback, BeEF::API::Server, 'pre_hook_send') # checks at every polling if there are new scans to be started def self.pre_hook_send(hooked_browser, body, params, request, response)