module BeEF
module Module
def self.is_present(mod)
BeEF::Core::Configuration.instance.get('beef.module').key? mod.to_s
end
def self.is_enabled(mod)
(is_present(mod) && BeEF::Core::Configuration.instance.get("beef.module.#{mod}.enable") == true)
end
def self.is_loaded(mod)
(is_enabled(mod) && BeEF::Core::Configuration.instance.get("beef.module.#{mod}.loaded") == true)
end
def self.get_definition(mod)
BeEF::Core::Command.const_get(BeEF::Core::Configuration.instance.get("beef.module.#{mod}.class"))
end
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 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
unless check_hard_load mod
print_debug "get_opts called on unloaded module '#{mod}'"
return []
end
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
def self.get_payload_options(mod, payload)
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
def self.soft_load(mod)
BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'pre_soft_load', mod)
config = BeEF::Core::Configuration.instance
mod_str = "beef.module.#{mod}"
if config.get("#{mod_str}.loaded")
print_error "Unable to load module '#{mod}'"
return false
end
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}'"
BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'post_soft_load', mod)
true
rescue StandardError => e
print_error "There was a problem soft loading the module '#{mod}': #{e.message}"
false
end
def self.hard_load(mod)
BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'pre_hard_load', mod)
config = BeEF::Core::Configuration.instance
unless is_enabled mod
print_error "Hard load attempted on module '#{mod}' that is not enabled."
return false
end
mod_str = "beef.module.#{mod}"
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
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}'"
BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'post_hard_load', mod)
true
rescue StandardError => 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
def self.check_hard_load(mod)
return true if is_loaded mod
hard_load mod
end
def self.get_key_by_database_id(id)
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
def self.get_key_by_class(c)
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
def self.exists?(mod)
kclass = BeEF::Core::Command.const_get mod.capitalize
kclass.is_a? Class
rescue NameError
false
end
def self.support(mod, opts)
target_config = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.target")
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 do |k, m|
m.each do |v|
case v
when String
if opts['browser'] == v
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 opts.key?('ver')
if subv.key?('min_ver')
break unless subv['min_ver'].is_a?(Integer) && opts['ver'].to_i >= subv['min_ver']
rating += 1
end
if subv.key?('max_ver')
break unless (subv['max_ver'].is_a?(Integer) && opts['ver'].to_i <= subv['max_ver']) || subv['max_ver'] == 'latest'
rating += 1
end
end
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?
results << { 'rating' => rating, 'const' => k }
end
end
next unless v.eql? BeEF::Core::Constants::Browsers::ALL
rating = 1
rating = 1 if k == BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING
results << { 'rating' => rating, 'const' => k }
end
end
return BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN unless results.count.positive?
result = {}
results.each do |r|
result = { 'rating' => r['rating'], 'const' => r['const'] } if result == {} || r['rating'] > result['rating']
end
result['const']
end
def self.parse_targets(mod)
mod_str = "beef.module.#{mod}"
target_config = BeEF::Core::Configuration.instance.get("#{mod_str}.target")
return unless target_config
targets = {}
target_config.each do |k, v|
k_str = k.to_s.upcase
next unless BeEF::Core::Constants::CommandModule.const_defined? "VERIFIED_#{k_str}"
key = BeEF::Core::Constants::CommandModule.const_get "VERIFIED_#{k_str}"
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
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
end
def self.match_target_browser(v)
unless v.instance_of?(String)
print_error 'Invalid datatype passed to BeEF::Module.match_target_browser()'
return false
end
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
def self.match_target_browser_spec(v)
unless v.instance_of?(Hash)
print_error 'Invalid datatype passed to BeEF::Module.match_target_browser_spec()'
return {}
end
browser = {}
browser['max_ver'] = v['max_ver'] if v.key?('max_ver') && (v['max_ver'].is_a?(Integer) || v['max_ver'].is_a?(Float) || v['max_ver'] == 'latest')
browser['min_ver'] = v['min_ver'] if v.key?('min_ver') && (v['min_ver'].is_a?(Integer) || v['min_ver'].is_a?(Float))
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
def self.match_target_os(v)
unless v.instance_of?(String)
print_error 'Invalid datatype passed to BeEF::Module.match_target_os()'
return false
end
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
def self.execute(mod, hbsession, opts = [])
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
return 'not_available'
end
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
check_hard_load mod
command_module = get_definition(mod).new(mod)
command_module.pre_execute if command_module.respond_to?(:pre_execute)
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
)
c.id
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|
mer = v.deep_merge o if v.key?('name') && o.key?('name') && v['name'] == o['name']
end
mer.nil? ? merged.push(v) : merged.push(mer)
end
merged
end
end
end