Code cleanup
This commit is contained in:
193
core/api.rb
193
core/api.rb
@@ -7,168 +7,205 @@
|
||||
module BeEF
|
||||
module API
|
||||
|
||||
#
|
||||
# Registrar class to handle all registered timed API calls
|
||||
#
|
||||
class Registrar
|
||||
|
||||
include Singleton
|
||||
|
||||
#
|
||||
# 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
|
||||
}
|
||||
@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}"
|
||||
unless verify_api_path(c, method)
|
||||
print_error "API Registrar: Attempted to register non-existant API method #{c} :#{method}"
|
||||
return
|
||||
end
|
||||
|
||||
if registered?(owner, c, method, params)
|
||||
print_debug "API Registrar: Attempting to re-register API call #{c} :#{method}"
|
||||
return
|
||||
end
|
||||
|
||||
id = @count
|
||||
@registry << {
|
||||
'id' => id,
|
||||
'owner' => owner,
|
||||
'class' => c,
|
||||
'method' => method,
|
||||
'params' => params
|
||||
}
|
||||
@count += 1
|
||||
|
||||
id
|
||||
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
|
||||
#
|
||||
def registered?(owner, c, method, params = [])
|
||||
@registry.each{|r|
|
||||
if r['owner'] == owner and r['class'] == c and r['method'] == method and self.is_matched_params?(r, params)
|
||||
return true
|
||||
end
|
||||
}
|
||||
return false
|
||||
@registry.each do |r|
|
||||
next unless r['owner'] == owner
|
||||
next unless r['class'] == c
|
||||
next unless r['method'] == method
|
||||
next unless is_matched_params? r, params
|
||||
return true
|
||||
end
|
||||
false
|
||||
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
|
||||
@registry.each do |r|
|
||||
next unless r['class'] == c
|
||||
next unless r['method'] == method
|
||||
next unless is_matched_params? r, params
|
||||
return true
|
||||
end
|
||||
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
|
||||
}
|
||||
@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
|
||||
@registry.each do |r|
|
||||
next unless r['class'] == c
|
||||
next unless r['method'] == method
|
||||
next unless is_matched_params? r, params
|
||||
owners << { :owner => r['owner'], :id => r['id'] }
|
||||
end
|
||||
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))
|
||||
(c.const_defined?('API_PATHS') && c.const_get('API_PATHS').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;
|
||||
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
|
||||
return true unless stored.length == params.length
|
||||
|
||||
stored.each_index do |i|
|
||||
next if stored[i].nil?
|
||||
return false unless stored[i] == params[i]
|
||||
end
|
||||
return true
|
||||
|
||||
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
|
||||
#
|
||||
# @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 => 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
|
||||
mods = get_owners(c, m, args)
|
||||
return nil unless mods.length.positive?
|
||||
|
||||
unless verify_api_path(c, m) && c.ancestors[0].to_s > 'BeEF::API'
|
||||
print_error "API Path not defined for Class: #{c} method:#{method}"
|
||||
return []
|
||||
end
|
||||
return nil
|
||||
|
||||
data = []
|
||||
method = 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)
|
||||
unless result.nil?
|
||||
data << { :api_id => mod[:id], :data => result }
|
||||
end
|
||||
rescue => e
|
||||
print_error "API Fire Error: #{e.message} in #{mod}.#{method}()"
|
||||
end
|
||||
end
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -37,7 +37,3 @@ require 'core/main/migration'
|
||||
require 'core/main/console/commandline'
|
||||
require 'core/main/console/banners'
|
||||
|
||||
# @note Include rubyzip lib
|
||||
require 'zip'
|
||||
|
||||
|
||||
|
||||
@@ -10,36 +10,40 @@ module BeEF
|
||||
# @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)
|
||||
BeEF::Core::Configuration.instance.get('beef.extension').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 false unless is_present(ext)
|
||||
BeEF::Core::Configuration.instance.get("beef.extension.#{ext}.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
|
||||
# @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 false unless is_enabled(ext)
|
||||
BeEF::Core::Configuration.instance.get("beef.extension.#{ext}.loaded") == true
|
||||
end
|
||||
|
||||
# Loads an extension
|
||||
# @param [String] ext the extension key
|
||||
# @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?("#{$root_dir}/extensions/#{ext}/extension.rb")
|
||||
if File.exist? "#{$root_dir}/extensions/#{ext}/extension.rb"
|
||||
require "#{$root_dir}/extensions/#{ext}/extension.rb"
|
||||
print_debug "Loaded extension: '#{ext}'"
|
||||
BeEF::Core::Configuration.instance.set('beef.extension.'+ext+'.loaded', true)
|
||||
BeEF::Core::Configuration.instance.set "beef.extension.#{ext}.loaded", true
|
||||
return true
|
||||
end
|
||||
print_error "Unable to load extension '#{ext}'"
|
||||
return false
|
||||
false
|
||||
rescue => e
|
||||
print_error "Unable to load extension '#{ext}':"
|
||||
print_more e.message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,13 +9,13 @@ module BeEF
|
||||
# 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 }
|
||||
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 }
|
||||
BeEF::Core::Configuration.instance.get('beef.extension').select {|k,v| v['loaded'] == true }
|
||||
end
|
||||
|
||||
# Load all enabled extensions
|
||||
@@ -23,12 +23,10 @@ module BeEF
|
||||
def self.load
|
||||
BeEF::Core::Configuration.instance.load_extensions_config
|
||||
self.get_enabled.each { |k,v|
|
||||
BeEF::Extension.load(k)
|
||||
BeEF::Extension.load k
|
||||
}
|
||||
# API post extension load
|
||||
BeEF::API::Registrar.instance.fire(BeEF::API::Extensions, 'post_load')
|
||||
BeEF::API::Registrar.instance.fire BeEF::API::Extensions, 'post_load'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ require 'mime/types'
|
||||
require 'optparse'
|
||||
require 'resolv'
|
||||
require 'digest'
|
||||
require 'zip'
|
||||
|
||||
# @note Include the filters
|
||||
require 'core/filters'
|
||||
|
||||
@@ -6,37 +6,42 @@
|
||||
|
||||
module BeEF
|
||||
module Core
|
||||
|
||||
#
|
||||
# @note This module contains a list of utils functions to use when writing commands
|
||||
#
|
||||
module CommandUtils
|
||||
|
||||
#
|
||||
# Format a string to support multiline in javascript.
|
||||
# @param [String] text String to convert
|
||||
#
|
||||
# @return [String] Formatted string
|
||||
def format_multiline(text); text.gsub(/\n/, '\n'); end
|
||||
|
||||
#
|
||||
def format_multiline(text)
|
||||
text.gsub(/\n/, '\n')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#
|
||||
# @note The Command Module Context is being used when evaluating code in eruby.
|
||||
# In other words, we use that code to add funky functions to the
|
||||
# javascript templates of our commands.
|
||||
#
|
||||
class CommandContext < Erubis::Context
|
||||
include BeEF::Core::CommandUtils
|
||||
|
||||
#
|
||||
# Constructor
|
||||
# @param [Hash] hash
|
||||
def initialize(hash=nil);
|
||||
super(hash);
|
||||
#
|
||||
def initialize(hash = nil)
|
||||
super(hash)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# @note This class is the base class for all command modules in the framework.
|
||||
# Two instances of this object are created during the execution of command module.
|
||||
# Two instances of this object are created during the execution of command module.
|
||||
#
|
||||
class Command
|
||||
|
||||
attr_reader :datastore, :path, :default_command_url, :beefjs_components, :friendlyname
|
||||
attr_accessor :zombie, :command_id, :session_id
|
||||
|
||||
@@ -44,8 +49,11 @@ module BeEF
|
||||
include BeEF::Core::Constants::Browsers
|
||||
include BeEF::Core::Constants::CommandModule
|
||||
|
||||
#
|
||||
# Super class controller
|
||||
#
|
||||
# @param [String] key command module key
|
||||
#
|
||||
def initialize(key)
|
||||
config = BeEF::Core::Configuration.instance
|
||||
|
||||
@@ -61,62 +69,98 @@ module BeEF
|
||||
@beefjs_components = {}
|
||||
end
|
||||
|
||||
#
|
||||
# This function is called just before the instructions are sent to hooked browser.
|
||||
#
|
||||
def pre_send; end
|
||||
|
||||
#
|
||||
# Callback method. This function is called when the hooked browser sends results back.
|
||||
#
|
||||
def callback; end
|
||||
|
||||
#
|
||||
# If the command requires some data to be sent back, this function will process them.
|
||||
# @param [] head
|
||||
# @param [Hash] params Hash of parameters
|
||||
# @todo Determine argument "head" type
|
||||
#
|
||||
def process_zombie_response(head, params); end
|
||||
|
||||
#
|
||||
# Returns true if the command needs configurations to work. False if not.
|
||||
# @deprecated This command should not be used since the implementation of the new configuration system
|
||||
def needs_configuration?; !@datastore.nil?; end
|
||||
#
|
||||
def needs_configuration?
|
||||
!@datastore.nil?
|
||||
end
|
||||
|
||||
#
|
||||
# Returns information about the command in a JSON format.
|
||||
# @return [String] JSON formatted string
|
||||
#
|
||||
def to_json
|
||||
{
|
||||
'Name' => @friendlyname,
|
||||
'Description' => BeEF::Core::Configuration.instance.get("beef.module.#{@key}.description"),
|
||||
'Category' => BeEF::Core::Configuration.instance.get("beef.module.#{@key}.category"),
|
||||
'Data' => BeEF::Module.get_options(@key)
|
||||
'Name' => @friendlyname,
|
||||
'Description' => BeEF::Core::Configuration.instance.get("beef.module.#{@key}.description"),
|
||||
'Category' => BeEF::Core::Configuration.instance.get("beef.module.#{@key}.category"),
|
||||
'Data' => BeEF::Module.get_options(@key)
|
||||
}.to_json
|
||||
end
|
||||
|
||||
#
|
||||
# Builds the 'datastore' attribute of the command which is used to generate javascript code.
|
||||
# @param [Hash] data Data to be inserted into the datastore
|
||||
# @todo Confirm argument "data" type
|
||||
def build_datastore(data);
|
||||
@datastore = JSON.parse(data)
|
||||
# @todo TODO Confirm argument "data" type
|
||||
#
|
||||
def build_datastore(data)
|
||||
@datastore = JSON.parse data
|
||||
rescue => e
|
||||
print_error "Could not build datastore: #{e.message}"
|
||||
end
|
||||
|
||||
#
|
||||
# Sets the datastore for the callback function. This function is meant to be called by the CommandHandler
|
||||
# @param [Hash] http_params HTTP parameters
|
||||
# @param [Hash] http_headers HTTP headers
|
||||
#
|
||||
def build_callback_datastore(result, command_id, beefhook, http_params, http_headers)
|
||||
@datastore = {'http_headers' => {}} # init the datastore
|
||||
|
||||
if http_params != nil && http_headers != nil
|
||||
if !http_params.nil? && !http_headers.nil?
|
||||
# get, check and add the http_params to the datastore
|
||||
http_params.keys.each { |http_params_key|
|
||||
(print_error 'http_params_key is invalid';return) if not BeEF::Filters.is_valid_command_module_datastore_key?(http_params_key)
|
||||
http_params_value = Erubis::XmlHelper.escape_xml(http_params[http_params_key])
|
||||
(print_error 'http_params_value is invalid';return) if not BeEF::Filters.is_valid_command_module_datastore_param?(http_params_value)
|
||||
@datastore[http_params_key] = http_params_value # add the checked key and value to the datastore
|
||||
}
|
||||
http_params.keys.each do |http_params_key|
|
||||
unless BeEF::Filters.is_valid_command_module_datastore_key? http_params_key
|
||||
print_error 'http_params_key is invalid'
|
||||
return
|
||||
end
|
||||
|
||||
http_params_value = Erubis::XmlHelper.escape_xml http_params[http_params_key]
|
||||
unless BeEF::Filters.is_valid_command_module_datastore_param?(http_params_value)
|
||||
print_error 'http_params_value is invalid'
|
||||
return
|
||||
end
|
||||
|
||||
# add the checked key and value to the datastore
|
||||
@datastore[http_params_key] = http_params_value
|
||||
end
|
||||
|
||||
# get, check and add the http_headers to the datastore
|
||||
http_headers.keys.each { |http_header_key|
|
||||
(print_error 'http_header_key is invalid';return) if not BeEF::Filters.is_valid_command_module_datastore_key?(http_header_key)
|
||||
http_header_value = Erubis::XmlHelper.escape_xml(http_headers[http_header_key][0])
|
||||
(print_error 'http_header_value is invalid';return) if not BeEF::Filters.is_valid_command_module_datastore_param?(http_header_value)
|
||||
@datastore['http_headers'][http_header_key] = http_header_value # add the checked key and value to the datastore
|
||||
}
|
||||
http_headers.keys.each do |http_header_key|
|
||||
unless BeEF::Filters.is_valid_command_module_datastore_key? http_header_key
|
||||
print_error 'http_header_key is invalid'
|
||||
return
|
||||
end
|
||||
|
||||
http_header_value = Erubis::XmlHelper.escape_xml http_headers[http_header_key][0]
|
||||
unless BeEF::Filters.is_valid_command_module_datastore_param? http_header_value
|
||||
print_error 'http_header_value is invalid'
|
||||
return
|
||||
end
|
||||
|
||||
# add the checked key and value to the datastore
|
||||
@datastore['http_headers'][http_header_key] = http_header_value
|
||||
end
|
||||
end
|
||||
|
||||
@datastore['results'] = result
|
||||
@@ -124,28 +168,32 @@ module BeEF
|
||||
@datastore['beefhook'] = beefhook
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the output of the command. These are the actual instructions sent to the browser.
|
||||
# @return [String] The command output
|
||||
#
|
||||
def output
|
||||
f = @path+'command.js'
|
||||
(print_error "#{f} file does not exist";return) if not File.exists? f
|
||||
f = "#{@path}command.js"
|
||||
unless File.exist? f
|
||||
print_error "File does not exist: #{f}"
|
||||
return
|
||||
end
|
||||
|
||||
command = BeEF::Core::Models::Command.first(:id => @command_id)
|
||||
|
||||
@eruby = Erubis::FastEruby.new(File.read(f))
|
||||
|
||||
data = BeEF::Core::Configuration.instance.get("beef.module.#{@key}")
|
||||
#data = BeEF::Core::Configuration.instance.get "beef.module.#{@key}"
|
||||
cc = BeEF::Core::CommandContext.new
|
||||
cc['command_url'] = @default_command_url
|
||||
cc['command_id'] = @command_id
|
||||
JSON.parse(command['data']).each{|v|
|
||||
JSON.parse(command['data']).each do |v|
|
||||
cc[v['name']] = v['value']
|
||||
}
|
||||
if self.respond_to?(:execute)
|
||||
self.execute
|
||||
end
|
||||
@output = @eruby.evaluate(cc)
|
||||
|
||||
execute if respond_to?(:execute)
|
||||
|
||||
@output = @eruby.evaluate cc
|
||||
@output
|
||||
end
|
||||
|
||||
@@ -155,19 +203,25 @@ module BeEF
|
||||
@results = results
|
||||
end
|
||||
|
||||
# If nothing else than the file is specified, the function will map the file to a random path without any extension.
|
||||
#
|
||||
# If nothing else than the file is specified,
|
||||
# the function will map the file to a random path without any extension.
|
||||
#
|
||||
# @param [String] file File to be mounted
|
||||
# @param [String] path URL path to mounted file
|
||||
# @param [String] extension URL extension
|
||||
# @param [Integer] count The amount of times this file can be accessed before being automatically unmounted
|
||||
# @deprecated This function is possibly deprecated in place of the API
|
||||
def map_file_to_url(file, path=nil, extension=nil, count=1)
|
||||
return BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind(file, path, extension, count)
|
||||
#
|
||||
def map_file_to_url(file, path = nil, extension = nil, count = 1)
|
||||
BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind(file, path, extension, count)
|
||||
end
|
||||
|
||||
#
|
||||
# Tells the framework to load a specific module of the BeEFJS library that the command will be using.
|
||||
# @param [String] component String of BeEFJS component to load
|
||||
# @note Example: use 'beef.net.local'
|
||||
#
|
||||
def use(component)
|
||||
return if @beefjs_components.include? component
|
||||
|
||||
@@ -176,23 +230,23 @@ module BeEF
|
||||
component_path.gsub!(/\./, '/')
|
||||
component_path.replace "#{$root_dir}/core/main/client/#{component_path}.js"
|
||||
|
||||
raise "Invalid beefjs component for command module #{@path}" if not File.exists?(component_path)
|
||||
raise "Invalid beefjs component for command module #{@path}" unless File.exist? component_path
|
||||
|
||||
@beefjs_components[component] = component_path
|
||||
end
|
||||
|
||||
# @todo Document
|
||||
# @todo TODO Document
|
||||
def oc_value(name)
|
||||
option = BeEF::Core::Models::OptionCache.first(:name => name)
|
||||
return nil if not option
|
||||
return option.value
|
||||
option = BeEF::Core::Models::OptionCache.first(:name => name)
|
||||
return nil unless option
|
||||
option.value
|
||||
end
|
||||
|
||||
# @todo Document
|
||||
def apply_defaults()
|
||||
@datastore.each { |opt|
|
||||
opt["value"] = oc_value(opt["name"]) || opt["value"]
|
||||
}
|
||||
# @todo TODO Document
|
||||
def apply_defaults
|
||||
@datastore.each do |opt|
|
||||
opt['value'] = oc_value(opt['name']) || opt['value']
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
@@ -201,9 +255,6 @@ module BeEF
|
||||
@eruby
|
||||
@update_zombie
|
||||
@results
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,26 +6,26 @@
|
||||
|
||||
module BeEF
|
||||
module Core
|
||||
|
||||
class Configuration
|
||||
|
||||
attr_accessor :config
|
||||
|
||||
# antisnatchor: still a singleton, but implemented by hand because we want to have only one instance
|
||||
# of the Configuration object while having the possibility to specify a parameter to the constructor.
|
||||
# This is why we don't use anymore the default Ruby implementation -> include Singleton
|
||||
def self.instance()
|
||||
return @@instance
|
||||
def self.instance
|
||||
@@instance
|
||||
end
|
||||
|
||||
# Loads the default configuration system
|
||||
# @param [String] configuration_file Configuration file to be loaded, by default loads $root_dir/config.yaml
|
||||
# @param [String] configuration_file Configuration file to be loaded,
|
||||
# by default loads $root_dir/config.yaml
|
||||
def initialize(config)
|
||||
raise Exception::TypeError, '"config" needs to be a string' if not config.string?
|
||||
raise Exception::TypeError, "Configuration file '#{config}' cannot be found" if not File.exist?(config)
|
||||
raise Exception::TypeError, "'config' needs to be a string" unless config.string?
|
||||
raise Exception::TypeError, "Configuration file '#{config}' cannot be found" unless File.exist? config
|
||||
|
||||
begin
|
||||
#open base config
|
||||
@config = self.load(config)
|
||||
@config = load(config)
|
||||
# set default value if key? does not exist
|
||||
@config.default = nil
|
||||
@@config = config
|
||||
@@ -33,6 +33,7 @@ module BeEF
|
||||
print_error "Fatal Error: cannot load configuration file"
|
||||
print_debug e
|
||||
end
|
||||
|
||||
@@instance = self
|
||||
end
|
||||
|
||||
@@ -40,89 +41,101 @@ module BeEF
|
||||
# @param [String] file YAML file to be loaded
|
||||
# @return [Hash] YAML formatted hash
|
||||
def load(file)
|
||||
begin
|
||||
return nil if not File.exists?(file)
|
||||
raw = File.read(file)
|
||||
return YAML.load(raw)
|
||||
rescue => e
|
||||
print_debug "Unable to load '#{file}' #{e}"
|
||||
return nil
|
||||
end
|
||||
return nil unless File.exist? file
|
||||
raw = File.read file
|
||||
YAML.safe_load raw
|
||||
rescue => e
|
||||
print_debug "Unable to load '#{file}' #{e}"
|
||||
nil
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the value of a selected key in the configuration file.
|
||||
# @param [String] key Key of configuration item
|
||||
# @return [Hash|String] The resulting value stored against the 'key'
|
||||
#
|
||||
def get(key)
|
||||
subkeys = key.split('.')
|
||||
lastkey = subkeys.pop
|
||||
subhash = subkeys.inject(@config) do |hash, k|
|
||||
hash[k]
|
||||
end
|
||||
return (subhash != nil and subhash.has_key?(lastkey)) ? subhash[lastkey] : nil
|
||||
return nil if subhash.nil?
|
||||
subhash.key?(lastkey) ? subhash[lastkey] : nil
|
||||
end
|
||||
|
||||
#
|
||||
# Sets the give key value pair to the config instance
|
||||
# @param [String] key The configuration key
|
||||
# @param value The value to be stored against the 'key'
|
||||
# @return [Boolean] If the store procedure was successful
|
||||
#
|
||||
def set(key, value)
|
||||
subkeys = key.split('.').reverse
|
||||
return false if subkeys.length == 0
|
||||
hash = {subkeys.shift.to_s => value}
|
||||
subkeys.each{|v|
|
||||
hash = {v.to_s => hash}
|
||||
}
|
||||
@config = @config.deep_merge(hash)
|
||||
return true
|
||||
return false if subkeys.empty?
|
||||
|
||||
hash = { subkeys.shift.to_s => value }
|
||||
subkeys.each { |v| hash = {v.to_s => hash} }
|
||||
@config = @config.deep_merge hash
|
||||
true
|
||||
end
|
||||
|
||||
#
|
||||
# Clears the given key hash
|
||||
# @param [String] key Configuration key to be cleared
|
||||
# @return [Boolean] If the configuration key was cleared
|
||||
#
|
||||
def clear(key)
|
||||
subkeys = key.split('.')
|
||||
return false if subkeys.length == 0
|
||||
return false if subkeys.empty?
|
||||
|
||||
lastkey = subkeys.pop
|
||||
hash = @config
|
||||
subkeys.each{|v|
|
||||
hash = hash[v]
|
||||
}
|
||||
return (hash.delete(lastkey) == nil) ? false : true
|
||||
subkeys.each {|v| hash = hash[v] }
|
||||
hash.delete(lastkey).nil? ? false : true
|
||||
end
|
||||
|
||||
#
|
||||
# Load extensions configurations
|
||||
#
|
||||
def load_extensions_config
|
||||
self.set('beef.extension', {})
|
||||
Dir.glob("#{$root_dir}/extensions/*/config.yaml") do | cf |
|
||||
y = self.load(cf)
|
||||
if y != nil
|
||||
y['beef']['extension'][y['beef']['extension'].keys.first]['path'] = cf.gsub(/config\.yaml/, '').gsub(/#{$root_dir}\//, '')
|
||||
@config = y.deep_merge(@config)
|
||||
else
|
||||
set('beef.extension', {})
|
||||
Dir.glob("#{$root_dir}/extensions/*/config.yaml") do |cf|
|
||||
y = load(cf)
|
||||
if y.nil?
|
||||
print_error "Unable to load extension configuration '#{cf}'"
|
||||
next
|
||||
end
|
||||
|
||||
y['beef']['extension'][y['beef']['extension'].keys.first]['path'] = cf.gsub(/config\.yaml/, '').gsub(%r{#{$root_dir}/}, '')
|
||||
@config = y.deep_merge(@config)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Load module configurations
|
||||
#
|
||||
def load_modules_config
|
||||
self.set('beef.module', {})
|
||||
set('beef.module', {})
|
||||
# support nested sub-categories, like browser/hooked_domain/ajax_fingerprint
|
||||
module_configs = File.join("#{$root_dir}/modules/**", "config.yaml")
|
||||
Dir.glob(module_configs) do | cf |
|
||||
y = self.load(cf)
|
||||
if y != nil
|
||||
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::Registrar.instance.fire(BeEF::API::Configuration, 'module_configuration_load', y['beef']['module'].keys.first)
|
||||
else
|
||||
Dir.glob(module_configs) do |cf|
|
||||
y = load(cf)
|
||||
if y.nil?
|
||||
print_error "Unable to load module configuration '#{cf}'"
|
||||
next
|
||||
end
|
||||
|
||||
y['beef']['module'][y['beef']['module'].keys.first]['path'] = cf.gsub('config.yaml', '').gsub(%r{#{$root_dir}/}, '')
|
||||
@config = y.deep_merge @config
|
||||
# API call for post module config load
|
||||
BeEF::API::Registrar.instance.fire(
|
||||
BeEF::API::Configuration,
|
||||
'module_configuration_load',
|
||||
y['beef']['module'].keys.first
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,15 +6,18 @@
|
||||
|
||||
module BeEF
|
||||
module Core
|
||||
|
||||
module Crypto
|
||||
|
||||
# @note the minimum length of the security token
|
||||
TOKEN_MINIMUM_LENGTH = 15
|
||||
|
||||
#
|
||||
# Generate a secure random token
|
||||
#
|
||||
# @param [Integer] len The length of the secure token
|
||||
#
|
||||
# @return [String] Security token
|
||||
#
|
||||
def self.secure_token(len = nil)
|
||||
# get default length from config
|
||||
config = BeEF::Core::Configuration.instance
|
||||
@@ -24,12 +27,15 @@ module Core
|
||||
raise Exception::TypeError, "Token length is less than the minimum length enforced by the framework: #{TOKEN_MINIMUM_LENGTH}" if (token_length < TOKEN_MINIMUM_LENGTH)
|
||||
|
||||
# return random hex string
|
||||
return OpenSSL::Random.random_bytes(token_length).unpack("H*")[0]
|
||||
OpenSSL::Random.random_bytes(token_length).unpack("H*")[0]
|
||||
end
|
||||
|
||||
#
|
||||
# Generate a secure random token, 20 chars, used as an auth token for the RESTful API.
|
||||
# After creation it's stored in the BeEF configuration object => conf.get('beef.api_token')
|
||||
#
|
||||
# @return [String] Security token
|
||||
#
|
||||
def self.api_token
|
||||
config = BeEF::Core::Configuration.instance
|
||||
token_length = 20
|
||||
@@ -40,9 +46,11 @@ module Core
|
||||
token
|
||||
end
|
||||
|
||||
#
|
||||
# Generates a unique identifier for DNS rules.
|
||||
#
|
||||
# @return [String] 8-character hex identifier
|
||||
#
|
||||
def self.dns_rule_id
|
||||
id = nil
|
||||
length = 4
|
||||
@@ -56,7 +64,6 @@ module Core
|
||||
|
||||
id.to_s
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
|
||||
module BeEF
|
||||
module Core
|
||||
|
||||
class Logger
|
||||
|
||||
include Singleton
|
||||
|
||||
# Constructor
|
||||
@@ -19,12 +17,15 @@ module Core
|
||||
# if notifications are enabled create a new instance
|
||||
@notifications = BeEF::Extension::Notifications::Notifications unless @config.get('beef.extension.notifications.enable') == false
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Registers a new event in the logs
|
||||
# @param [String] from The origin of the event (i.e. Authentication, Hooked Browser)
|
||||
# @param [String] event The event description
|
||||
# @param [Integer] hb The id of the hooked browser affected (default = 0 if no HB)
|
||||
#
|
||||
# @return [Boolean] True if the register was successful
|
||||
#
|
||||
def register(from, event, hb = 0)
|
||||
# type conversion to enforce standards
|
||||
hb = hb.to_i
|
||||
@@ -33,24 +34,23 @@ module Core
|
||||
time_now = Time.now
|
||||
|
||||
# arguments type checking
|
||||
raise Exception::TypeError, '"from" needs to be a string' if not from.string?
|
||||
raise Exception::TypeError, '"event" needs to be a string' if not event.string?
|
||||
raise Exception::TypeError, '"Hooked Browser ID" needs to be an integer' if not hb.integer?
|
||||
raise Exception::TypeError, '"from" needs to be a string' unless from.string?
|
||||
raise Exception::TypeError, '"event" needs to be a string' unless event.string?
|
||||
raise Exception::TypeError, '"Hooked Browser ID" needs to be an integer' unless hb.integer?
|
||||
|
||||
# logging the new event into the database
|
||||
@logs.new(:type => "#{from}", :event => "#{event}", :date => time_now, :hooked_browser_id => hb).save
|
||||
@logs.new(:type => from.to_s, :event => event.to_s, :date => time_now, :hooked_browser_id => hb).save
|
||||
print_debug "Event: #{event}"
|
||||
# if notifications are enabled send the info there too
|
||||
if @notifications
|
||||
@notifications.new(from, event, time_now, hb)
|
||||
end
|
||||
|
||||
# return
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
@logs
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,18 +8,22 @@ module BeEF
|
||||
module Core
|
||||
|
||||
# @note This class migrates and updates values in the database each time you restart BeEF.
|
||||
# So for example, when you want to add a new command module, you stop BeEF, copy your command module into the framework
|
||||
# and then restart BeEF. That class will take care of installing automatically the new command module in the db.
|
||||
# So for example, when you want to add a new command module, you stop BeEF,
|
||||
# copy your command module into the framework and then restart BeEF.
|
||||
# That class will take care of installing automatically the new command module in the db.
|
||||
class Migration
|
||||
|
||||
include Singleton
|
||||
|
||||
#
|
||||
# Updates the database.
|
||||
#
|
||||
def update_db!
|
||||
update_commands!
|
||||
end
|
||||
|
||||
#
|
||||
# Checks for new command modules and updates the database.
|
||||
#
|
||||
def update_commands!
|
||||
config = BeEF::Core::Configuration.instance
|
||||
|
||||
@@ -27,22 +31,21 @@ module Core
|
||||
BeEF::Core::Models::CommandModule.all.each do |mod|
|
||||
db_modules << mod.name
|
||||
end
|
||||
|
||||
|
||||
config.get('beef.module').each{|k,v|
|
||||
BeEF::Core::Models::CommandModule.new(:name => k, :path => "#{v['path']}module.rb").save if not db_modules.include? k
|
||||
}
|
||||
config.get('beef.module').each do |k, v|
|
||||
h = { :name => k, :path => "#{v['path']}module.rb" }
|
||||
BeEF::Core::Models::CommandModule.new(h).save unless db_modules.include? k
|
||||
end
|
||||
|
||||
BeEF::Core::Models::CommandModule.all.each{|mod|
|
||||
if config.get('beef.module.'+mod.name) != nil
|
||||
config.set('beef.module.'+mod.name+'.db.id', mod.id)
|
||||
config.set('beef.module.'+mod.name+'.db.path', mod.path)
|
||||
BeEF::Core::Models::CommandModule.all.each do |mod|
|
||||
unless config.get("beef.module.#{mod.name}").nil?
|
||||
config.set "beef.module.#{mod.name}.db.id", mod.id
|
||||
config.set "beef.module.#{mod.name}.db.path", mod.path
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
# Call Migration method
|
||||
BeEF::API::Registrar.instance.fire(BeEF::API::Migration, 'migrate_commands')
|
||||
|
||||
BeEF::API::Registrar.instance.fire BeEF::API::Migration, 'migrate_commands'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,9 +10,7 @@ Thin::SERVER = nil
|
||||
|
||||
module BeEF
|
||||
module Core
|
||||
|
||||
class Server
|
||||
|
||||
include Singleton
|
||||
|
||||
# @note Grabs the version of beef the framework is deployed on
|
||||
@@ -43,46 +41,56 @@ module BeEF
|
||||
'beef_public' => @configuration.get('beef.http.public'),
|
||||
'beef_public_port' => @configuration.get('beef.http.public_port'),
|
||||
'beef_hook' => @configuration.get('beef.http.hook_file'),
|
||||
'beef_proto' => @configuration.get('beef.http.https.enable') == true ? "https" : "http",
|
||||
'client_debug' => @configuration.get("beef.client_debug")
|
||||
'beef_proto' => @configuration.get('beef.http.https.enable') == true ? 'https' : 'http',
|
||||
'client_debug' => @configuration.get('beef.client_debug')
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Mounts a handler, can either be a hard or soft mount
|
||||
#
|
||||
# @param [String] url The url to mount
|
||||
# @param [Class] http_handler_class Class to call once mount is triggered
|
||||
# @param args Arguments to pass to the http handler class
|
||||
#
|
||||
def mount(url, http_handler_class, args = nil)
|
||||
# argument type checking
|
||||
raise Exception::TypeError, '"url" needs to be a string' if not url.string?
|
||||
raise Exception::TypeError, '"url" needs to be a string' unless url.string?
|
||||
|
||||
if args == nil
|
||||
if args.nil?
|
||||
@mounts[url] = http_handler_class
|
||||
else
|
||||
@mounts[url] = http_handler_class, *args
|
||||
end
|
||||
print_debug("Server: mounted handler '#{url}'")
|
||||
print_debug "Server: mounted handler '#{url}'"
|
||||
end
|
||||
|
||||
#
|
||||
# Unmounts handler
|
||||
#
|
||||
# @param [String] url URL to unmount.
|
||||
#
|
||||
def unmount(url)
|
||||
raise Exception::TypeError, '"url" needs to be a string' if not url.string?
|
||||
@mounts.delete(url)
|
||||
raise Exception::TypeError, '"url" needs to be a string' unless url.string?
|
||||
@mounts.delete url
|
||||
end
|
||||
|
||||
#
|
||||
# Reload the URL map (used by the NetworkStack AssetHandler to mount new URLs at runtime)
|
||||
#
|
||||
def remap
|
||||
@rack_app.remap(@mounts)
|
||||
@rack_app.remap @mounts
|
||||
end
|
||||
|
||||
#
|
||||
# Prepares the BeEF http server.
|
||||
#
|
||||
def prepare
|
||||
# Create http handler for the javascript hook file
|
||||
self.mount("#{@configuration.get("beef.http.hook_file")}", BeEF::Core::Handlers::HookedBrowsers.new)
|
||||
mount(@configuration.get("beef.http.hook_file").to_s, BeEF::Core::Handlers::HookedBrowsers.new)
|
||||
|
||||
# Create handler for the initialization checks (Browser Details)
|
||||
self.mount("/init", BeEF::Core::Handlers::BrowserDetails)
|
||||
mount('/init', BeEF::Core::Handlers::BrowserDetails)
|
||||
|
||||
# Dynamically get the list of all the http handlers using the API and register them
|
||||
BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'mount_handler', self)
|
||||
@@ -111,10 +119,10 @@ module BeEF
|
||||
openssl_version = OpenSSL::OPENSSL_VERSION
|
||||
if openssl_version =~ / 1\.0\.1([a-f])? /
|
||||
print_warning "Warning: #{openssl_version} is vulnerable to Heartbleed (CVE-2014-0160)."
|
||||
print_more "Upgrade OpenSSL to version 1.0.1g or newer."
|
||||
print_more 'Upgrade OpenSSL to version 1.0.1g or newer.'
|
||||
end
|
||||
|
||||
cert_key = @configuration.get('beef.http.https.key')
|
||||
cert_key = @configuration.get 'beef.http.https.key'
|
||||
unless cert_key.start_with? '/'
|
||||
cert_key = File.expand_path cert_key, $root_dir
|
||||
end
|
||||
@@ -123,7 +131,7 @@ module BeEF
|
||||
exit 1
|
||||
end
|
||||
|
||||
cert = @configuration.get('beef.http.https.cert')
|
||||
cert = @configuration.get 'beef.http.https.cert'
|
||||
unless cert.start_with? '/'
|
||||
cert = File.expand_path cert, $root_dir
|
||||
end
|
||||
@@ -146,14 +154,16 @@ module BeEF
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Starts the BeEF http server
|
||||
#
|
||||
def start
|
||||
@http_server.start
|
||||
rescue RuntimeError => e
|
||||
# port is in use
|
||||
raise unless e.message.include? 'no acceptor'
|
||||
print_error "Another process is already listening on port #{@configuration.get('beef.http.port')}, or you're trying to bind BeEF to an invalid IP."
|
||||
print_error "Is BeEF already running? Exiting..."
|
||||
print_error 'Is BeEF already running? Exiting...'
|
||||
exit 127
|
||||
end
|
||||
end
|
||||
|
||||
585
core/module.rb
585
core/module.rb
@@ -10,28 +10,28 @@ module BeEF
|
||||
# @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)
|
||||
BeEF::Core::Configuration.instance.get('beef.module').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}.enable") == true)
|
||||
(is_present(mod) && BeEF::Core::Configuration.instance.get("beef.module.#{mod}.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}.loaded") == true)
|
||||
(is_enabled(mod) && BeEF::Core::Configuration.instance.get("beef.module.#{mod}.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}.class"))
|
||||
BeEF::Core::Command.const_get(BeEF::Core::Configuration.instance.get("beef.module.#{mod}.class"))
|
||||
end
|
||||
|
||||
# Gets all module options
|
||||
@@ -39,26 +39,30 @@ module BeEF
|
||||
# @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)
|
||||
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
|
||||
options.each do |o|
|
||||
unless o[:data].is_a?(Array)
|
||||
print_debug "API Warning: return result for BeEF::Module.get_options() was not an array."
|
||||
next
|
||||
end
|
||||
}
|
||||
mo += o[:data]
|
||||
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
|
||||
|
||||
unless check_hard_load mod
|
||||
print_debug "get_opts called on unloaded module '#{mod}'"
|
||||
return []
|
||||
end
|
||||
return []
|
||||
|
||||
class_name = BeEF::Core::Configuration.instance.get "beef.module.#{mod}.class"
|
||||
class_symbol = BeEF::Core::Command.const_get class_name
|
||||
|
||||
return [] unless class_symbol && class_symbol.respond_to?(:options)
|
||||
|
||||
class_symbol.options
|
||||
end
|
||||
|
||||
# Gets all module payload options
|
||||
@@ -66,11 +70,8 @@ module BeEF
|
||||
# @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 []
|
||||
return [] unless BeEF::API::Registrar.instance.matched?(BeEF::API::Module, 'get_payload_options', [mod, nil])
|
||||
BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'get_payload_options', mod, payload)
|
||||
end
|
||||
|
||||
# Soft loads a module
|
||||
@@ -83,21 +84,29 @@ module BeEF
|
||||
# API call for pre-soft-load module
|
||||
BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'pre_soft_load', mod)
|
||||
config = BeEF::Core::Configuration.instance
|
||||
|
||||
mod_str = "beef.module.#{mod}"
|
||||
if not config.get("#{mod_str}.loaded")
|
||||
if not File.exists?("#{$root_dir}/#{config.get("#{mod_str}.path")}/module.rb")
|
||||
print_debug "Unable to locate module file: #{config.get("#{mod_str}.path")}/module.rb"
|
||||
return false
|
||||
end
|
||||
BeEF::Core::Configuration.instance.set("#{mod_str}.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
|
||||
if config.get("#{mod_str}.loaded")
|
||||
print_error "Unable to load module '#{mod}'"
|
||||
return false
|
||||
end
|
||||
print_error "Unable to load module '#{mod}'"
|
||||
return false
|
||||
|
||||
mod_path = "#{$root_dir}/#{config.get("#{mod_str}.path")}/module.rb"
|
||||
unless File.exist? mod_path
|
||||
print_debug "Unable to locate module file: #{mod_path}"
|
||||
return false
|
||||
end
|
||||
|
||||
BeEF::Core::Configuration.instance.set("#{mod_str}.class", mod.capitalize)
|
||||
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)
|
||||
true
|
||||
rescue => e
|
||||
print_error "There was a problem soft loading the module '#{mod}'"
|
||||
false
|
||||
end
|
||||
|
||||
# Hard loads a module
|
||||
@@ -110,69 +119,73 @@ module BeEF
|
||||
# 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 not self.is_enabled(mod)
|
||||
|
||||
unless is_enabled mod
|
||||
print_error "Hard load attempted on module '#{mod}' that is not enabled."
|
||||
return false
|
||||
end
|
||||
|
||||
mod_str = "beef.module.#{mod}"
|
||||
begin
|
||||
require config.get("#{mod_str}.path")+'module.rb'
|
||||
if self.exists?(config.get("#{mod_str}.class"))
|
||||
# start server mount point
|
||||
BeEF::Core::Server.instance.mount("/command/#{mod}.js", BeEF::Core::Handlers::Commands, mod)
|
||||
BeEF::Core::Configuration.instance.set("#{mod_str}.mount", "/command/#{mod}.js")
|
||||
BeEF::Core::Configuration.instance.set("#{mod_str}.loaded", true)
|
||||
print_debug "Hard Load module: '#{mod}'"
|
||||
# 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}' but the class BeEF::Core::Commands::#{mod.capitalize} does not exist"
|
||||
end
|
||||
rescue => e
|
||||
BeEF::Core::Configuration.instance.set("#{mod_str}.loaded", false)
|
||||
print_error "There was a problem loading the module '#{mod}'"
|
||||
print_debug "Hard load module syntax error: #{e}"
|
||||
mod_path = "#{config.get("#{mod_str}.path")}/module.rb"
|
||||
require mod_path
|
||||
|
||||
unless exists? config.get("#{mod_str}.class")
|
||||
print_error "Hard loaded module '#{mod}' but the class BeEF::Core::Commands::#{mod.capitalize} does not exist"
|
||||
return false
|
||||
end
|
||||
return false
|
||||
|
||||
# start server mount point
|
||||
BeEF::Core::Server.instance.mount("/command/#{mod}.js", BeEF::Core::Handlers::Commands, mod)
|
||||
BeEF::Core::Configuration.instance.set("#{mod_str}.mount", "/command/#{mod}.js")
|
||||
BeEF::Core::Configuration.instance.set("#{mod_str}.loaded", true)
|
||||
print_debug "Hard Load module: '#{mod}'"
|
||||
|
||||
# API call for post-hard-load module
|
||||
BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'post_hard_load', mod)
|
||||
true
|
||||
rescue => e
|
||||
BeEF::Core::Configuration.instance.set("#{mod_str}.loaded", false)
|
||||
print_error "There was a problem loading the module '#{mod}'"
|
||||
print_debug "Hard load module syntax error: #{e}"
|
||||
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
|
||||
return true if is_loaded mod
|
||||
hard_load mod
|
||||
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 do |k, v|
|
||||
v.key?('db') && v['db']['id'].to_i == id.to_i
|
||||
end
|
||||
ret.is_a?(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 do |k, v|
|
||||
v.key?('class') && v['class'].to_s.eql?(c.to_s)
|
||||
end
|
||||
ret.is_a?(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
|
||||
kclass = BeEF::Core::Command.const_get mod.capitalize
|
||||
kclass.is_a? Class
|
||||
rescue NameError
|
||||
false
|
||||
end
|
||||
|
||||
# Checks target configuration to see if browser / version / operating system is supported
|
||||
@@ -187,104 +200,102 @@ module BeEF
|
||||
# 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 not target_config or not opts.kind_of? Hash
|
||||
return nil
|
||||
end
|
||||
if not opts.key?('browser')
|
||||
return nil unless target_config
|
||||
return nil unless opts.is_a? Hash
|
||||
|
||||
unless opts.key? 'browser'
|
||||
print_error "BeEF::Module.support() was passed a hash without a valid browser constant"
|
||||
return nil
|
||||
end
|
||||
|
||||
results = []
|
||||
target_config.each{|k,m|
|
||||
m.each{|v|
|
||||
target_config.each do |k, m|
|
||||
m.each do |v|
|
||||
case v
|
||||
when String
|
||||
if opts['browser'] == v
|
||||
# if k == BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING
|
||||
# rating += 1
|
||||
# end
|
||||
results << {'rating' => 2, 'const' => k}
|
||||
end
|
||||
when Hash
|
||||
if opts['browser'] == v.keys.first or v.keys.first == BeEF::Core::Constants::Browsers::ALL
|
||||
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
|
||||
match = true
|
||||
end
|
||||
when Array
|
||||
subv['os'].each{|p|
|
||||
if o == p
|
||||
rating += 1
|
||||
match = true
|
||||
elsif p == BeEF::Core::Constants::Os::OS_ALL_UA_STR
|
||||
match = true
|
||||
end
|
||||
}
|
||||
end
|
||||
}
|
||||
if not match
|
||||
break
|
||||
end
|
||||
end
|
||||
if rating > 0
|
||||
# if k == BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING
|
||||
# rating += 1
|
||||
# end
|
||||
results << {'rating' => rating, 'const' => k}
|
||||
end
|
||||
end
|
||||
end
|
||||
if v == BeEF::Core::Constants::Browsers::ALL
|
||||
when String
|
||||
if opts['browser'] == v
|
||||
# if k == BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING
|
||||
# rating += 1
|
||||
# end
|
||||
results << {'rating' => 2, 'const' => k}
|
||||
end
|
||||
when Hash
|
||||
break if opts['browser'] != v.keys.first && v.keys.first != BeEF::Core::Constants::Browsers::ALL
|
||||
|
||||
subv = v[v.keys.first]
|
||||
rating = 1
|
||||
if k == BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING
|
||||
rating = 1
|
||||
# version check
|
||||
if opts.key?('ver')
|
||||
if subv.key?('min_ver')
|
||||
if subv['min_ver'].is_a?(Integer) && opts['ver'].to_i >= subv['min_ver']
|
||||
rating += 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if subv.key?('max_ver')
|
||||
if (subv['max_ver'].is_a?(Integer) && opts['ver'].to_i <= subv['max_ver']) || subv['max_ver'] == 'latest'
|
||||
rating += 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
results << {'rating' => rating, 'const' => k}
|
||||
end
|
||||
}
|
||||
}
|
||||
if results.count > 0
|
||||
result = {}
|
||||
results.each {|r|
|
||||
if result == {}
|
||||
result = {'rating' => r['rating'], 'const' => r['const']}
|
||||
else
|
||||
if r['rating'] > result['rating']
|
||||
result = {'rating' => r['rating'], 'const' => r['const']}
|
||||
# os check
|
||||
if opts.key?('os') && subv.key?('os')
|
||||
match = false
|
||||
opts['os'].each do |o|
|
||||
case subv['os']
|
||||
when String
|
||||
if o == subv['os']
|
||||
rating += 1
|
||||
match = true
|
||||
elsif subv['os'].eql? BeEF::Core::Constants::Os::OS_ALL_UA_STR
|
||||
match = true
|
||||
end
|
||||
when Array
|
||||
subv['os'].each do |p|
|
||||
if o == p
|
||||
rating += 1
|
||||
match = true
|
||||
elsif p.eql? BeEF::Core::Constants::Os::OS_ALL_UA_STR
|
||||
match = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
break unless match
|
||||
end
|
||||
|
||||
if rating.positive?
|
||||
# if k == BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING
|
||||
# rating += 1
|
||||
# end
|
||||
results << {'rating' => rating, 'const' => k}
|
||||
end
|
||||
end
|
||||
}
|
||||
return result['const']
|
||||
else
|
||||
return BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN
|
||||
|
||||
next unless v.eql? BeEF::Core::Constants::Browsers::ALL
|
||||
|
||||
rating = 1
|
||||
if k == BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING
|
||||
rating = 1
|
||||
end
|
||||
|
||||
results << {'rating' => rating, 'const' => k}
|
||||
end
|
||||
end
|
||||
|
||||
return BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN unless results.count.positive?
|
||||
|
||||
result = {}
|
||||
results.each do |r|
|
||||
if result == {} || r['rating'] > result['rating']
|
||||
result = {'rating' => r['rating'], 'const' => r['const']}
|
||||
end
|
||||
end
|
||||
|
||||
result['const']
|
||||
end
|
||||
|
||||
# Translates module target configuration
|
||||
@@ -293,53 +304,46 @@ module BeEF
|
||||
def self.parse_targets(mod)
|
||||
mod_str = "beef.module.#{mod}"
|
||||
target_config = BeEF::Core::Configuration.instance.get("#{mod_str}.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
|
||||
}
|
||||
return unless target_config
|
||||
|
||||
targets = {}
|
||||
target_config.each do |k, v|
|
||||
begin
|
||||
next unless BeEF::Core::Constants::CommandModule.const_defined? "VERIFIED_#{k.upcase}"
|
||||
key = BeEF::Core::Constants::CommandModule.const_get "VERIFIED_#{k.upcase}"
|
||||
targets[key] = [] unless targets.key? key
|
||||
browser = nil
|
||||
|
||||
case v
|
||||
when String
|
||||
browser = match_target_browser v
|
||||
targets[key] << browser if browser
|
||||
when Array
|
||||
v.each do |c|
|
||||
browser = match_target_browser c
|
||||
targets[key] << browser if browser
|
||||
end
|
||||
when Hash
|
||||
v.each do |k, c|
|
||||
browser = match_target_browser k
|
||||
next unless browser
|
||||
|
||||
case c
|
||||
when TrueClass
|
||||
targets[key] << browser
|
||||
when Hash
|
||||
details = match_target_browser_spec c
|
||||
targets[key] << {browser => details} if details
|
||||
end
|
||||
end
|
||||
rescue NameError
|
||||
print_error "Module '#{mod}' configuration has invalid target status defined '#{k}'"
|
||||
end
|
||||
}
|
||||
BeEF::Core::Configuration.instance.clear("#{mod_str}.target")
|
||||
BeEF::Core::Configuration.instance.set("#{mod_str}.target", targets)
|
||||
rescue NameError
|
||||
print_error "Module '#{mod}' configuration has invalid target status defined '#{k}'"
|
||||
end
|
||||
end
|
||||
|
||||
BeEF::Core::Configuration.instance.clear "#{mod_str}.target"
|
||||
BeEF::Core::Configuration.instance.set "#{mod_str}.target", targets
|
||||
end
|
||||
|
||||
# Translates simple browser target configuration
|
||||
@@ -347,19 +351,17 @@ module BeEF
|
||||
# @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()"
|
||||
unless v.class == String
|
||||
print_error 'Invalid datatype passed to BeEF::Module.match_target_browser()'
|
||||
return false
|
||||
end
|
||||
return browser
|
||||
|
||||
return false unless BeEF::Core::Constants::Browsers.const_defined? v.upcase
|
||||
|
||||
BeEF::Core::Constants::Browsers.const_get v.upcase
|
||||
rescue NameError
|
||||
print_error "Could not identify browser target specified as '#{v}'"
|
||||
false
|
||||
end
|
||||
|
||||
# Translates complex browser target configuration
|
||||
@@ -367,35 +369,35 @@ module BeEF
|
||||
# @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()"
|
||||
unless v.class == Hash
|
||||
print_error 'Invalid datatype passed to BeEF::Module.match_target_browser_spec()'
|
||||
return {}
|
||||
end
|
||||
return browser
|
||||
|
||||
browser = {}
|
||||
if v.key?('max_ver') && (v['max_ver'].is_a?(Integer) || v['max_ver'].is_a?(Float) || v['max_ver'] == 'latest')
|
||||
browser['max_ver'] = v['max_ver']
|
||||
end
|
||||
|
||||
if v.key?('min_ver') && (v['min_ver'].is_a?(Integer) || v['min_ver'].is_a?(Float))
|
||||
browser['min_ver'] = v['min_ver']
|
||||
end
|
||||
|
||||
return browser unless v.key? 'os'
|
||||
|
||||
case v['os']
|
||||
when String
|
||||
os = match_target_os v['os']
|
||||
browser['os'] = os if os
|
||||
when Array
|
||||
browser['os'] = []
|
||||
v['os'].each do |c|
|
||||
os = match_target_os c
|
||||
browser['os'] << os if os
|
||||
end
|
||||
end
|
||||
|
||||
browser
|
||||
end
|
||||
|
||||
# Translates simple OS target configuration
|
||||
@@ -403,84 +405,81 @@ module BeEF
|
||||
# @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()"
|
||||
unless v.class == String
|
||||
print_error 'Invalid datatype passed to BeEF::Module.match_target_os()'
|
||||
return false
|
||||
end
|
||||
return os
|
||||
|
||||
return false unless BeEF::Core::Constants::Os.const_defined? "OS_#{v.upcase}_UA_STR"
|
||||
|
||||
BeEF::Core::Constants::Os.const_get "OS_#{v.upcase}_UA_STR"
|
||||
rescue NameError
|
||||
print_error "Could not identify OS target specified as '#{v}'"
|
||||
false
|
||||
end
|
||||
|
||||
# Executes a module
|
||||
# @param [String] mod module key
|
||||
# @param [String] hbsession hooked browser session
|
||||
# @param [Array] opts array of module execute options (see #get_options)
|
||||
# @return [Fixnum] the command_id associated to the module execution when info is persisted. nil if there are errors.
|
||||
# @return [Integer] the command_id associated to the module execution when info is persisted. nil if there are errors.
|
||||
# @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))
|
||||
unless is_present(mod) && is_enabled(mod)
|
||||
print_error "Module not found '#{mod}'. Failed to execute module."
|
||||
return nil
|
||||
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)
|
||||
|
||||
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 not_nil by default as we cannot determine the correct status if multiple API hooks have been called
|
||||
return 'not_available' # @note using metasploit, we cannot know if the module execution was successful or not
|
||||
# @note using metasploit, we cannot know if the module execution was successful or not
|
||||
return 'not_available'
|
||||
end
|
||||
hb = BeEF::HBManager.get_by_session(hbsession)
|
||||
if not hb
|
||||
|
||||
hb = BeEF::HBManager.get_by_session hbsession
|
||||
unless hb
|
||||
print_error "Could not find hooked browser when attempting to execute module '#{mod}'"
|
||||
return nil
|
||||
end
|
||||
self.check_hard_load(mod)
|
||||
command_module = self.get_definition(mod).new(mod)
|
||||
|
||||
check_hard_load mod
|
||||
command_module = 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.create(: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
|
||||
merge_options(mod, [])
|
||||
c = BeEF::Core::Models::Command.create(
|
||||
:data => 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
|
||||
)
|
||||
return c.id
|
||||
c.id
|
||||
end
|
||||
|
||||
# Merges default module options with array of custom options
|
||||
# @param [String] mod module key
|
||||
# @param [Hash] h module options customised by user input
|
||||
# @param [Hash] opts 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
|
||||
end
|
||||
def self.merge_options(mod, opts)
|
||||
return nil unless is_present mod
|
||||
|
||||
check_hard_load mod
|
||||
merged = []
|
||||
defaults = get_options mod
|
||||
defaults.each do |v|
|
||||
mer = nil
|
||||
opts.each do |o|
|
||||
if v.key?('name') && o.key?('name') && v['name'] == o['name']
|
||||
mer = v.deep_merge o
|
||||
end
|
||||
end
|
||||
|
||||
mer.nil? ? merged.push(v) : merged.push(mer)
|
||||
end
|
||||
|
||||
merged
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -9,50 +9,56 @@ module BeEF
|
||||
# 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 }
|
||||
BeEF::Core::Configuration.instance.get('beef.module').select do |_k, v|
|
||||
v['enable'] == true && !v['category'].nil?
|
||||
end
|
||||
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 }
|
||||
BeEF::Core::Configuration.instance.get('beef.module').select do |_k, v|
|
||||
v['loaded'] == true
|
||||
end
|
||||
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|
|
||||
flatcategory = ""
|
||||
if v['category'].kind_of?(Array)
|
||||
# Therefore this module has nested categories (sub-folders), munge them together into a string with '/' characters, like a folder.
|
||||
v['category'].each {|cat|
|
||||
flatcategory << cat + "/"
|
||||
}
|
||||
BeEF::Core::Configuration.instance.get('beef.module').each_value do |v|
|
||||
flatcategory = ''
|
||||
if v['category'].is_a?(Array)
|
||||
# Therefore this module has nested categories (sub-folders),
|
||||
# munge them together into a string with '/' characters, like a folder.
|
||||
v['category'].each do |cat|
|
||||
flatcategory << "#{cat}/"
|
||||
end
|
||||
else
|
||||
flatcategory = v['category']
|
||||
end
|
||||
if not categories.include?(flatcategory)
|
||||
categories << flatcategory
|
||||
end
|
||||
}
|
||||
return categories.sort.uniq #This is now uniqued, because otherwise the recursive function to build the json tree breaks if there are duplicates.
|
||||
categories << flatcategory unless categories.include? flatcategory
|
||||
end
|
||||
|
||||
# This is now uniqued, because otherwise the recursive function to build
|
||||
# the json tree breaks if there are duplicates.
|
||||
categories.sort.uniq
|
||||
end
|
||||
|
||||
# Get all modules currently stored in the database
|
||||
# @return [Array] DataMapper array of all BeEF::Core::Models::CommandModule's in the database
|
||||
def self.get_stored_in_db
|
||||
return BeEF::Core::Models::CommandModule.all(:order => [:id.asc])
|
||||
BeEF::Core::Models::CommandModule.all(:order => [:id.asc])
|
||||
end
|
||||
|
||||
# Loads all enabled modules
|
||||
# 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')
|
||||
get_enabled.each_key do |k|
|
||||
BeEF::Module.soft_load k
|
||||
end
|
||||
BeEF::API::Registrar.instance.fire BeEF::API::Modules, 'post_soft_load'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,13 +8,14 @@ class Hash
|
||||
# Recursively deep merge two hashes together
|
||||
# @param [Hash] hash Hash to be merged
|
||||
# @return [Hash] Combined hash
|
||||
# @note Duplicate keys are overwritten by the value defined in the hash calling deep_merge (not the parameter hash)
|
||||
# @note Duplicate keys are overwritten by the value defined
|
||||
# in the hash calling deep_merge (not the parameter hash)
|
||||
# @note http://snippets.dzone.com/posts/show/4706
|
||||
def deep_merge(hash)
|
||||
target = dup
|
||||
hash.keys.each do |key|
|
||||
if hash[key].is_a? Hash and self[key].is_a? Hash
|
||||
target[key] = target[key].deep_merge(hash[key])
|
||||
if hash[key].is_a?(Hash) && self[key].is_a?(Hash)
|
||||
target[key] = target[key].deep_merge hash[key]
|
||||
next
|
||||
end
|
||||
target[key] = hash[key]
|
||||
|
||||
@@ -35,4 +35,9 @@ class Object
|
||||
self.is_a?(Class)
|
||||
end
|
||||
|
||||
# Returns true if the object is nil, and empty string, or empty array
|
||||
# @return [Boolean]
|
||||
def blank?
|
||||
self.respond_to?(:empty?) ? !!empty? : !self
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user