diff --git a/core/api.rb b/core/api.rb index aeafd6b40..3ad1bf391 100644 --- a/core/api.rb +++ b/core/api.rb @@ -15,172 +15,172 @@ # module BeEF -module API + module API # Registrar class to handle all registered timed API calls class Registrar - include Singleton - - # Create registrar - def initialize - @registry = [] - @count = 1 - end + include Singleton - # Register timed API calls to an owner - # @param [Class] owner the owner of the API hook - # @param [Class] c the API class the owner would like to hook into - # @param [String] method the method of the class the owner would like to execute - # @param [Array] params an array of parameters that need to be matched before the owner will be called - def register(owner, c, method, params = []) - if self.verify_api_path(c, method) - if not self.registered?(owner, c, method, params) - id = @count - @registry << { - 'id' => id, - 'owner' => owner, - 'class' => c, - 'method' => method, - 'params' => params - } - @count += 1 - return id - else - print_debug "API Registrar: Attempting to re-register API call #{c.to_s} :#{method.to_s}" - end - else - print_error "API Registrar: Attempted to register non-existant API method #{c.to_s} :#{method.to_s}" - end - end - - # Tests whether the owner is registered for an API hook - # @param [Class] owner the owner of the API hook - # @param [Class] c the API class - # @param [String] method the method of the class - # @param [Array] params an array of parameters that need to be matched - # @return [Boolean] whether or not the owner is registered - # @todo Change the param matching to use the new :is_matched_params?() method - Issue #479 - def registered?(owner, c, method, params = []) - @registry.each{|r| - if r['owner'] == owner and r['class'] == c and r['method'] == method and params == r['params'] - return true - end + # Create registrar + def initialize + @registry = [] + @count = 1 + end + + # Register timed API calls to an owner + # @param [Class] owner the owner of the API hook + # @param [Class] c the API class the owner would like to hook into + # @param [String] method the method of the class the owner would like to execute + # @param [Array] params an array of parameters that need to be matched before the owner will be called + def register(owner, c, method, params = []) + if self.verify_api_path(c, method) + if not self.registered?(owner, c, method, params) + id = @count + @registry << { + 'id' => id, + 'owner' => owner, + 'class' => c, + 'method' => method, + 'params' => params } - return false + @count += 1 + return id + else + print_debug "API Registrar: Attempting to re-register API call #{c.to_s} :#{method.to_s}" + end + else + print_error "API Registrar: Attempted to register non-existant API method #{c.to_s} :#{method.to_s}" end + end - # Match a timed API call to determine if an API.fire() is required - # @param [Class] c the target API class - # @param [String] method the method of the target API class - # @param [Array] params an array of parameters that need to be matched - # @return [Boolean] whether or not the arguments match an entry in the API registry - def matched?(c, method, params = []) - @registry.each{|r| - if r['class'] == c and r['method'] == method and self.is_matched_params?(r, params) - return true - end - } - return false - end - - # Un-registers an API hook - # @param [Integer] id the ID of the API hook - def unregister(id) - @registry.delete_if{|r| - r['id'] == id - } - end - - # Retrieves all the owners and ID's of an API hook - # @param [Class] c the target API class - # @param [String] method the method of the target API class - # @param [Array] params an array of parameters that need to be matched - # @return [Array] an array of hashes consisting of two keys :owner and :id - def get_owners(c, method, params = []) - owners = [] - @registry.each{|r| - if r['class'] == c and r['method'] == method - if self.is_matched_params?(r, params) - owners << { :owner => r['owner'], :id => r['id']} - end - end - } - return owners - end - - # Verifies that the api_path has been regitered - # Verifies the API path has been registered. - # @note This is a security precaution - # @param [Class] c the target API class to verify - # @param [String] m the target method to verify - def verify_api_path(c, m) - return (c.const_defined?('API_PATHS') and c.const_get('API_PATHS').has_key?(m)) - end - - # Retrieves the registered symbol reference for an API hook - # @param [Class] c the target API class to verify - # @param [String] m the target method to verify - # @return [Symbol] the API path - def get_api_path(c, m) - return (self.verify_api_path(c, m)) ? c.const_get('API_PATHS')[m] : nil; - end - - # Matches stored API params to params - # @note If a stored API parameter has a NilClass the parameter matching is skipped for that parameter - # @note By default this method returns true, this is either because the API.fire() did not include any parameters or there were no parameters defined for this registry entry - # @param [Hash] reg hash of registry element, must contain 'params' key - # @param [Array] params array of parameters to be compared to the stored parameters - # @return [Boolean] whether params matches the stored API parameters - def is_matched_params?(reg, params) - stored = reg['params'] - if stored.length == params.length - matched = true - stored.each_index{|i| - next if stored[i] == nil - if not stored[i] == params[i] - matched = false - end - } - return false if not matched - end + # Tests whether the owner is registered for an API hook + # @param [Class] owner the owner of the API hook + # @param [Class] c the API class + # @param [String] method the method of the class + # @param [Array] params an array of parameters that need to be matched + # @return [Boolean] whether or not the owner is registered + # @todo Change the param matching to use the new :is_matched_params?() method - Issue #479 + def registered?(owner, c, method, params = []) + @registry.each{|r| + if r['owner'] == owner and r['class'] == c and r['method'] == method and params == r['params'] return true - end + end + } + return false + end - # Fires all owners registered to this API hook - # @param [Class] c the target API class - # @param [String] m the target API method - # @param [Array] *args parameters passed for the API call - # @return [Hash, NilClass] returns either a Hash of :api_id and :data if the owners return data, otherwise NilClass - def fire(c, m, *args) - mods = self.get_owners(c, m, args) - if mods.length > 0 - data = [] - 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 (very verbose) - #print_info "API: #{mod} fired #{method}" - result = mod[:owner].method(method).call(*args) - if not result == nil - data << {:api_id => mod[:id], :data => result} - end - 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:#{method.to_s}" - end - return data + # Match a timed API call to determine if an API.fire() is required + # @param [Class] c the target API class + # @param [String] method the method of the target API class + # @param [Array] params an array of parameters that need to be matched + # @return [Boolean] whether or not the arguments match an entry in the API registry + def matched?(c, method, params = []) + @registry.each{|r| + if r['class'] == c and r['method'] == method and self.is_matched_params?(r, params) + return true + end + } + return false + end + + # Un-registers an API hook + # @param [Integer] id the ID of the API hook + def unregister(id) + @registry.delete_if{|r| + r['id'] == id + } + end + + # Retrieves all the owners and ID's of an API hook + # @param [Class] c the target API class + # @param [String] method the method of the target API class + # @param [Array] params an array of parameters that need to be matched + # @return [Array] an array of hashes consisting of two keys :owner and :id + def get_owners(c, method, params = []) + owners = [] + @registry.each{|r| + if r['class'] == c and r['method'] == method + if self.is_matched_params?(r, params) + owners << { :owner => r['owner'], :id => r['id']} end - return nil + end + } + return owners + end + + # Verifies that the api_path has been regitered + # Verifies the API path has been registered. + # @note This is a security precaution + # @param [Class] c the target API class to verify + # @param [String] m the target method to verify + def verify_api_path(c, m) + return (c.const_defined?('API_PATHS') and c.const_get('API_PATHS').has_key?(m)) + end + + # Retrieves the registered symbol reference for an API hook + # @param [Class] c the target API class to verify + # @param [String] m the target method to verify + # @return [Symbol] the API path + def get_api_path(c, m) + return (self.verify_api_path(c, m)) ? c.const_get('API_PATHS')[m] : nil; + end + + # Matches stored API params to params + # @note If a stored API parameter has a NilClass the parameter matching is skipped for that parameter + # @note By default this method returns true, this is either because the API.fire() did not include any parameters or there were no parameters defined for this registry entry + # @param [Hash] reg hash of registry element, must contain 'params' key + # @param [Array] params array of parameters to be compared to the stored parameters + # @return [Boolean] whether params matches the stored API parameters + def is_matched_params?(reg, params) + stored = reg['params'] + if stored.length == params.length + matched = true + stored.each_index{|i| + next if stored[i] == nil + if not stored[i] == params[i] + matched = false + end + } + return false if not matched end + return true + end + + # Fires all owners registered to this API hook + # @param [Class] c the target API class + # @param [String] m the target API method + # @param [Array] *args parameters passed for the API call + # @return [Hash, NilClass] returns either a Hash of :api_id and :data if the owners return data, otherwise NilClass + def fire(c, m, *args) + mods = self.get_owners(c, m, args) + if mods.length > 0 + data = [] + 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 (very verbose) + #print_info "API: #{mod} fired #{method}" + result = mod[:owner].method(method).call(*args) + if not result == nil + data << {:api_id => mod[:id], :data => result} + end + 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:#{method.to_s}" + end + return data + end + return nil + end end - -end + + end end require 'core/api/module' diff --git a/core/extension.rb b/core/extension.rb index 9a77f6011..7b52fe344 100644 --- a/core/extension.rb +++ b/core/extension.rb @@ -14,27 +14,27 @@ # limitations under the License. # module BeEF -module Extension + module Extension # Checks to see if extension is set inside the configuration # @param [String] ext the extension key # @return [Boolean] whether or not the extension exists in BeEF's configuration def self.is_present(ext) - return BeEF::Core::Configuration.instance.get('beef.extension').has_key?(ext.to_s) + return BeEF::Core::Configuration.instance.get('beef.extension').has_key?(ext.to_s) end # Checks to see if extension is enabled in configuration # @param [String] ext the extension key # @return [Boolean] whether or not the extension is enabled def self.is_enabled(ext) - return (self.is_present(ext) and BeEF::Core::Configuration.instance.get('beef.extension.'+ext.to_s+'.enable') == true) + return (self.is_present(ext) and BeEF::Core::Configuration.instance.get('beef.extension.'+ext.to_s+'.enable') == true) end # Checks to see if extension has been loaded # @param [String] ext the extension key # @return [Boolean] whether or not the extension is loaded def self.is_loaded(ext) - return (self.is_enabled(ext) and BeEF::Core::Configuration.instance.get('beef.extension.'+ext.to_s+'.loaded') == true) + return (self.is_enabled(ext) and BeEF::Core::Configuration.instance.get('beef.extension.'+ext.to_s+'.loaded') == true) end # Loads an extension @@ -42,14 +42,14 @@ module Extension # @return [Boolean] whether or not the extension loaded successfully # @todo Wrap the require() statement in a try catch block to allow BeEF to fail gracefully if there is a problem with that extension - Issue #480 def self.load(ext) - if File.exists?('extensions/'+ext+'/extension.rb') - require 'extensions/'+ext+'/extension.rb' - print_debug "Loaded extension: '#{ext}'" - BeEF::Core::Configuration.instance.set('beef.extension.'+ext+'.loaded', true) - return true - end - print_error "Unable to load extension '#{ext}'" - return false + if File.exists?('extensions/'+ext+'/extension.rb') + require 'extensions/'+ext+'/extension.rb' + print_debug "Loaded extension: '#{ext}'" + BeEF::Core::Configuration.instance.set('beef.extension.'+ext+'.loaded', true) + return true + end + print_error "Unable to load extension '#{ext}'" + return false end -end + end end diff --git a/core/extensions.rb b/core/extensions.rb index e3f4199ef..f5f2026f2 100644 --- a/core/extensions.rb +++ b/core/extensions.rb @@ -14,31 +14,31 @@ # limitations under the License. # module BeEF -module Extensions + module Extensions # Returns configuration of all enabled extensions # @return [Array] an array of extension configuration hashes that are enabled def self.get_enabled - return BeEF::Core::Configuration.instance.get('beef.extension').select { |k,v| v['enable'] == true } + return BeEF::Core::Configuration.instance.get('beef.extension').select { |k,v| v['enable'] == true } end # Returns configuration of all loaded extensions # @return [Array] an array of extension configuration hashes that are loaded def self.get_loaded - return BeEF::Core::Configuration.instance.get('beef.extension').select {|k,v| v['loaded'] == true } + return BeEF::Core::Configuration.instance.get('beef.extension').select {|k,v| v['loaded'] == true } end # Load all enabled extensions # @note API fire for post_load def self.load - BeEF::Core::Configuration.instance.load_extensions_config - self.get_enabled.each { |k,v| - BeEF::Extension.load(k) - } - # API post extension load - BeEF::API::Registrar.instance.fire(BeEF::API::Extensions, 'post_load') + BeEF::Core::Configuration.instance.load_extensions_config + self.get_enabled.each { |k,v| + BeEF::Extension.load(k) + } + # API post extension load + BeEF::API::Registrar.instance.fire(BeEF::API::Extensions, 'post_load') end -end + end end diff --git a/core/filters.rb b/core/filters.rb index 31056a70d..1522bb250 100644 --- a/core/filters.rb +++ b/core/filters.rb @@ -14,9 +14,9 @@ # limitations under the License. # module BeEF -module Filters + module Filters -end + end end # @note Include the filters diff --git a/core/hbmanager.rb b/core/hbmanager.rb index 77177ee35..cd5eb8bc0 100644 --- a/core/hbmanager.rb +++ b/core/hbmanager.rb @@ -14,21 +14,21 @@ # limitations under the License. # module BeEF -module HBManager - + module HBManager + # Get hooked browser by session id # @param [String] sid hooked browser session id string # @return [BeEF::Core::Models::HookedBrowser] returns the associated Hooked Browser def self.get_by_session(sid) - BeEF::Core::Models::HookedBrowser.first(:session => sid) + BeEF::Core::Models::HookedBrowser.first(:session => sid) end # Get hooked browser by id # @param [Integer] id hooked browser database id # @return [BeEF::Core::Models::HookedBrowser] returns the associated Hooked Browser def self.get_by_id(id) - BeEF::Core::Models::HookedBrowser.first(:id => id) + BeEF::Core::Models::HookedBrowser.first(:id => id) end -end + end end diff --git a/core/module.rb b/core/module.rb index cb2421edd..b79db349a 100644 --- a/core/module.rb +++ b/core/module.rb @@ -14,34 +14,34 @@ # limitations under the License. # module BeEF -module Module + module Module # Checks to see if module key is in configuration # @param [String] mod module key # @return [Boolean] if the module key exists in BeEF's configuration def self.is_present(mod) - return BeEF::Core::Configuration.instance.get('beef.module').has_key?(mod.to_s) + return BeEF::Core::Configuration.instance.get('beef.module').has_key?(mod.to_s) end # Checks to see if module is enabled in configuration # @param [String] mod module key # @return [Boolean] if the module key is enabled in BeEF's configuration def self.is_enabled(mod) - return (self.is_present(mod) and BeEF::Core::Configuration.instance.get('beef.module.'+mod.to_s+'.enable') == true) + return (self.is_present(mod) and BeEF::Core::Configuration.instance.get('beef.module.'+mod.to_s+'.enable') == true) end # Checks to see if the module reports that it has loaded through the configuration # @param [String] mod module key # @return [Boolean] if the module key is loaded in BeEF's configuration def self.is_loaded(mod) - return (self.is_enabled(mod) and BeEF::Core::Configuration.instance.get('beef.module.'+mod.to_s+'.loaded') == true) + return (self.is_enabled(mod) and BeEF::Core::Configuration.instance.get('beef.module.'+mod.to_s+'.loaded') == true) end # Returns module class definition # @param [String] mod module key # @return [Class] the module class def self.get_definition(mod) - return BeEF::Core::Command.const_get(BeEF::Core::Configuration.instance.get("beef.module.#{mod.to_s}.class")) + return BeEF::Core::Command.const_get(BeEF::Core::Configuration.instance.get("beef.module.#{mod.to_s}.class")) end # Gets all module options @@ -49,31 +49,31 @@ module Module # @return [Hash] a hash of all the module options # @note API Fire: get_options def self.get_options(mod) - if BeEF::API::Registrar.instance.matched?(BeEF::API::Module, 'get_options', [mod]) - options = BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'get_options', mod) - mo = [] - options.each{|o| - if o[:data].kind_of?(Array) - mo += o[:data] - else - print_debug "API Warning: return result for BeEF::Module.get_options() was not an array." - end - } - return mo + if BeEF::API::Registrar.instance.matched?(BeEF::API::Module, 'get_options', [mod]) + options = BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'get_options', mod) + mo = [] + options.each{|o| + if o[:data].kind_of?(Array) + mo += o[:data] + else + print_debug "API Warning: return result for BeEF::Module.get_options() was not an array." + end + } + return mo + end + if self.check_hard_load(mod) + class_name = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.class") + class_symbol = BeEF::Core::Command.const_get(class_name) + if class_symbol and class_symbol.respond_to?(:options) + return class_symbol.options end - if self.check_hard_load(mod) - class_name = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.class") - class_symbol = BeEF::Core::Command.const_get(class_name) - if class_symbol and class_symbol.respond_to?(:options) - return class_symbol.options - end - #TODO: do we really need to print this info? At then modules with no options are common, - # so I guess we shouldn't print this info even in debug mode -# else -# print_debug "Module '#{mod}', no options method defined" -# end - end - return [] + #TODO: do we really need to print this info? At then modules with no options are common, + # so I guess we shouldn't print this info even in debug mode + # else + # print_debug "Module '#{mod}', no options method defined" + # end + end + return [] end # Gets all module payload options @@ -81,13 +81,13 @@ module Module # @return [Hash] a hash of all the module options # @note API Fire: get_options def self.get_payload_options(mod,payload) - if BeEF::API::Registrar.instance.matched?(BeEF::API::Module, 'get_payload_options', [mod,nil]) - options = BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'get_payload_options', mod,payload) - return options - end - return [] + if BeEF::API::Registrar.instance.matched?(BeEF::API::Module, 'get_payload_options', [mod,nil]) + options = BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'get_payload_options', mod,payload) + return options + end + return [] end - + # Soft loads a module # @note A soft load consists of only loading the modules configuration (ie not the module.rb) # @param [String] mod module key @@ -95,23 +95,23 @@ module Module # @note API Fire: pre_soft_load # @note API Fire: post_soft_load def self.soft_load(mod) - # API call for pre-soft-load module - BeEF::API::Registrar.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?($root_dir+"/"+config.get('beef.module.'+mod+'.path')+'/module.rb') - BeEF::Core::Configuration.instance.set('beef.module.'+mod+'.class', mod.capitalize) - self.parse_targets(mod) - print_debug "Soft Load module: '#{mod}'" - # API call for post-soft-load module - BeEF::API::Registrar.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" - end - print_error "Unable to load module '#{mod}'" + # API call for pre-soft-load module + BeEF::API::Registrar.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?($root_dir+"/"+config.get('beef.module.'+mod+'.path')+'/module.rb') + BeEF::Core::Configuration.instance.set('beef.module.'+mod+'.class', mod.capitalize) + self.parse_targets(mod) + print_debug "Soft Load module: '#{mod}'" + # API call for post-soft-load module + BeEF::API::Registrar.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" end - return false + print_error "Unable to load module '#{mod}'" + end + return false end # Hard loads a module @@ -121,71 +121,71 @@ module Module # @note API Fire: pre_hard_load # @note API Fire: post_hard_load def self.hard_load(mod) - # API call for pre-hard-load module - BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'pre_hard_load', mod) - config = BeEF::Core::Configuration.instance - if self.is_enabled(mod) - begin - require config.get("beef.module.#{mod}.path")+'module.rb' - if self.exists?(config.get("beef.module.#{mod}.class")) - # start server mount point - BeEF::Core::Server.instance.mount("/command/#{mod}.js", BeEF::Core::Handlers::Commands, mod) - BeEF::Core::Configuration.instance.set("beef.module.#{mod}.mount", "/command/#{mod}.js") - 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::Registrar.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" - end - rescue => e - BeEF::Core::Configuration.instance.set('beef.module.'+mod+'.loaded', false) - print_error "There was a problem loading the module '#{mod.to_s}'" - print_debug "Hard load module syntax error: #{e.to_s}" - end - else - print_error "Hard load attempted on module '#{mod.to_s}' that is not enabled." + # API call for pre-hard-load module + BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'pre_hard_load', mod) + config = BeEF::Core::Configuration.instance + if self.is_enabled(mod) + begin + require config.get("beef.module.#{mod}.path")+'module.rb' + if self.exists?(config.get("beef.module.#{mod}.class")) + # start server mount point + BeEF::Core::Server.instance.mount("/command/#{mod}.js", BeEF::Core::Handlers::Commands, mod) + BeEF::Core::Configuration.instance.set("beef.module.#{mod}.mount", "/command/#{mod}.js") + 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::Registrar.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" + end + rescue => e + BeEF::Core::Configuration.instance.set('beef.module.'+mod+'.loaded', false) + print_error "There was a problem loading the module '#{mod.to_s}'" + print_debug "Hard load module syntax error: #{e.to_s}" end - return false + else + print_error "Hard load attempted on module '#{mod.to_s}' that is not enabled." + end + return false end # Checks to see if a module has been hard loaded, if not a hard load is attempted # @param [String] mod module key # @return [Boolean] if already hard loaded then true otherwise (see #hard_load) def self.check_hard_load(mod) - if not self.is_loaded(mod) - return self.hard_load(mod) - end - return true + if not self.is_loaded(mod) + return self.hard_load(mod) + end + return true end - + # Get module key by database ID # @param [Integer] id module database ID # @return [String] module key def self.get_key_by_database_id(id) - ret = BeEF::Core::Configuration.instance.get('beef.module').select {|k, v| v.has_key?('db') and v['db']['id'].to_i == id.to_i } - return (ret.kind_of?(Array)) ? ret.first.first : ret.keys.first + ret = BeEF::Core::Configuration.instance.get('beef.module').select {|k, v| v.has_key?('db') and v['db']['id'].to_i == id.to_i } + return (ret.kind_of?(Array)) ? ret.first.first : ret.keys.first end # Get module key by module class # @param [Class] c module class # @return [String] module key def self.get_key_by_class(c) - ret = BeEF::Core::Configuration.instance.get('beef.module').select {|k, v| v.has_key?('class') and v['class'].to_s == c.to_s } - return (ret.kind_of?(Array)) ? ret.first.first : ret.keys.first + ret = BeEF::Core::Configuration.instance.get('beef.module').select {|k, v| v.has_key?('class') and v['class'].to_s == c.to_s } + return (ret.kind_of?(Array)) ? ret.first.first : ret.keys.first end # Checks to see if module class exists # @param [String] mod module key # @return [Boolean] returns whether or not the class exists def self.exists?(mod) - begin - kclass = BeEF::Core::Command.const_get(mod.capitalize) - return kclass.is_a?(Class) - rescue NameError - return false - end + begin + kclass = BeEF::Core::Command.const_get(mod.capitalize) + return kclass.is_a?(Class) + rescue NameError + return false + end end # Checks target configuration to see if browser / version / operating system is supported @@ -199,138 +199,138 @@ module Module # 4+ = As above but with extra parameters. # Please note this rating system has no correlation to the return constant value BeEF::Core::Constants::CommandModule::* def self.support(mod, opts) - target_config = BeEF::Core::Configuration.instance.get('beef.module.'+mod+'.target') - if target_config and opts.kind_of? Hash - if opts.key?('browser') - results = [] - target_config.each{|k,m| - m.each{|v| - case v - when String - if opts['browser'] == v - results << {'rating' => 2, 'const' => k} - end - when Hash - if opts['browser'] == v.keys.first - subv = v[v.keys.first] - rating = 1 - #version check - if opts.key?('ver') - if subv.key?('min_ver') - if subv['min_ver'].kind_of? Fixnum and opts['ver'].to_i >= subv['min_ver'] - rating += 1 - else - break - end - end - if subv.key?('max_ver') - if (subv['max_ver'].kind_of? Fixnum and opts['ver'].to_i <= subv['max_ver']) or subv['max_ver'] == "latest" - rating += 1 - else - break - end - end - end - # os check - if opts.key?('os') and subv.key?('os') - match = false - opts['os'].each{|o| - case subv['os'] - when String - if o == subv['os'] - rating += 1 - match = true - elsif subv['os'] == BeEF::Core::Constants::Os::OS_ALL_UA_STR - rating += 1 - match = true - end - when Array - subv['os'].each{|p| - if o == p or p == BeEF::Core::Constants::Os::OS_ALL_UA_STR - rating += 1 - match = true - end - } - end - } - if not match - break - end - end - if rating != 1 - results << {'rating' => rating, 'const' => k} - end - end + target_config = BeEF::Core::Configuration.instance.get('beef.module.'+mod+'.target') + if target_config and opts.kind_of? Hash + if opts.key?('browser') + results = [] + target_config.each{|k,m| + m.each{|v| + case v + when String + if opts['browser'] == v + results << {'rating' => 2, 'const' => k} + end + when Hash + if opts['browser'] == v.keys.first + subv = v[v.keys.first] + rating = 1 + #version check + if opts.key?('ver') + if subv.key?('min_ver') + if subv['min_ver'].kind_of? Fixnum and opts['ver'].to_i >= subv['min_ver'] + rating += 1 + else + break end - if v == BeEF::Core::Constants::Browsers::ALL - results << {'rating' => 1, 'const' => k} + end + if subv.key?('max_ver') + if (subv['max_ver'].kind_of? Fixnum and opts['ver'].to_i <= subv['max_ver']) or subv['max_ver'] == "latest" + rating += 1 + else + break end - } - } - if results.count > 0 - return results.sort_by {|v| v['rating']}.last['const'] - else - return BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN - end - else - print_error "BeEF::Module.support() was passed a hash without a valid browser constant" - end + end + end + # os check + if opts.key?('os') and subv.key?('os') + match = false + opts['os'].each{|o| + case subv['os'] + when String + if o == subv['os'] + rating += 1 + match = true + elsif subv['os'] == BeEF::Core::Constants::Os::OS_ALL_UA_STR + rating += 1 + match = true + end + when Array + subv['os'].each{|p| + if o == p or p == BeEF::Core::Constants::Os::OS_ALL_UA_STR + rating += 1 + match = true + end + } + end + } + if not match + break + end + end + if rating != 1 + results << {'rating' => rating, 'const' => k} + end + end + end + if v == BeEF::Core::Constants::Browsers::ALL + results << {'rating' => 1, 'const' => k} + end + } + } + if results.count > 0 + return results.sort_by {|v| v['rating']}.last['const'] + else + return BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN + end + else + print_error "BeEF::Module.support() was passed a hash without a valid browser constant" end - return nil + end + return nil end # Translates module target configuration # @note Takes the user defined target configuration and replaces it with equivalent a constant based generated version # @param [String] mod module key def self.parse_targets(mod) - target_config = BeEF::Core::Configuration.instance.get('beef.module.'+mod+'.target') - if target_config - targets = {} - target_config.each{|k,v| - begin - if BeEF::Core::Constants::CommandModule.const_defined?('VERIFIED_'+k.upcase) - key = BeEF::Core::Constants::CommandModule.const_get('VERIFIED_'+k.upcase) - if not targets.key?(key) - targets[key] = [] - end - browser = nil - case v - when String - browser = self.match_target_browser(v) - if browser - targets[key] << browser - end - when Array - v.each{|c| - browser = self.match_target_browser(c) - if browser - targets[key] << browser - end - } - when Hash - v.each{|k,c| - browser = self.match_target_browser(k) - if browser - case c - when TrueClass - targets[key] << browser - when Hash - details = self.match_target_browser_spec(c) - if details - targets[key] << {browser => details} - end - end - end - } - end + target_config = BeEF::Core::Configuration.instance.get('beef.module.'+mod+'.target') + if target_config + targets = {} + target_config.each{|k,v| + begin + if BeEF::Core::Constants::CommandModule.const_defined?('VERIFIED_'+k.upcase) + key = BeEF::Core::Constants::CommandModule.const_get('VERIFIED_'+k.upcase) + if not targets.key?(key) + targets[key] = [] + end + browser = nil + case v + when String + browser = self.match_target_browser(v) + if browser + targets[key] << browser + end + when Array + v.each{|c| + browser = self.match_target_browser(c) + if browser + targets[key] << browser end - rescue NameError - print_error "Module \"#{mod}\" configuration has invalid target status defined \"#{k}\"" - end - } - BeEF::Core::Configuration.instance.clear("beef.module.#{mod}.target") - BeEF::Core::Configuration.instance.set("beef.module.#{mod}.target", targets) - end + } + when Hash + v.each{|k,c| + browser = self.match_target_browser(k) + if browser + case c + when TrueClass + targets[key] << browser + when Hash + details = self.match_target_browser_spec(c) + if details + targets[key] << {browser => details} + end + end + end + } + end + end + rescue NameError + print_error "Module \"#{mod}\" configuration has invalid target status defined \"#{k}\"" + end + } + BeEF::Core::Configuration.instance.clear("beef.module.#{mod}.target") + BeEF::Core::Configuration.instance.set("beef.module.#{mod}.target", targets) + end end # Translates simple browser target configuration @@ -338,19 +338,19 @@ module Module # @param [String] v user defined browser # @return [Constant] a BeEF browser constant def self.match_target_browser(v) - browser = false - if v.class == String - begin - if BeEF::Core::Constants::Browsers.const_defined?(v.upcase) - browser = BeEF::Core::Constants::Browsers.const_get(v.upcase) - end - rescue NameError - print_error "Could not identify browser target specified as \"#{v}\"" - end - else - print_error "Invalid datatype passed to BeEF::Module.match_target_browser()" + browser = false + if v.class == String + begin + if BeEF::Core::Constants::Browsers.const_defined?(v.upcase) + browser = BeEF::Core::Constants::Browsers.const_get(v.upcase) + end + rescue NameError + print_error "Could not identify browser target specified as \"#{v}\"" end - return browser + else + print_error "Invalid datatype passed to BeEF::Module.match_target_browser()" + end + return browser end # Translates complex browser target configuration @@ -358,35 +358,35 @@ module Module # @param [Hash] v user defined browser hash # @return [Hash] BeEF constants hash def self.match_target_browser_spec(v) - browser = {} - if v.class == Hash - if v.key?('max_ver') and (v['max_ver'].is_a?(Fixnum) or v['max_ver'].is_a?(Float) or v['max_ver'] == "latest") - browser['max_ver'] = v['max_ver'] - end - if v.key?('min_ver') and (v['min_ver'].is_a?(Fixnum) or v['min_ver'].is_a?(Float)) - browser['min_ver'] = v['min_ver'] - end - if v.key?('os') - case v['os'] - when String - os = self.match_target_os(v['os']) - if os - browser['os'] = os - end - when Array - browser['os'] = [] - v['os'].each{|c| - os = self.match_target_os(c) - if os - browser['os'] << os - end - } - end - end - else - print_error "Invalid datatype passed to BeEF::Module.match_target_browser_spec()" + browser = {} + if v.class == Hash + if v.key?('max_ver') and (v['max_ver'].is_a?(Fixnum) or v['max_ver'].is_a?(Float) or v['max_ver'] == "latest") + browser['max_ver'] = v['max_ver'] end - return browser + if v.key?('min_ver') and (v['min_ver'].is_a?(Fixnum) or v['min_ver'].is_a?(Float)) + browser['min_ver'] = v['min_ver'] + end + if v.key?('os') + case v['os'] + when String + os = self.match_target_os(v['os']) + if os + browser['os'] = os + end + when Array + browser['os'] = [] + v['os'].each{|c| + os = self.match_target_os(c) + if os + browser['os'] << os + end + } + end + end + else + print_error "Invalid datatype passed to BeEF::Module.match_target_browser_spec()" + end + return browser end # Translates simple OS target configuration @@ -394,19 +394,19 @@ module Module # @param [String] v user defined OS string # @return [Constant] BeEF OS Constant def self.match_target_os(v) - os = false - if v.class == String - begin - if BeEF::Core::Constants::Os.const_defined?("OS_#{v.upcase}_UA_STR") - os = BeEF::Core::Constants::Os.const_get("OS_#{v.upcase}_UA_STR") - end - rescue NameError - print_error "Could not identify OS target specified as \"#{v}\"" - end - else - print_error "Invalid datatype passed to BeEF::Module.match_target_os()" + os = false + if v.class == String + begin + if BeEF::Core::Constants::Os.const_defined?("OS_#{v.upcase}_UA_STR") + os = BeEF::Core::Constants::Os.const_get("OS_#{v.upcase}_UA_STR") + end + rescue NameError + print_error "Could not identify OS target specified as \"#{v}\"" end - return os + else + print_error "Invalid datatype passed to BeEF::Module.match_target_os()" + end + return os end # Executes a module @@ -416,32 +416,32 @@ module Module # @return [Boolean] whether or not the BeEF system executed the module # @note The return value of this function does not specify if the module was successful, only that it was executed within the framework def self.execute(mod, hbsession, opts=[]) - if not (self.is_present(mod) and self.is_enabled(mod)) - print_error "Module not found '#{mod}'. Failed to execute module." - return false - end - if BeEF::API::Registrar.instance.matched?(BeEF::API::Module, 'override_execute', [mod, nil,nil]) - BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'override_execute', mod, hbsession,opts) - # @note We return true by default as we cannot determine the correct status if multiple API hooks have been called - return true - end - hb = BeEF::HBManager.get_by_session(hbsession) - if not hb - print_error "Could not find hooked browser when attempting to execute module '#{mod}'" - return false - end - self.check_hard_load(mod) - command_module = self.get_definition(mod).new(mod) - if command_module.respond_to?(:pre_execute) - command_module.pre_execute - end - h = self.merge_options(mod, []) - c = BeEF::Core::Models::Command.new(:data => self.merge_options(mod, opts).to_json, - :hooked_browser_id => hb.id, - :command_module_id => BeEF::Core::Configuration.instance.get("beef.module.#{mod}.db.id"), - :creationdate => Time.new.to_i - ).save + if not (self.is_present(mod) and self.is_enabled(mod)) + print_error "Module not found '#{mod}'. Failed to execute module." + return false + end + if BeEF::API::Registrar.instance.matched?(BeEF::API::Module, 'override_execute', [mod, nil,nil]) + BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'override_execute', mod, hbsession,opts) + # @note We return true by default as we cannot determine the correct status if multiple API hooks have been called return true + end + hb = BeEF::HBManager.get_by_session(hbsession) + if not hb + print_error "Could not find hooked browser when attempting to execute module '#{mod}'" + return false + end + self.check_hard_load(mod) + command_module = self.get_definition(mod).new(mod) + if command_module.respond_to?(:pre_execute) + command_module.pre_execute + end + h = self.merge_options(mod, []) + c = BeEF::Core::Models::Command.new(:data => self.merge_options(mod, opts).to_json, + :hooked_browser_id => hb.id, + :command_module_id => BeEF::Core::Configuration.instance.get("beef.module.#{mod}.db.id"), + :creationdate => Time.new.to_i + ).save + return true end # Merges default module options with array of custom options @@ -449,29 +449,29 @@ module Module # @param [Hash] h module options customised by user input # @return [Hash, nil] returns merged options def self.merge_options(mod, h) - if self.is_present(mod) - self.check_hard_load(mod) - merged = [] - defaults = self.get_options(mod) - defaults.each{|v| - mer = nil - h.each{|o| - if v.has_key?('name') and o.has_key?('name') and v['name'] == o['name'] - mer = v.deep_merge(o) - end - } - if mer != nil - merged.push(mer) - else - merged.push(v) - end - } - return merged - end - return nil + if self.is_present(mod) + self.check_hard_load(mod) + merged = [] + defaults = self.get_options(mod) + defaults.each{|v| + mer = nil + h.each{|o| + if v.has_key?('name') and o.has_key?('name') and v['name'] == o['name'] + mer = v.deep_merge(o) + end + } + if mer != nil + merged.push(mer) + else + merged.push(v) + end + } + return merged + end + return nil end -end + end end diff --git a/core/modules.rb b/core/modules.rb index ed2e287be..dac76bd1c 100644 --- a/core/modules.rb +++ b/core/modules.rb @@ -14,30 +14,30 @@ # limitations under the License. # module BeEF -module Modules + module Modules # Return configuration hashes of all modules that are enabled # @return [Array] configuration hashes of all enabled modules def self.get_enabled - return BeEF::Core::Configuration.instance.get('beef.module').select {|k,v| v['enable'] == true and v['category'] != nil } + return BeEF::Core::Configuration.instance.get('beef.module').select {|k,v| v['enable'] == true and v['category'] != nil } end # Return configuration hashes of all modules that are loaded # @return [Array] configuration hashes of all loaded modules def self.get_loaded - return BeEF::Core::Configuration.instance.get('beef.module').select {|k,v| v['loaded'] == true } + return BeEF::Core::Configuration.instance.get('beef.module').select {|k,v| v['loaded'] == true } end # Return an array of categories specified in module configuration files # @return [Array] all available module categories sorted alphabetically def self.get_categories - categories = [] - BeEF::Core::Configuration.instance.get('beef.module').each {|k,v| - if not categories.include?(v['category']) - categories << v['category'] - end - } - return categories.sort + categories = [] + BeEF::Core::Configuration.instance.get('beef.module').each {|k,v| + if not categories.include?(v['category']) + categories << v['category'] + end + } + return categories.sort end # Get all modules currently stored in the database @@ -45,15 +45,15 @@ module Modules def self.get_stored_in_db return BeEF::Core::Models::CommandModule.all(:order => [:id.asc]) end - + # Loads all enabled modules # @note API Fire: post_soft_load def self.load - BeEF::Core::Configuration.instance.load_modules_config - self.get_enabled.each { |k,v| - BeEF::Module.soft_load(k) - } - BeEF::API::Registrar.instance.fire(BeEF::API::Modules, 'post_soft_load') + BeEF::Core::Configuration.instance.load_modules_config + self.get_enabled.each { |k,v| + BeEF::Module.soft_load(k) + } + BeEF::API::Registrar.instance.fire(BeEF::API::Modules, 'post_soft_load') end -end + end end diff --git a/core/settings.rb b/core/settings.rb index 60b01c869..0be0f6644 100644 --- a/core/settings.rb +++ b/core/settings.rb @@ -15,7 +15,7 @@ # module BeEF module Settings - + # Checks if an extension exists in the framework. # @param [String] beef_extension extension class # @return [Boolean] if the extension exists @@ -24,7 +24,7 @@ module BeEF def self.extension_exists?(beef_extension) BeEF::Extension.const_defined?(beef_extension) end - + # Checks to see if the console extensions has been loaded # @return [Boolean] if the console extension has been loaded # @deprecated Use #{BeEF::Extension.is_loaded()} instead of this method. @@ -32,6 +32,6 @@ module BeEF def self.console? self.extension_exists?('Console') end - + end end