Commit 87d08aa4 authored by Sophie Brun's avatar Sophie Brun

New upstream version 0.4.7.3

parent e9e18f39
......@@ -3,7 +3,7 @@ Verify first that your issue/request has not been posted previously:
* https://github.com/beefproject/beef/issues
* https://github.com/beefproject/beef/wiki/FAQ
Ensure you're using the [latest version of BeEF](https://github.com/beefproject/beef/releases/tag/beef-0.4.7.1).
Ensure you're using the [latest version of BeEF](https://github.com/beefproject/beef/releases/tag/beef-0.4.7.2).
#### Environment
......
......@@ -4,4 +4,4 @@
# See the file 'doc/COPYING' for copying permission
#
0.4.7.1-alpha
0.4.7.3-alpha
......@@ -7,7 +7,7 @@
#
#
# @note stop deprecation warning from being displayed
# @note stop Fixnum deprecation warning from being displayed
#
$VERBOSE = nil
......@@ -26,7 +26,7 @@ end
#
if RUBY_PLATFORM.downcase.include?('mswin') || RUBY_PLATFORM.downcase.include?('mingw')
puts
puts "Ruby platform #{RUBY_PLATFORM} is no longer supported."
puts "Ruby platform #{RUBY_PLATFORM} is not supported."
puts
exit 1
end
......@@ -39,20 +39,18 @@ $:.unshift($root_dir)
$home_dir = File.expand_path("#{Dir.home}/.beef/", __FILE__).freeze
#
# @note Require core loader's
# @note Require core loader
#
require 'core/loader'
#
# @note Check the system language settings for UTF-8 compatibility
# @note Create ~/.beef/
#
env_lang = ENV['LANG']
if env_lang !~ /(utf8|utf-8)/i
print_warning "Warning: System language $LANG does not appear to be UTF-8 compatible."
if env_lang =~ /\A([a-z]+_[a-z]+)\./i
country = $1
print_more "Try: export LANG=#{country}.utf8"
end
begin
FileUtils.mkdir_p($home_dir) unless File.directory?($home_dir)
rescue => e
print_error "Could not create '#{$home_dir}': #{e.message}"
exit 1
end
#
......@@ -65,20 +63,20 @@ else
end
#
# @note After the BeEF core is loaded, bootstrap the rest of the framework internals
# @note set log level
#
require 'core/bootstrap'
BeEF.logger.level = config.get('beef.debug') ? Logger::DEBUG : Logger::WARN
#
# @note Loads enabled extensions
#
BeEF::Extensions.load
#
# @note Prints the BeEF ascii art if the -a flag was passed
# @note Check the system language settings for UTF-8 compatibility
#
if BeEF::Core::Console::CommandLine.parse[:ascii_art] == true
BeEF::Core::Console::Banners.print_ascii_art
env_lang = ENV['LANG']
if env_lang !~ /(utf8|utf-8)/i
print_warning "Warning: System language $LANG '#{env_lang}' does not appear to be UTF-8 compatible."
if env_lang =~ /\A([a-z]+_[a-z]+)\./i
country = $1
print_more "Try: export LANG=#{country}.utf8"
end
end
#
......@@ -92,11 +90,65 @@ unless BeEF::Core::Console::CommandLine.parse[:ws_port].empty?
config.set('beef.http.websocket.port', BeEF::Core::Console::CommandLine.parse[:ws_port])
end
#
# @note Validate configuration file
#
unless BeEF::Core::Configuration.instance.validate
exit 1
end
#
# @note Exit on default credentials
#
if config.get("beef.credentials.user").eql?('beef') && config.get("beef.credentials.passwd").eql?('beef')
print_error "ERROR: Default username and password in use!"
print_more "Change the beef.credentials.passwd in config.yaml"
exit 1
end
#
# @note Validate beef.http.public and beef.http.public_port
#
unless config.get('beef.http.public').to_s.eql?('') || BeEF::Filters.is_valid_hostname?(config.get('beef.http.public'))
print_error "ERROR: Invalid public hostname: #{config.get('beef.http.public')}"
exit 1
end
unless config.get('beef.http.public_port').to_s.eql?('') || BeEF::Filters.is_valid_port?(config.get('beef.http.public_port'))
print_error "ERROR: Invalid public port: #{config.get('beef.http.public_port')}"
exit 1
end
#
# @note Validate database driver
#
unless ['sqlite', 'postgres', 'mysql'].include? config.get('beef.database.driver')
print_error 'No default database selected. Please add one in config.yaml'
exit 1
end
#
# @note After the BeEF core is loaded, bootstrap the rest of the framework internals
#
require 'core/bootstrap'
#
# @note Prints the BeEF ascii art if the -a flag was passed
#
if BeEF::Core::Console::CommandLine.parse[:ascii_art] == true
BeEF::Core::Console::Banners.print_ascii_art
end
#
# @note Prints BeEF welcome message
#
BeEF::Core::Console::Banners.print_welcome_msg
#
# @note Loads enabled extensions
#
BeEF::Extensions.load
#
# @note Loads enabled modules
#
......@@ -142,7 +194,7 @@ begin
rescue => e
print_error "Could not connect to database: #{e.message}"
if config.get("beef.database.driver") == 'sqlite'
print_more "Ensure the #{config.get("beef.database.db_file")} database file is writable"
print_error "Ensure the #{$root_dir}/#{config.get("beef.database.db_file")} database file is writable"
end
exit 1
end
......@@ -171,45 +223,6 @@ BeEF::Core::Console::Banners.print_loaded_modules
BeEF::Core::Console::Banners.print_network_interfaces_count
BeEF::Core::Console::Banners.print_network_interfaces_routes
#
# @note Create ~/.beef/
#
begin
FileUtils.mkdir_p($home_dir) unless File.directory?($home_dir)
rescue => e
print_error "Could not create '#{$home_dir}': #{e.message}"
end
#
# @note Check whether we load the Console Shell or not
#
if config.get("beef.extension.console.shell.enable") == true
print_error "The console extension is currently unsupported."
print_more "See issue #1090 - https://github.com/beefproject/beef/issues/1090"
end
#
# @note Exit on default credentials
#
if config.get("beef.credentials.user").eql?('beef') && config.get("beef.credentials.passwd").eql?('beef')
print_error "ERROR: Default username and password in use!"
print_more "Change the beef.credentials.passwd in config.yaml"
exit 1
end
#
# @note Validate beef.http.public and beef.http.public_port
#
unless config.get('beef.http.public').to_s.eql?('') || BeEF::Filters.is_valid_hostname?(config.get('beef.http.public'))
print_error "ERROR: Invalid public hostname: #{config.get('beef.http.public')}"
exit 1
end
unless config.get('beef.http.public_port').to_s.eql?('') || BeEF::Filters.is_valid_port?(config.get('beef.http.public_port'))
print_error "ERROR: Invalid public port: #{config.get('beef.http.public_port')}"
exit 1
end
#
# @note Prints the API key needed to use the RESTful API
#
......
......@@ -6,7 +6,7 @@
# BeEF Configuration file
beef:
version: '0.4.7.1-alpha'
version: '0.4.7.3-alpha'
# More verbose messages (server-side)
debug: false
# More verbose messages (client-side)
......@@ -23,10 +23,10 @@ beef:
# Interface / IP restrictions
restrictions:
# subnet of IP addresses that can hook to the framework
permitted_hooking_subnet: "0.0.0.0/0"
permitted_hooking_subnet: ["0.0.0.0/0", "::/0"]
# subnet of IP addresses that can connect to the admin UI
#permitted_ui_subnet: "127.0.0.1/32"
permitted_ui_subnet: "0.0.0.0/0"
#permitted_ui_subnet: ["127.0.0.1/32", "::1/128"]
permitted_ui_subnet: ["0.0.0.0/0", "::/0"]
# slow API calls to 1 every api_attempt_delay seconds
api_attempt_delay: "0.05"
......
......@@ -32,6 +32,7 @@ require 'ansi'
require 'term/ansicolor'
require 'json'
require 'data_objects'
require 'dm-do-adapter'
require 'parseconfig'
require 'erubis'
require 'mime/types'
......@@ -39,6 +40,10 @@ require 'optparse'
require 'resolv'
require 'digest'
require 'zip'
require 'logger'
# @note Logger
require 'core/logger'
# @note Include the filters
require 'core/filters'
......
#
# Copyright (c) 2006-2019 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - http://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
#
# @note log to file
#
module BeEF
class << self
attr_writer :logger
def logger
@logger ||= Logger.new("#{$home_dir}/beef.log").tap do |log|
log.progname = self.name
log.level = Logger::WARN
end
end
end
end
......@@ -30,8 +30,8 @@ module BeEF
@config.default = nil
@@config = config
rescue => e
print_error "Fatal Error: cannot load configuration file"
print_debug e
print_error "Fatal Error: cannot load configuration file '#{config}' : #{e.message}"
print_error e.backtrace
end
@@instance = self
......@@ -45,8 +45,35 @@ module BeEF
raw = File.read file
YAML.safe_load raw
rescue => e
print_debug "Unable to load '#{file}' #{e}"
nil
print_debug "Unable to load configuration file '#{file}' : #{e.message}"
print_error e.backtrace
end
#
# @note balidate the configuration file
#
def validate
if @config.empty?
print_error 'Configuration file is empty'
return
end
if @config['beef'].nil?
print_error "Configuration file is malformed: 'beef' is nil"
return
end
if @config['beef']['credentials'].nil?
print_error "Configuration file is malformed: 'beef.credentials' is nil"
return
end
if @config['beef']['http'].nil?
print_error "Configuration file is malformed: 'beef.http' is nil"
return
end
true
end
#
......
......@@ -30,10 +30,19 @@ module Handlers
# @note check source ip address of browser
permitted_hooking_subnet = config.get('beef.restrictions.permitted_hooking_subnet')
target_network = IPAddr.new(permitted_hooking_subnet)
if not target_network.include?(request.ip)
BeEF::Core::Logger.instance.register('Target Range', "Attempted hook from out of target range browser (#{request.ip}) rejected.")
error 500
if permitted_hooking_subnet.nil? || permitted_hooking_subnet.empty?
BeEF::Core::Logger.instance.register('Target Range', "Attempted hook from outside of permitted hooking subnet (#{request.ip}) rejected.")
error 404
end
found = false
permitted_hooking_subnet.each do |subnet|
found = true if IPAddr.new(subnet).include?(request.ip)
end
unless found
BeEF::Core::Logger.instance.register('Target Range', "Attempted hook from outside of permitted hooking subnet (#{request.ip}) rejected.")
error 404
end
# @note get zombie if already hooked the framework
......
......@@ -96,7 +96,7 @@ module BeEF
print_debug "[WebSocket] New message: #{msg_hash}" if @@debug
rescue => e
print_error "[WebSocket] Failed parsing WebSocket message: #{e.message}"
puts e.backtrace
print_error e.backtrace
next
end
......
......@@ -70,15 +70,20 @@ module BeEF
# This is from extensions/admin_ui/controllers/authentication/authentication.rb
#
def self.permitted_source?(ip)
# get permitted subnet
# test if supplied IP address is valid
return false unless BeEF::Filters::is_valid_ip?(ip)
# get permitted subnets
permitted_ui_subnet = BeEF::Core::Configuration.instance.get("beef.restrictions.permitted_ui_subnet")
target_network = IPAddr.new(permitted_ui_subnet)
return false if permitted_ui_subnet.nil?
return false if permitted_ui_subnet.empty?
# test if supplied IP address is valid dot-decimal format
return false unless ip =~ /\A[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\z/
# test if ip within subnets
permitted_ui_subnet.each do |subnet|
return true if IPAddr.new(subnet).include?(ip)
end
# test if ip within subnet
return target_network.include?(ip)
false
end
#
......
......@@ -154,7 +154,7 @@ module BeEF
end
rescue => e
print_error "Failed to prepare HTTP server: #{e.message}"
puts e.backtrace
print_error e.backtrace
exit 1
end
......
......@@ -14,6 +14,3 @@ require 'core/ruby/string'
require 'core/ruby/print'
require 'core/ruby/hash'
# @note Patching DataMapper Data Objects Adapter (dm-do-adapter)
require 'core/ruby/patches/dm-do-adapter/adapter.rb'
#
# Copyright (c) 2006-2019 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - http://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# @note The following file contains patches for DataMapper Data Objects Adapter (dm-do-adapter)
# This patch fixes the following error:
# DataObjects::URI.new with arguments is deprecated, use a Hash of URI components (/home/username/.rvm/gems/ruby-1.9.2-p290/gems/dm-do-adapter-1.1.0/lib/dm-do-adapter/adapter.rb:231:in `new')
# The error is patched in dm-do-adapter 1.1.1 however it has yet to be released.
# Patch: https://github.com/datamapper/dm-do-adapter/commit/7f0b53d1ada8735910e04ff37d60c6ff037ce288
=begin
Deleted:
< DataObjects::URI.new(
< @options[:adapter],
< @options[:user] || @options[:username],
< @options[:password],
< @options[:host],
< port,
< @options[:path] || @options[:database],
< query,
< @options[:fragment]
< ).freeze
Added:
> DataObjects::URI.new({
> :scheme => @options[:adapter],
> :user => @options[:user] || @options[:username],
> :password => @options[:password],
> :host => @options[:host],
> :port => port,
> :path => @options[:path] || @options[:database],
> :query => query,
> :fragment => @options[:fragment]
> }).freeze
=end
require 'dm-do-adapter'
module DataMapper
module Adapters
class DataObjectsAdapter < AbstractAdapter
def normalized_uri
@normalized_uri ||=
begin
keys = [
:adapter, :user, :password, :host, :port, :path, :fragment,
:scheme, :query, :username, :database ]
query = DataMapper::Ext::Hash.except(@options, keys)
query = nil if query.empty?
# Better error message in case port is no Numeric value
port = @options[:port].nil? ? nil : @options[:port].to_int
DataObjects::URI.new({
:scheme => @options[:adapter],
:user => @options[:user] || @options[:username],
:password => @options[:password],
:host => @options[:host],
:port => port,
:path => @options[:path] || @options[:database],
:query => query,
:fragment => @options[:fragment]
}).freeze
end
end
end
end
end
......@@ -8,12 +8,14 @@
# @param [String] s String to be printed
def print_error(s)
puts Time.now.localtime.strftime("[%k:%M:%S]")+'[!]'.red+' '+s
BeEF.logger.error s.to_s
end
# Function used to print information to the console
# @param [String] s String to be printed
def print_info(s)
puts Time.now.localtime.strftime("[%k:%M:%S]")+'[*]'.blue+' '+s
BeEF.logger.info s.to_s
end
# Function used to print information to the console (wraps print_info)
......@@ -26,6 +28,7 @@ end
# @param [String] s String to be printed
def print_warning(s)
puts Time.now.localtime.strftime("[%k:%M:%S]")+'[!]'.yellow+' '+s.to_s
BeEF.logger.warn s.to_s
end
# Function used to print debug information
......@@ -35,6 +38,7 @@ def print_debug(s)
config = BeEF::Core::Configuration.instance
if config.get('beef.debug') || BeEF::Core::Console::CommandLine.parse[:verbose]
puts Time.now.localtime.strftime("[%k:%M:%S]")+'[>]'.yellow+' '+s.to_s
BeEF.logger.debug s.to_s
end
end
......@@ -42,6 +46,7 @@ end
# @param [String] s String to be printed
def print_success(s)
puts Time.now.localtime.strftime("[%k:%M:%S]")+'[+]'.green+' '+s
BeEF.logger.info s.to_s
end
# Function used to print successes to the console (wraps print_success)
......@@ -65,8 +70,10 @@ def print_more(s)
lines.each_with_index do |line, index|
if ((index+1) == lines.size)
puts "#{time} |_ #{line}"
BeEF.logger.info "#{time} |_ #{line}"
else
puts "#{time} | #{line}"
BeEF.logger.info "#{time} | #{line}"
end
end
end
......@@ -77,4 +84,5 @@ end
def print_over(s)
time = Time.now.localtime.strftime("[%k:%M:%S]")
print "\r#{time}"+"[*]".blue+" #{s}"
BeEF.logger.info s.to_s
end
......@@ -43,7 +43,7 @@ module API
File.path write_to
rescue => e
print_error "[AdminUI] Error: #{e.message}"
puts e.backtrace
print_error e.backtrace
end
def self.build_javascript_ui(beef_server)
......
......@@ -81,7 +81,7 @@ module AdminUI
end
rescue => e
print_error "Error handling HTTP request: #{e.message}"
puts e.backtrace
print_error e.backtrace
end
# Constructs a html script tag (from media/javascript directory)
......
......@@ -47,8 +47,8 @@ class Authentication < BeEF::Extension::AdminUI::HttpController
ua_ip = @request.ip # get client ip address
@body = '{ success : false }' # attempt to fail closed
# check if source IP address is permited to authenticate
if not permited_source?(ua_ip)
# check if source IP address is permitted to authenticate
if not permitted_source?(ua_ip)
BeEF::Core::Logger.instance.register('Authentication', "IP source address (#{@request.ip}) attempted to authenticate but is not within permitted subnet.")
return
end
......@@ -105,19 +105,22 @@ class Authentication < BeEF::Extension::AdminUI::HttpController
#
# Check the UI browser source IP is within the permitted subnet
#
def permited_source?(ip)
# get permitted subnet
config = BeEF::Core::Configuration.instance
permitted_ui_subnet = config.get('beef.restrictions.permitted_ui_subnet')
target_network = IPAddr.new(permitted_ui_subnet)
# test if supplied IP address is valid dot-decimal format
return false unless ip =~ /\A[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\z/
# test if ip within subnet
return target_network.include?(ip)
end
def permitted_source?(ip)
# test if supplied IP address is valid
return false unless BeEF::Filters::is_valid_ip?(ip)
# get permitted subnets
permitted_ui_subnet = BeEF::Core::Configuration.instance.get("beef.restrictions.permitted_ui_subnet")
return false if permitted_ui_subnet.nil?
return false if permitted_ui_subnet.empty?
# test if ip within subnets
permitted_ui_subnet.each do |subnet|
return true if IPAddr.new(subnet).include?(ip)
end
false
end
end
end
......
......@@ -15,6 +15,18 @@ module Console
@short_name = @full_name = 'console'
@description = 'console environment to manage beef'
module PostLoad
BeEF::API::Registrar.instance.register(BeEF::Extension::Console::PostLoad, BeEF::API::Extensions, 'post_load')
def self.post_load
if BeEF::Core::Configuration.instance.get("beef.extension.console.enable")
print_error "The console extension is currently unsupported."
print_more "See issue #1090 - https://github.com/beefproject/beef/issues/1090"
BeEF::Core::Configuration.instance.set('beef.extension.console.enable', false)
BeEF::Core::Configuration.instance.set('beef.extension.console.loaded', false)
end
end
end
end
end
end
......
......@@ -66,7 +66,7 @@ module BeEF
bootstrap
rescue => e
print_error "[Evasion] Failed to bootstrap obfuscation technique: #{e.message}"
puts e.backtrace
print_error e.backtrace
end
def apply_chain(input)
......@@ -83,7 +83,7 @@ module BeEF
output
rescue => e
print_error "[Evasion] Failed to apply obfuscation technique: #{e.message}"
puts e.backtrace
print_error e.backtrace
end
end
end
......
......@@ -30,14 +30,15 @@ module BeEF
if connected
msf_module_config = {}
path = "#{$root_dir}/#{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.path')}"
if !BeEF::Core::Console::CommandLine.parse[:resetdb] && File.exists?("#{path}msf-exploits.cache")
print_debug "Attempting to use Metasploit exploits cache file"
raw = File.read("#{path}msf-exploits.cache")
path = "#{$root_dir}/#{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.path')}/msf-exploits.cache"
if !BeEF::Core::Console::CommandLine.parse[:resetdb] && File.exist?(path)
print_debug 'Attempting to use Metasploit exploits cache file'
raw = File.read(path)
begin
msf_module_config = YAML.load(raw)
rescue => e
puts e
print_error "[Metasploit] #{e.message}"
print_error e.backtrace
end
count = 1
msf_module_config.each { |k, v|
......@@ -102,9 +103,9 @@ module BeEF
end
}
print "\r\n"
File.open("#{path}msf-exploits.cache", "w") do |f|
File.open(path, "w") do |f|
f.write(msf_module_config.to_yaml)
print_debug "Wrote Metasploit exploits to cache file"
print_debug "Wrote Metasploit exploits to cache file: #{path}"
end
end
BeEF::Core::Configuration.instance.set('beef.module', msf_module_config)
......
......@@ -128,7 +128,7 @@ module Metasploit
super(meth, *args)
rescue => e
print_error "[Metasploit] RPC call to '#{meth}' failed: #{e}"
puts e.backtrace
print_error e.backtrace
return
end
......
......@@ -171,7 +171,7 @@ module BeEF
header_key = line.split(': ')[0]
header_value = line.split(': ')[1]
next if header_key.nil?
next if ignore_headers.include?(header_key)
next if ignore_headers.any?{ |h| h.casecmp(header_key) == 0 }
if header_value.nil?
#headers_hash[header_key] = ""
else
......
......@@ -86,7 +86,7 @@ install_linux () {
Distro='Alpine'
elif [ -f /etc/os-release ] ; then
#DISTRO_ID=$(grep ^ID= /etc/os-release | cut -d= -f2-)
DISTRO_ID=$(cat /etc/os-release | grep ID= | cut -d= -f2-)
DISTRO_ID=$(cat /etc/os-release | grep ID= | grep -v "BUILD" | cut -d= -f2-)
if [ "${DISTRO_ID}" = 'kali' ] ; then
Distro='Kali'
elif [ "${DISTRO_ID}" = 'arch' ] || [ "${DISTRO_ID}" = 'manjaro' ] ; then
......@@ -207,14 +207,23 @@ install_beef () {
else
bundle install --without test development
fi
}
finish () {
echo
echo "=========================================="
echo "#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#"
echo
info "Install completed successfully!"
info "Run './beef' to launch BeEF"
echo
echo "=========================================="
echo "Next steps:"
echo
echo "* Change the default password in config.yaml"
echo "* Run ./update-geoipdb to install the Maxmind GeoIP database"
echo "* Review the wiki for important configuration information:"