diff --git a/beef b/beef index edaf82cf3..15925fcc3 100755 --- a/beef +++ b/beef @@ -7,7 +7,7 @@ # # -# @note stop deprecation warning from being displayed +# @note stop Fixnum deprecation warning from being displayed # $VERBOSE = nil @@ -26,7 +26,7 @@ end # if RUBY_PLATFORM.downcase.include?('mswin') || RUBY_PLATFORM.downcase.include?('mingw') puts - puts "Ruby platform #{RUBY_PLATFORM} is no longer supported." + puts "Ruby platform #{RUBY_PLATFORM} is not supported." puts exit 1 end @@ -38,23 +38,21 @@ $root_dir = File.join(File.expand_path(File.dirname(File.realpath(__FILE__))), ' $:.unshift($root_dir) $home_dir = File.expand_path("#{Dir.home}/.beef/", __FILE__).freeze +# +# @note Create ~/.beef/ +# +begin + FileUtils.mkdir_p($home_dir) unless File.directory?($home_dir) +rescue => e + print_error "Could not create '#{$home_dir}': #{e.message}" + exit 1 +end + # # @note Require core loader's # require 'core/loader' -# -# @note Check the system language settings for UTF-8 compatibility -# -env_lang = ENV['LANG'] -if env_lang !~ /(utf8|utf-8)/i - print_warning "Warning: System language $LANG does not appear to be UTF-8 compatible." - if env_lang =~ /\A([a-z]+_[a-z]+)\./i - country = $1 - print_more "Try: export LANG=#{country}.utf8" - end -end - # # @note Initialize the Configuration object. Loads a different config.yaml if -c flag was passed. # @@ -65,20 +63,20 @@ else end # -# @note After the BeEF core is loaded, bootstrap the rest of the framework internals +# @note set log level # -require 'core/bootstrap' +BeEF.logger.level = config.get('beef.debug') ? Logger::DEBUG : Logger::WARN # -# @note Loads enabled extensions +# @note Check the system language settings for UTF-8 compatibility # -BeEF::Extensions.load - -# -# @note Prints the BeEF ascii art if the -a flag was passed -# -if BeEF::Core::Console::CommandLine.parse[:ascii_art] == true - BeEF::Core::Console::Banners.print_ascii_art +env_lang = ENV['LANG'] +if env_lang !~ /(utf8|utf-8)/i + print_warning "Warning: System language $LANG '#{env_lang}' does not appear to be UTF-8 compatible." + if env_lang =~ /\A([a-z]+_[a-z]+)\./i + country = $1 + print_more "Try: export LANG=#{country}.utf8" + end end # @@ -92,11 +90,65 @@ unless BeEF::Core::Console::CommandLine.parse[:ws_port].empty? config.set('beef.http.websocket.port', BeEF::Core::Console::CommandLine.parse[:ws_port]) end +# +# @note Validate configuration file +# +unless BeEF::Core::Configuration.instance.validate + exit 1 +end + +# +# @note Exit on default credentials +# +if config.get("beef.credentials.user").eql?('beef') && config.get("beef.credentials.passwd").eql?('beef') + print_error "ERROR: Default username and password in use!" + print_more "Change the beef.credentials.passwd in config.yaml" + exit 1 +end + +# +# @note Validate beef.http.public and beef.http.public_port +# +unless config.get('beef.http.public').to_s.eql?('') || BeEF::Filters.is_valid_hostname?(config.get('beef.http.public')) + print_error "ERROR: Invalid public hostname: #{config.get('beef.http.public')}" + exit 1 +end + +unless config.get('beef.http.public_port').to_s.eql?('') || BeEF::Filters.is_valid_port?(config.get('beef.http.public_port')) + print_error "ERROR: Invalid public port: #{config.get('beef.http.public_port')}" + exit 1 +end + +# +# @note Validate database driver +# +unless ['sqlite', 'postgres', 'mysql'].include? config.get('beef.database.driver') + print_error 'No default database selected. Please add one in config.yaml' + exit 1 +end + +# +# @note After the BeEF core is loaded, bootstrap the rest of the framework internals +# +require 'core/bootstrap' + +# +# @note Prints the BeEF ascii art if the -a flag was passed +# +if BeEF::Core::Console::CommandLine.parse[:ascii_art] == true + BeEF::Core::Console::Banners.print_ascii_art +end + # # @note Prints BeEF welcome message # BeEF::Core::Console::Banners.print_welcome_msg +# +# @note Loads enabled extensions +# +BeEF::Extensions.load + # # @note Loads enabled modules # @@ -112,7 +164,7 @@ Socket.do_not_reverse_lookup = true # case config.get("beef.database.driver") when "sqlite" - DataMapper.setup(:default, "sqlite3://#{$root_dir}/#{config.get("beef.database.db_file")}") + DataMapper.setup(:default, "sqlite3://#{$home_dir}/beef.db") when "mysql", "postgres" DataMapper.setup(:default, :adapter => config.get("beef.database.driver"), @@ -142,7 +194,7 @@ begin rescue => e print_error "Could not connect to database: #{e.message}" if config.get("beef.database.driver") == 'sqlite' - print_more "Ensure the #{config.get("beef.database.db_file")} database file is writable" + print_more "Ensure the #{$home_dir}/beef.db database file is writable" end exit 1 end @@ -171,45 +223,6 @@ BeEF::Core::Console::Banners.print_loaded_modules BeEF::Core::Console::Banners.print_network_interfaces_count BeEF::Core::Console::Banners.print_network_interfaces_routes -# -# @note Create ~/.beef/ -# -begin - FileUtils.mkdir_p($home_dir) unless File.directory?($home_dir) -rescue => e - print_error "Could not create '#{$home_dir}': #{e.message}" -end - -# -# @note Check whether we load the Console Shell or not -# -if config.get("beef.extension.console.shell.enable") == true - print_error "The console extension is currently unsupported." - print_more "See issue #1090 - https://github.com/beefproject/beef/issues/1090" -end - -# -# @note Exit on default credentials -# -if config.get("beef.credentials.user").eql?('beef') && config.get("beef.credentials.passwd").eql?('beef') - print_error "ERROR: Default username and password in use!" - print_more "Change the beef.credentials.passwd in config.yaml" - exit 1 -end - -# -# @note Validate beef.http.public and beef.http.public_port -# -unless config.get('beef.http.public').to_s.eql?('') || BeEF::Filters.is_valid_hostname?(config.get('beef.http.public')) - print_error "ERROR: Invalid public hostname: #{config.get('beef.http.public')}" - exit 1 -end - -unless config.get('beef.http.public_port').to_s.eql?('') || BeEF::Filters.is_valid_port?(config.get('beef.http.public_port')) - print_error "ERROR: Invalid public port: #{config.get('beef.http.public_port')}" - exit 1 -end - # # @note Prints the API key needed to use the RESTful API # diff --git a/config.yaml b/config.yaml index 25bbb1e07..ac9abbaa4 100644 --- a/config.yaml +++ b/config.yaml @@ -102,9 +102,6 @@ beef: # Finally, run a 'bundle install' command and start BeEF. driver: "sqlite" - # db_file is only used for sqlite - db_file: "beef.db" - # db connection information is only used for mysql/postgres db_host: "localhost" db_port: 3306 diff --git a/core/loader.rb b/core/loader.rb index 9c9cb4310..10c57333b 100644 --- a/core/loader.rb +++ b/core/loader.rb @@ -40,6 +40,10 @@ require 'optparse' require 'resolv' require 'digest' require 'zip' +require 'logger' + +# @note Logger +require 'core/logger' # @note Include the filters require 'core/filters' diff --git a/core/logger.rb b/core/logger.rb new file mode 100644 index 000000000..0d16bf497 --- /dev/null +++ b/core/logger.rb @@ -0,0 +1,21 @@ +# +# Copyright (c) 2006-2019 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# + +# +# @note log to file +# +module BeEF + class << self + attr_writer :logger + + def logger + @logger ||= Logger.new("#{$home_dir}/beef.log").tap do |log| + log.progname = self.name + log.level = Logger::WARN + end + end + end +end diff --git a/core/main/configuration.rb b/core/main/configuration.rb index 6ad8dfc1b..d3449bf12 100644 --- a/core/main/configuration.rb +++ b/core/main/configuration.rb @@ -30,8 +30,8 @@ module BeEF @config.default = nil @@config = config rescue => e - print_error "Fatal Error: cannot load configuration file" - print_debug e + print_error "Fatal Error: cannot load configuration file '#{file}' : #{e.message}" + print_error e.backtrace end @@instance = self @@ -45,8 +45,35 @@ module BeEF raw = File.read file YAML.safe_load raw rescue => e - print_debug "Unable to load '#{file}' #{e}" - nil + print_debug "Unable to load configuration file '#{file}' : #{e.message}" + print_error e.backtrace + end + + # + # @note balidate the configuration file + # + def validate + if @config.empty? + print_error 'Configuration file is empty' + return + end + + if @config['beef'].nil? + print_error "Configuration file is malformed: 'beef' is nil" + return + end + + if @config['beef']['credentials'].nil? + print_error "Configuration file is malformed: 'beef.credentials' is nil" + return + end + + if @config['beef']['http'].nil? + print_error "Configuration file is malformed: 'beef.http' is nil" + return + end + + true end # diff --git a/core/main/network_stack/websocket/websocket.rb b/core/main/network_stack/websocket/websocket.rb index 361fe8205..69b521f7b 100644 --- a/core/main/network_stack/websocket/websocket.rb +++ b/core/main/network_stack/websocket/websocket.rb @@ -96,7 +96,7 @@ module BeEF print_debug "[WebSocket] New message: #{msg_hash}" if @@debug rescue => e print_error "[WebSocket] Failed parsing WebSocket message: #{e.message}" - puts e.backtrace + print_error e.backtrace next end diff --git a/core/main/server.rb b/core/main/server.rb index 708713e60..4536b1ed5 100644 --- a/core/main/server.rb +++ b/core/main/server.rb @@ -154,7 +154,7 @@ module BeEF end rescue => e print_error "Failed to prepare HTTP server: #{e.message}" - puts e.backtrace + print_error e.backtrace exit 1 end diff --git a/core/ruby/print.rb b/core/ruby/print.rb index f1ee1e9a2..9205ed318 100644 --- a/core/ruby/print.rb +++ b/core/ruby/print.rb @@ -8,12 +8,14 @@ # @param [String] s String to be printed def print_error(s) puts Time.now.localtime.strftime("[%k:%M:%S]")+'[!]'.red+' '+s + BeEF.logger.error s.to_s end # Function used to print information to the console # @param [String] s String to be printed def print_info(s) puts Time.now.localtime.strftime("[%k:%M:%S]")+'[*]'.blue+' '+s + BeEF.logger.info s.to_s end # Function used to print information to the console (wraps print_info) @@ -26,6 +28,7 @@ end # @param [String] s String to be printed def print_warning(s) puts Time.now.localtime.strftime("[%k:%M:%S]")+'[!]'.yellow+' '+s.to_s + BeEF.logger.warn s.to_s end # Function used to print debug information @@ -35,6 +38,7 @@ def print_debug(s) config = BeEF::Core::Configuration.instance if config.get('beef.debug') || BeEF::Core::Console::CommandLine.parse[:verbose] puts Time.now.localtime.strftime("[%k:%M:%S]")+'[>]'.yellow+' '+s.to_s + BeEF.logger.debug s.to_s end end @@ -42,6 +46,7 @@ end # @param [String] s String to be printed def print_success(s) puts Time.now.localtime.strftime("[%k:%M:%S]")+'[+]'.green+' '+s + BeEF.logger.info s.to_s end # Function used to print successes to the console (wraps print_success) @@ -65,8 +70,10 @@ def print_more(s) lines.each_with_index do |line, index| if ((index+1) == lines.size) puts "#{time} |_ #{line}" + BeEF.logger.info "#{time} |_ #{line}" else puts "#{time} | #{line}" + BeEF.logger.info "#{time} | #{line}" end end end @@ -77,4 +84,5 @@ end def print_over(s) time = Time.now.localtime.strftime("[%k:%M:%S]") print "\r#{time}"+"[*]".blue+" #{s}" + BeEF.logger.info s.to_s end diff --git a/extensions/admin_ui/api/handler.rb b/extensions/admin_ui/api/handler.rb index ef107a68b..39ac554ac 100644 --- a/extensions/admin_ui/api/handler.rb +++ b/extensions/admin_ui/api/handler.rb @@ -43,7 +43,7 @@ module API File.path write_to rescue => e print_error "[AdminUI] Error: #{e.message}" - puts e.backtrace + print_error e.backtrace end def self.build_javascript_ui(beef_server) diff --git a/extensions/admin_ui/classes/httpcontroller.rb b/extensions/admin_ui/classes/httpcontroller.rb index e0a01423c..ff7fbe4f9 100644 --- a/extensions/admin_ui/classes/httpcontroller.rb +++ b/extensions/admin_ui/classes/httpcontroller.rb @@ -81,7 +81,7 @@ module AdminUI end rescue => e print_error "Error handling HTTP request: #{e.message}" - puts e.backtrace + print_error e.backtrace end # Constructs a html script tag (from media/javascript directory) diff --git a/extensions/console/extension.rb b/extensions/console/extension.rb index a2a53083a..04d416d85 100644 --- a/extensions/console/extension.rb +++ b/extensions/console/extension.rb @@ -15,6 +15,18 @@ module Console @short_name = @full_name = 'console' @description = 'console environment to manage beef' + module PostLoad + BeEF::API::Registrar.instance.register(BeEF::Extension::Console::PostLoad, BeEF::API::Extensions, 'post_load') + + def self.post_load + if BeEF::Core::Configuration.instance.get("beef.extension.console.enable") + print_error "The console extension is currently unsupported." + print_more "See issue #1090 - https://github.com/beefproject/beef/issues/1090" + BeEF::Core::Configuration.instance.set('beef.extension.console.enable', false) + BeEF::Core::Configuration.instance.set('beef.extension.console.loaded', false) + end + end + end end end end diff --git a/extensions/evasion/evasion.rb b/extensions/evasion/evasion.rb index 0e4032b24..cec3ea1b3 100644 --- a/extensions/evasion/evasion.rb +++ b/extensions/evasion/evasion.rb @@ -66,7 +66,7 @@ module BeEF bootstrap rescue => e print_error "[Evasion] Failed to bootstrap obfuscation technique: #{e.message}" - puts e.backtrace + print_error e.backtrace end def apply_chain(input) @@ -83,7 +83,7 @@ module BeEF output rescue => e print_error "[Evasion] Failed to apply obfuscation technique: #{e.message}" - puts e.backtrace + print_error e.backtrace end end end diff --git a/extensions/metasploit/api.rb b/extensions/metasploit/api.rb index b42c3e18f..d7309c3c3 100644 --- a/extensions/metasploit/api.rb +++ b/extensions/metasploit/api.rb @@ -30,14 +30,15 @@ module BeEF if connected msf_module_config = {} - path = "#{$root_dir}/#{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.path')}" - if !BeEF::Core::Console::CommandLine.parse[:resetdb] && File.exists?("#{path}msf-exploits.cache") - print_debug "Attempting to use Metasploit exploits cache file" - raw = File.read("#{path}msf-exploits.cache") + path = "#{$root_dir}/#{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.path')}/msf-exploits.cache" + if !BeEF::Core::Console::CommandLine.parse[:resetdb] && File.exist?(path) + print_debug 'Attempting to use Metasploit exploits cache file' + raw = File.read(path) begin msf_module_config = YAML.load(raw) rescue => e - puts e + print_error "[Metasploit] #{e.message}" + print_error e.backtrace end count = 1 msf_module_config.each { |k, v| @@ -102,9 +103,9 @@ module BeEF end } print "\r\n" - File.open("#{path}msf-exploits.cache", "w") do |f| + File.open(path, "w") do |f| f.write(msf_module_config.to_yaml) - print_debug "Wrote Metasploit exploits to cache file" + print_debug "Wrote Metasploit exploits to cache file: #{path}" end end BeEF::Core::Configuration.instance.set('beef.module', msf_module_config) diff --git a/extensions/metasploit/rpcclient.rb b/extensions/metasploit/rpcclient.rb index 913622f9c..855f7c7d1 100644 --- a/extensions/metasploit/rpcclient.rb +++ b/extensions/metasploit/rpcclient.rb @@ -128,7 +128,7 @@ module Metasploit super(meth, *args) rescue => e print_error "[Metasploit] RPC call to '#{meth}' failed: #{e}" - puts e.backtrace + print_error e.backtrace return end