From 4dd7230c40c99c478a44c2598a2cc14b966713d4 Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Sat, 16 Feb 2019 12:54:09 +0000 Subject: [PATCH] cleanup --- core/filters/command.rb | 9 - core/main/configuration.rb | 4 +- core/main/crypto.rb | 2 +- core/main/geoip.rb | 2 +- core/main/handlers/commands.rb | 160 ++++++++++-------- core/main/logger.rb | 6 +- core/main/models/command.rb | 60 ++++--- core/main/models/commandmodule.rb | 7 +- core/main/models/hookedbrowser.rb | 25 ++- .../main/network_stack/websocket/websocket.rb | 2 +- core/main/server.rb | 4 +- .../admin_ui/controllers/panel/panel.rb | 2 +- .../media/javascript/ui/panel/PanelViewer.js | 2 +- 13 files changed, 163 insertions(+), 122 deletions(-) diff --git a/core/filters/command.rb b/core/filters/command.rb index f8dd8ca6d..c14cba3d6 100644 --- a/core/filters/command.rb +++ b/core/filters/command.rb @@ -16,15 +16,6 @@ module Filters true end - # Check if the command id valid - # @param [String] str String for testing - # @return [Boolean] If the string is a valid command id - def self.is_valid_command_id?(str) - return false unless is_non_empty_string?(str) - return false unless nums_only?(str) - true - end - # Check if the session id valid # @param [String] str String for testing # @return [Boolean] If the string has valid hook session id characters diff --git a/core/main/configuration.rb b/core/main/configuration.rb index 61014759b..6ad8dfc1b 100644 --- a/core/main/configuration.rb +++ b/core/main/configuration.rb @@ -20,8 +20,8 @@ module BeEF # @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" unless config.string? - raise Exception::TypeError, "Configuration file '#{config}' cannot be found" unless File.exist? config + raise TypeError, "'config' needs to be a string" unless config.string? + raise TypeError, "Configuration file '#{config}' cannot be found" unless File.exist? config begin #open base config diff --git a/core/main/crypto.rb b/core/main/crypto.rb index 35e7d9303..c1b87b77c 100644 --- a/core/main/crypto.rb +++ b/core/main/crypto.rb @@ -24,7 +24,7 @@ module Core token_length = len || config.get('beef.crypto_default_value_length').to_i # type checking - raise Exception::TypeError, "Token length is less than the minimum length enforced by the framework: #{TOKEN_MINIMUM_LENGTH}" if (token_length < TOKEN_MINIMUM_LENGTH) + raise 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 OpenSSL::Random.random_bytes(token_length).unpack("H*")[0] diff --git a/core/main/geoip.rb b/core/main/geoip.rb index 04b88a786..19384d3a1 100644 --- a/core/main/geoip.rb +++ b/core/main/geoip.rb @@ -48,7 +48,7 @@ module Core # @return [Hash] IP address lookup results # def lookup(ip) - raise Exception::TypeError, '"ip" needs to be a string' unless ip.string? + raise TypeError, '"ip" needs to be a string' unless ip.string? return unless @enabled diff --git a/core/main/handlers/commands.rb b/core/main/handlers/commands.rb index c65986fd6..5b3007990 100644 --- a/core/main/handlers/commands.rb +++ b/core/main/handlers/commands.rb @@ -4,81 +4,107 @@ # See the file 'doc/COPYING' for copying permission # module BeEF - module Core - module Handlers +module Core +module Handlers + class Commands - class Commands + include BeEF::Core::Handlers::Modules::BeEFJS + include BeEF::Core::Handlers::Modules::Command - include BeEF::Core::Handlers::Modules::BeEFJS - include BeEF::Core::Handlers::Modules::Command + @data = {} - @data = {} + # + # Handles command data + # + # @param [Hash] data Data from command execution + # @param [Class] kclass Class of command + # + # @todo Confirm argument data variable type [radoen]: type is Hash confirmed. + # + def initialize(data, kclass) + @kclass = BeEF::Core::Command.const_get(kclass.capitalize) + @data = data + setup + end - # Handles command data - # @param [Hash] data Data from command execution - # @param [Class] kclass Class of command - # @todo Confirm argument data variable type [radoen]: type is Hash confirmed. - def initialize(data, kclass) - @kclass = BeEF::Core::Command.const_get(kclass.capitalize) - @data = data - setup() - end - - # Initial setup function, creates the command module and saves details to datastore - def setup() - - - @http_params = @data['request'].params - @http_header = Hash.new - http_header = @data['request'].env.select { |k, v| k.to_s.start_with? 'HTTP_' }.each { |key, value| - @http_header[key.sub(/^HTTP_/, '')] = value.force_encoding('UTF-8') - } - - # @note get and check command id from the request - command_id = get_param(@data, 'cid') - # @todo ruby filter needs to be updated to detect fixnums not strings - command_id = command_id.to_s() - (print_error "command_id is invalid"; return) if not BeEF::Filters.is_valid_command_id?(command_id.to_s()) - - # @note get and check session id from the request - beefhook = get_param(@data, 'beefhook') - (print_error "BeEF hook is invalid"; return) if not BeEF::Filters.is_valid_hook_session_id?(beefhook) - - result = get_param(@data, 'results') - - # @note create the command module to handle the response - command = @kclass.new(BeEF::Module.get_key_by_class(@kclass)) - command.build_callback_datastore(result, command_id, beefhook, @http_params, @http_header) - command.session_id = beefhook - if command.respond_to?(:post_execute) - command.post_execute - end - #@todo this is the part that store result on db and the modify will be accessible from all the framework and so UI too - # @note get/set details for datastore and log entry - command_friendly_name = command.friendlyname - (print_error "command friendly name is empty"; return) if command_friendly_name.empty? - - command_status = @data['status'] - command_results = @data['results'] - (print_error "command results or status are empty"; return) if command_results.empty? - - # @note save the command module results to the datastore and create a log entry - command_results = {'data' => command_results} - BeEF::Core::Models::Command.save_result(beefhook, command_id, command_friendly_name, command_results, command_status) - - end - - # Returns parameter from hash - # @param [Hash] query Hash of data to return data from - # @param [String] key Key to search for and return inside `query` - # @return Value referenced in hash at the supplied key - def get_param(query, key) - return (query.class == Hash and query.has_key?(key)) ? query[key] : nil - end + # + # @note Initial setup function, creates the command module and saves details to datastore + # + def setup + @http_params = @data['request'].params + @http_header = {} + http_header = @data['request'].env.select { |k, v| k.to_s.start_with? 'HTTP_' }.each { |key, value| + @http_header[key.sub(/^HTTP_/, '')] = value.force_encoding('UTF-8') + } + # @note get and check command id from the request + command_id = get_param(@data, 'cid') + unless command_id.integer? + print_error "command_id is invalid" + return end + # @note get and check session id from the request + beefhook = get_param(@data, 'beefhook') + unless BeEF::Filters.is_valid_hook_session_id?(beefhook) + print_error "BeEF hook is invalid" + return + end + result = get_param(@data, 'results') + + # @note create the command module to handle the response + command = @kclass.new(BeEF::Module.get_key_by_class(@kclass)) + command.build_callback_datastore(result, command_id, beefhook, @http_params, @http_header) + command.session_id = beefhook + command.post_execute if command.respond_to?(:post_execute) + + # @todo this is the part that store result on db and the modify + # will be accessible from all the framework and so UI too + # @note get/set details for datastore and log entry + command_friendly_name = command.friendlyname + if command_friendly_name.empty? + print_error 'command friendly name is empty' + return + end + + command_status = @data['status'] + unless command_status.integer? + print_error 'command status is invalid' + return + end + + command_results = @data['results'] + if command_results.empty? + print_error 'command results are empty' + return + end + + # @note save the command module results to the datastore and create a log entry + command_results = { 'data' => command_results } + BeEF::Core::Models::Command.save_result( + beefhook, + command_id, + command_friendly_name, + command_results, + command_status + ) + end + + # + # @note Returns parameter from hash + # + # @param [Hash] query Hash of data to return data from + # @param [String] key Key to search for and return inside `query` + # + # @return Value referenced in hash at the supplied key + # + def get_param(query, key) + return unless query.class == Hash + return unless query.key?(key) + query[key] end end end +end +end diff --git a/core/main/logger.rb b/core/main/logger.rb index b907d73d4..52fd9d617 100644 --- a/core/main/logger.rb +++ b/core/main/logger.rb @@ -34,9 +34,9 @@ module Core time_now = Time.now # arguments type checking - 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? + raise TypeError, '"from" needs to be a string' unless from.string? + raise TypeError, '"event" needs to be a string' unless event.string? + raise TypeError, '"Hooked Browser ID" needs to be an integer' unless hb.integer? # logging the new event into the database @logs.new(:type => from.to_s, :event => event.to_s, :date => time_now, :hooked_browser_id => hb).save diff --git a/core/main/models/command.rb b/core/main/models/command.rb index 360c37559..04e4a83ca 100644 --- a/core/main/models/command.rb +++ b/core/main/models/command.rb @@ -23,58 +23,62 @@ module Models has n, :results - + # # Save results and flag that the command has been run on the hooked browser + # # @param [String] hook_session_id The session_id. # @param [String] command_id The command_id. # @param [String] command_friendly_name The command friendly name. # @param [String] result The result of the command module. + # def self.save_result(hook_session_id, command_id, command_friendly_name, result, status) - # @note enforcing arguments types - command_id = command_id.to_i - # @note argument type checking - raise Exception::TypeError, '"hook_session_id" needs to be a string' if not hook_session_id.string? - raise Exception::TypeError, '"command_id" needs to be an integer' if not command_id.integer? - raise Exception::TypeError, '"command_friendly_name" needs to be a string' if not command_friendly_name.string? - raise Exception::TypeError, '"result" needs to be a hash' if not result.hash? - raise Exception::TypeError, '"status" needs to be an integer' if not status.integer? + raise TypeError, '"hook_session_id" needs to be a string' unless hook_session_id.string? + raise TypeError, '"command_id" needs to be an integer' unless command_id.integer? + raise TypeError, '"command_friendly_name" needs to be a string' unless command_friendly_name.string? + raise TypeError, '"result" needs to be a hash' unless result.hash? + raise TypeError, '"status" needs to be an integer' unless status.integer? # @note get the hooked browser structure and id from the database hooked_browser = BeEF::Core::Models::HookedBrowser.first(:session => hook_session_id) || nil - raise Exception::TypeError, "hooked_browser is nil" if hooked_browser.nil? - raise Exception::TypeError, "hooked_browser.id is nil" if hooked_browser.id.nil? - hooked_browser_id = hooked_browser.id - raise Exception::TypeError, "hooked_browser.ip is nil" if hooked_browser.ip.nil? - hooked_browser_ip = hooked_browser.ip + raise TypeError, "hooked_browser is nil" if hooked_browser.nil? + raise TypeError, "hooked_browser.id is nil" if hooked_browser.id.nil? # @note get the command module data structure from the database - command = first(:id => command_id.to_i, :hooked_browser_id => hooked_browser_id) || nil - raise Exception::TypeError, "command is nil" if command.nil? + command = first(:id => command_id, :hooked_browser_id => hooked_browser.id) || nil + raise TypeError, "command is nil" if command.nil? # @note create the entry for the results - command.results.new(:hooked_browser_id => hooked_browser_id, - :data => result.to_json,:status => status,:date => Time.now.to_i) + command.results.new( + :hooked_browser_id => hooked_browser.id, + :data => result.to_json, + :status => status, + :date => Time.now.to_i + ) command.save - s = self.show_status(status) - log = "Hooked browser [id:#{hooked_browser.id}, ip:#{hooked_browser.ip}] has executed instructions (status: #{s}) from command module [cid:#{command_id}, mod: #{command.command_module_id}, name:'#{command_friendly_name}']" - BeEF::Core::Logger.instance.register('Command', log, hooked_browser_id) + s = show_status(status) + log = "Hooked browser [id:#{hooked_browser.id}, ip:#{hooked_browser.ip}]" + log += " has executed instructions (status: #{s}) from command module [cid:#{command_id}," + log += " mod: #{command.command_module_id}, name:'#{command_friendly_name}']" + BeEF::Core::Logger.instance.register('Command', log, hooked_browser.id) print_info log + + true end + # @note show status def self.show_status(status) case status - when -1 - result = 'ERROR' - when 1 - result = 'SUCCESS' - else - result = 'UNKNOWN' + when -1 + result = 'ERROR' + when 1 + result = 'SUCCESS' + else + result = 'UNKNOWN' end result end - end end end diff --git a/core/main/models/commandmodule.rb b/core/main/models/commandmodule.rb index 0df984812..60b0b336d 100644 --- a/core/main/models/commandmodule.rb +++ b/core/main/models/commandmodule.rb @@ -12,9 +12,14 @@ module Models include DataMapper::Resource storage_names[:default] = 'core_commandmodules' - + + # @note command module ID property :id, Serial + + # @note command module name property :name, Text, :lazy => false + + # @note command module path property :path, Text, :lazy => false has n, :commands diff --git a/core/main/models/hookedbrowser.rb b/core/main/models/hookedbrowser.rb index 572780809..f5cc3065e 100644 --- a/core/main/models/hookedbrowser.rb +++ b/core/main/models/hookedbrowser.rb @@ -14,27 +14,42 @@ module Models include DataMapper::Resource storage_names[:default] = 'core_hookedbrowsers' - + + # @note zombie ID property :id, Serial + + # @note hooked browser session ID property :session, Text, :lazy => false + + # @note IP address of the hooked browser property :ip, Text, :lazy => false + + # @note timestamp first time the browser communicated with BeEF property :firstseen, String, :length => 15 + + # @note timestamp last time the browser communicated with BeEF property :lastseen, String, :length => 15 + + # @note HTTP headers sent be the browser to the BeEF server upon first hook property :httpheaders, Text, :lazy => false + # @note the domain originating the hook request property :domain, Text, :lazy => false + + # @note the port on the domain originating the hook request property :port, Integer, :default => 80 + + # @note number of times the zombie has polled property :count, Integer, :lazy => false - property :has_init, Boolean, :default => false - property :is_proxy, Boolean, :default => false + # @note if true the HB is used as a tunneling proxy + property :is_proxy, Boolean, :default => false has n, :commands has n, :results has n, :logs - #has n, :https - # Increases the count of a zombie + # @note Increases the count of a zombie def count! if not self.count.nil? then self.count += 1; else self.count = 1; end end diff --git a/core/main/network_stack/websocket/websocket.rb b/core/main/network_stack/websocket/websocket.rb index 9f457b9d3..7a0666571 100644 --- a/core/main/network_stack/websocket/websocket.rb +++ b/core/main/network_stack/websocket/websocket.rb @@ -195,7 +195,7 @@ module BeEF command_status = data["status"] (print_error "BeEFhook is invalid"; return) unless BeEF::Filters.is_valid_hook_session_id?(hooked_browser) - (print_error "command_id is invalid"; return) unless BeEF::Filters.is_valid_command_id?(command_id) + (print_error "command_id is invalid"; return) unless command_id.integer? (print_error "command name is empty"; return) if handler.empty? (print_error "command results are empty"; return) if command_results.empty? (print_error "command status is invalid"; return) unless command_status =~ /\A0|1|2|undefined\z/ diff --git a/core/main/server.rb b/core/main/server.rb index 13faf402e..155f1da2c 100644 --- a/core/main/server.rb +++ b/core/main/server.rb @@ -55,7 +55,7 @@ module BeEF # def mount(url, http_handler_class, args = nil) # argument type checking - raise Exception::TypeError, '"url" needs to be a string' unless url.string? + raise TypeError, '"url" needs to be a string' unless url.string? if args.nil? @mounts[url] = http_handler_class @@ -71,7 +71,7 @@ module BeEF # @param [String] url URL to unmount. # def unmount(url) - raise Exception::TypeError, '"url" needs to be a string' unless url.string? + raise TypeError, '"url" needs to be a string' unless url.string? @mounts.delete url end diff --git a/extensions/admin_ui/controllers/panel/panel.rb b/extensions/admin_ui/controllers/panel/panel.rb index 27a810db5..4bf5158a8 100644 --- a/extensions/admin_ui/controllers/panel/panel.rb +++ b/extensions/admin_ui/controllers/panel/panel.rb @@ -49,7 +49,7 @@ module BeEF }, # the rules for the distributed engine - 'ditributed-engine-rules' => distributed_engine_rules + 'distributed-engine-rules' => distributed_engine_rules } @body = ret.to_json diff --git a/extensions/admin_ui/media/javascript/ui/panel/PanelViewer.js b/extensions/admin_ui/media/javascript/ui/panel/PanelViewer.js index cb15e45ee..5b5dd2e5e 100644 --- a/extensions/admin_ui/media/javascript/ui/panel/PanelViewer.js +++ b/extensions/admin_ui/media/javascript/ui/panel/PanelViewer.js @@ -58,7 +58,7 @@ Ext.TaskMgr.start({ var hr = document.getElementById("header-right"); hr.innerHTML = "You appear to be logged out. Login"; } - var distributed_engine_rules = (updates['ditributed-engine-rules']) ? updates['ditributed-engine-rules'] : null; + var distributed_engine_rules = (updates['distributed-engine-rules']) ? updates['distributed-engine-rules'] : null; beefwui.hooked_browsers = (updates['hooked-browsers']); //? updates['hooked-browsers'] : null; var hooked_browsers = (updates['hooked-browsers']) ? updates['hooked-browsers'] : null;