diff --git a/beef b/beef index 8fe6052da1..1704b53d25 100755 --- a/beef +++ b/beef @@ -39,6 +39,16 @@ $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 Parse beef command line arguments before requiring loader. +# The loader will require bundler default arguments, bringing in Sinatra which will +# then hog the Option Parsing. Thus, we need to parse before that. +# +require 'core/main/console/commandline' +BeEF::Core::Console::CommandLine.parse + + # # @note Require core loader # @@ -48,8 +58,8 @@ require 'timeout' # # @note Ask user if they would like to update beef # -if File.exist?("#{$root_dir}git") && BeEF::Core::Console::CommandLine.parse[:update_disabled] == false - if BeEF::Core::Console::CommandLine.parse[:update_auto] == true +if File.exist?("#{$root_dir}git") && BeEF::Core::Console::CommandLine.get_options[:update_disabled] == false + if BeEF::Core::Console::CommandLine.get_options[:update_auto] == true print 'Checking latest BeEF repository and updating' `git pull && bundle` elsif `git rev-parse master` != `git rev-parse origin/master` @@ -79,10 +89,10 @@ end # # @note Initialize the Configuration object. Loads a different config.yaml if -c flag was passed. # -if BeEF::Core::Console::CommandLine.parse[:ext_config].empty? +if BeEF::Core::Console::CommandLine.get_options[:ext_config].empty? config = BeEF::Core::Configuration.new("#{$root_dir}/config.yaml") else - config = BeEF::Core::Configuration.new("#{BeEF::Core::Console::CommandLine.parse[:ext_config]}") + config = BeEF::Core::Configuration.new("#{BeEF::Core::Console::CommandLine.get_options[:ext_config]}") end # @@ -105,12 +115,12 @@ end # # @note Check if port and WebSocket port need to be updated from command line parameters # -unless BeEF::Core::Console::CommandLine.parse[:port].empty? - config.set('beef.http.port', BeEF::Core::Console::CommandLine.parse[:port]) +unless BeEF::Core::Console::CommandLine.get_options[:port].empty? + config.set('beef.http.port', BeEF::Core::Console::CommandLine.get_options[:port]) end -unless BeEF::Core::Console::CommandLine.parse[:ws_port].empty? - config.set('beef.http.websocket.port', BeEF::Core::Console::CommandLine.parse[:ws_port]) +unless BeEF::Core::Console::CommandLine.get_options[:ws_port].empty? + config.set('beef.http.websocket.port', BeEF::Core::Console::CommandLine.get_options[:ws_port]) end # @@ -150,7 +160,7 @@ require 'core/bootstrap' # # @note Prints the BeEF ascii art if the -a flag was passed # -if BeEF::Core::Console::CommandLine.parse[:ascii_art] == true +if BeEF::Core::Console::CommandLine.get_options[:ascii_art] == true BeEF::Core::Console::Banners.print_ascii_art end @@ -182,7 +192,7 @@ Socket.do_not_reverse_lookup = true # db_file = config.get('beef.database.file') # @note Resets the database if the -x flag was passed -if BeEF::Core::Console::CommandLine.parse[:resetdb] +if BeEF::Core::Console::CommandLine.get_options[:resetdb] print_info 'Resetting the database for BeEF.' begin File.delete(db_file) if File.exist?(db_file) diff --git a/core/main/console/commandline.rb b/core/main/console/commandline.rb index 75a33977b0..ca8a691a6f 100644 --- a/core/main/console/commandline.rb +++ b/core/main/console/commandline.rb @@ -3,6 +3,8 @@ # Browser Exploitation Framework (BeEF) - http://beefproject.com # See the file 'doc/COPYING' for copying permission # +require 'optparse' + module BeEF module Core module Console @@ -10,16 +12,17 @@ module Console # This module parses the command line argument when running beef. # module CommandLine - @options = {} - @options[:verbose] = false - @options[:resetdb] = false - @options[:ascii_art] = false - @options[:ext_config] = '' - @options[:port] = '' - @options[:ws_port] = '' - @options[:interactive] = false - @options[:update_disabled] = false - @options[:update_auto] = false + @options = { + verbose: false, + resetdb: false, + ascii_art: false, + ext_config: '', + port: '', + ws_port: '', + interactive: false, + update_disabled: false, + update_auto: false, + } @already_parsed = false @@ -28,7 +31,7 @@ module CommandLine # It also populates the 'options' hash. # def self.parse - return @options if @already_parsed + return if @already_parsed optparse = OptionParser.new do |opts| opts.on('-x', '--reset', 'Reset the database') do @@ -39,11 +42,11 @@ def self.parse @options[:verbose] = true end - opts.on('-a', '--ascii_art', 'Prints BeEF ascii art') do + opts.on('-a', '--ascii-art', 'Prints BeEF ascii art') do @options[:ascii_art] = true end - opts.on('-c', '--config FILE', "Load a different configuration file: if it's called custom-config.yaml, git automatically ignores it.") do |f| + opts.on('-c', '--config FILE', "Specify configuration file to load (instead of ./config.yaml)") do |f| @options[:ext_config] = f end @@ -55,26 +58,40 @@ def self.parse @options[:ws_port] = ws_port end - opts.on('-ud', '--update_disabled', 'Skips update') do + opts.on('--update-disable', 'Skips update') do @options[:update_disabled] = true end - opts.on('-ua', '--update_auto', 'Automatic update with no prompt') do + opts.on('--update-auto', 'Automatic update with no prompt') do @options[:update_auto] = true end - # opts.on('-i', '--interactive', 'Starts with the Console Shell activated') do - # @options[:interactive] = true - # end + opts.on("-h", "--help", "Prints this help") do + puts opts + exit 0 + end end + # NOTE: + # OptionParser consumes ARGV, all options are removed from it after parsing. + # If we wanted to pass Options to Sinatra, we would need to parse on a copy here. + # We don't do that since we explicitly don't want to allow users messing with these options, though. optparse.parse! @already_parsed = true - @options rescue OptionParser::InvalidOption - puts 'Invalid command line option provided. Please run beef --help' + puts 'Provided option not recognized by beef. If you provided a Sinatra option, note that beef explicitly disallows them.' exit 1 end + + # + # Return the parsed options. + # Ensures that cmd line arguments are parsed. + # + def self.get_options + parse unless @already_parsed + return @options + end + end end end diff --git a/core/ruby/print.rb b/core/ruby/print.rb index d53d42bc66..23394cedfb 100644 --- a/core/ruby/print.rb +++ b/core/ruby/print.rb @@ -36,7 +36,7 @@ def print_warning(s) # @note This function will only print messages if the debug flag is set to true def print_debug(s) config = BeEF::Core::Configuration.instance - return unless config.get('beef.debug') || BeEF::Core::Console::CommandLine.parse[:verbose] + return unless config.get('beef.debug') || BeEF::Core::Console::CommandLine.get_options[:verbose] puts Time.now.localtime.strftime('[%k:%M:%S]') + '[>]' + ' ' + s.to_s BeEF.logger.debug s.to_s diff --git a/extensions/metasploit/api.rb b/extensions/metasploit/api.rb index da9810bf11..0a15c74d22 100644 --- a/extensions/metasploit/api.rb +++ b/extensions/metasploit/api.rb @@ -28,7 +28,7 @@ def self.post_soft_load msf_module_config = {} 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) + if !BeEF::Core::Console::CommandLine.get_options[:resetdb] && File.exist?(path) print_debug 'Attempting to use Metasploit exploits cache file' raw = File.read(path) begin diff --git a/spec/beef/api/auth_rate_spec.rb b/spec/beef/api/auth_rate_spec.rb index e69811baba..750f2fba29 100644 --- a/spec/beef/api/auth_rate_spec.rb +++ b/spec/beef/api/auth_rate_spec.rb @@ -34,7 +34,7 @@ print_info "Loading database" db_file = @config.get('beef.database.file') - if BeEF::Core::Console::CommandLine.parse[:resetdb] + if BeEF::Core::Console::CommandLine.get_options[:resetdb] print_info 'Resetting the database for BeEF.' File.delete(db_file) if File.exist?(db_file) end