diff --git a/config.yaml b/config.yaml index 39103d0f8..2e8b191a9 100644 --- a/config.yaml +++ b/config.yaml @@ -46,8 +46,8 @@ beef: # Imitate a specified web server (default root page, 404 default error page, 'Server' HTTP response header) web_server_imitation: - enable: false - type: "apache" #supported: apache, iis + enable: false + type: "apache" #supported: apache, iis database: # For information on using other databases please read the @@ -66,6 +66,11 @@ beef: db_passwd: "beef123" db_encoding: "UTF-8" + # Credentials to authenticate in BeEF. Used by both the RESTful API and the Admin_UI extension + credentials: + user: "beef" + passwd: "beef" + crypto_default_value_length: 80 # You may override default extension configuration parameters here diff --git a/core/bootstrap.rb b/core/bootstrap.rb index 06da83019..747720849 100644 --- a/core/bootstrap.rb +++ b/core/bootstrap.rb @@ -30,6 +30,7 @@ require 'core/main/handlers/modules/beefjs' require 'core/main/handlers/modules/command' require 'core/main/handlers/commands' require 'core/main/handlers/hookedbrowsers' +require 'core/main/handlers/browserdetails' # @note Include the network stack require 'core/main/network_stack/handlers/dynamicreconstruction' @@ -50,6 +51,7 @@ require 'core/hbmanager' require 'core/main/rest/handlers/hookedbrowsers' require 'core/main/rest/handlers/modules' require 'core/main/rest/handlers/logs' +require 'core/main/rest/handlers/admin' require 'core/main/rest/api' ## @note Include Websocket diff --git a/core/core.rb b/core/core.rb index bc655694c..dc554314b 100644 --- a/core/core.rb +++ b/core/core.rb @@ -27,6 +27,7 @@ require 'core/main/models/log' require 'core/main/models/command' require 'core/main/models/result' require 'core/main/models/optioncache' +require 'core/main/models/browserdetails' # @note Include the constants require 'core/main/constants/browsers' diff --git a/extensions/initialization/handler.rb b/core/main/handlers/browserdetails.rb similarity index 97% rename from extensions/initialization/handler.rb rename to core/main/handlers/browserdetails.rb index a56fae3fb..862e20770 100644 --- a/extensions/initialization/handler.rb +++ b/core/main/handlers/browserdetails.rb @@ -14,18 +14,15 @@ # limitations under the License. # module BeEF - module Extension - module Initialization - - # - # The http handler that manages the return of the initial browser details. - # - class Handler + module Core + module Handlers + # @note Retrieves information about the browser (type, version, plugins etc.) + class BrowserDetails @data = {} HB = BeEF::Core::Models::HookedBrowser - BD = BeEF::Extension::Initialization::Models::BrowserDetails + BD = BeEF::Core::Models::BrowserDetails def initialize(data) @data = data @@ -33,7 +30,7 @@ module BeEF end def err_msg(error) - print_error "[INITIALIZATION] #{error}" + print_error "[Browser Details] #{error}" end def setup() diff --git a/extensions/initialization/models/browserdetails.rb b/core/main/models/browserdetails.rb similarity index 93% rename from extensions/initialization/models/browserdetails.rb rename to core/main/models/browserdetails.rb index f2ac1edb6..0cd114c75 100644 --- a/extensions/initialization/models/browserdetails.rb +++ b/core/main/models/browserdetails.rb @@ -14,8 +14,7 @@ # limitations under the License. # module BeEF -module Extension -module Initialization +module Core module Models # # Table stores the details of browsers. @@ -26,16 +25,7 @@ module Models include DataMapper::Resource - storage_names[:default] = 'extension_initialization_browserdetails' - - - # - # Class constructor - # - def initialize(config) - super(config) - end - + storage_names[:default] = 'core_browserdetails' property :session_id, String, :length => 255, :key => true property :detail_key, String, :length => 255, :lazy => false, :key => true property :detail_value, Text, :lazy => false @@ -59,7 +49,7 @@ module Models return nil if not get(session_id, detail_key).nil? # store the returned browser details - browserdetails = BeEF::Extension::Initialization::Models::BrowserDetails.new( + browserdetails = BeEF::Core::Models::BrowserDetails.new( :session_id => session_id, :detail_key => detail_key, :detail_value => detail_value) @@ -120,4 +110,3 @@ module Models end end end -end diff --git a/core/main/rest/api.rb b/core/main/rest/api.rb index c6bfafa59..0f8ce0b7c 100644 --- a/core/main/rest/api.rb +++ b/core/main/rest/api.rb @@ -35,9 +35,29 @@ module BeEF end end + module RegisterAdminHandler + def self.mount_handler(server) + server.mount('/api/admin', BeEF::Core::Rest::Admin.new) + end + end + BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterHooksHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterModulesHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterLogsHandler, BeEF::API::Server, 'mount_handler') + BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterAdminHandler, BeEF::API::Server, 'mount_handler') + + # + # Check the source IP is within the permitted subnet + # This is from extensions/admin_ui/controllers/authentication/authentication.rb + # + def self.permitted_source?(ip) + # get permitted subnet + permitted_ui_subnet = BeEF::Core::Configuration.instance.get("beef.restrictions.permitted_ui_subnet") + target_network = IPAddr.new(permitted_ui_subnet) + + # test if ip within subnet + return target_network.include?(ip) + end end end diff --git a/core/main/rest/handlers/admin.rb b/core/main/rest/handlers/admin.rb new file mode 100644 index 000000000..d36935bfe --- /dev/null +++ b/core/main/rest/handlers/admin.rb @@ -0,0 +1,75 @@ +# +# 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. +# + +module BeEF + module Core + module Rest + class Admin < BeEF::Core::Router::Router + + config = BeEF::Core::Configuration.instance + + before do + # error 401 unless params[:token] == config.get('beef.api_token') + halt 401 if not BeEF::Core::Rest.permitted_source?(request.ip) + headers 'Content-Type' => 'application/json; charset=UTF-8', + 'Pragma' => 'no-cache', + 'Cache-Control' => 'no-cache', + 'Expires' => '0' + end + + # @note Authenticate using the config set username/password to retrieve the "token" used for subsquent calls. + # Return the secret token used for subsquene tAPI calls. + # + # Input must be specified in JSON format + # + # +++ Example: +++ + #POST /api/admin/login HTTP/1.1 + #Host: 127.0.0.1:3000 + #Content-Type: application/json; charset=UTF-8 + #Content-Length: 18 + # + #{"username":"beef", "password":"beef"} + #===response (snip)=== + #HTTP/1.1 200 OK + #Content-Type: application/json; charset=UTF-8 + #Content-Length: 35 + # + #{"success":"true","token":"122323121"} + # + post '/login' do + request.body.rewind + begin + data = JSON.parse request.body.read + # check username and password + if not (data['username'].eql? config.get('beef.credentials.user') and data['password'].eql? config.get('beef.credentials.passwd') ) + BeEF::Core::Logger.instance.register('Authentication', "User with ip #{request.ip} has failed to authenticate in the application.") + halt 401 + else + { "success" => true, + "token" => "#{config.get('beef.api_token')}" + }.to_json + end + rescue Exception => e + error 400 + end + end + + private + + end + end + end +end \ No newline at end of file diff --git a/core/main/rest/handlers/hookedbrowsers.rb b/core/main/rest/handlers/hookedbrowsers.rb index aa269ff88..aedc3fe34 100644 --- a/core/main/rest/handlers/hookedbrowsers.rb +++ b/core/main/rest/handlers/hookedbrowsers.rb @@ -23,6 +23,7 @@ module BeEF before do error 401 unless params[:token] == config.get('beef.api_token') + halt 401 if not BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', @@ -54,7 +55,7 @@ module BeEF end def get_hb_details(hb) - details = BeEF::Extension::Initialization::Models::BrowserDetails + details = BeEF::Core::Models::BrowserDetails { 'name' => details.get(hb.session, 'BrowserName'), diff --git a/core/main/rest/handlers/logs.rb b/core/main/rest/handlers/logs.rb index 52a64e089..848e1fd2e 100644 --- a/core/main/rest/handlers/logs.rb +++ b/core/main/rest/handlers/logs.rb @@ -23,6 +23,7 @@ module BeEF before do error 401 unless params[:token] == config.get('beef.api_token') + halt 401 if not BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', diff --git a/core/main/rest/handlers/modules.rb b/core/main/rest/handlers/modules.rb index 5afa85482..7addcf623 100644 --- a/core/main/rest/handlers/modules.rb +++ b/core/main/rest/handlers/modules.rb @@ -23,6 +23,7 @@ module BeEF before do error 401 unless params[:token] == config.get('beef.api_token') + halt 401 if not BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', @@ -40,6 +41,7 @@ module BeEF next if !BeEF::Module.is_enabled(modk) mods_hash[i] = { 'id' => mod.id, + 'class' => config.get("beef.module.#{modk}.class"), 'name' => config.get("beef.module.#{modk}.name"), 'category' => config.get("beef.module.#{modk}.category") } diff --git a/core/main/server.rb b/core/main/server.rb index e47eb1fd1..86ae23e74 100644 --- a/core/main/server.rb +++ b/core/main/server.rb @@ -82,6 +82,9 @@ module BeEF # Create http handler for the javascript hook file self.mount("#{@configuration.get("beef.http.hook_file")}", BeEF::Core::Handlers::HookedBrowsers.new) + # Create handler for the initialization checks (Browser Details) + self.mount("/init", BeEF::Core::Handlers::BrowserDetails) + # Dynamically get the list of all the http handlers using the API and register them BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'mount_handler', self) diff --git a/extensions/admin_ui/api/command.rb b/extensions/admin_ui/api/command.rb index a35d52839..d1257fe64 100644 --- a/extensions/admin_ui/api/command.rb +++ b/extensions/admin_ui/api/command.rb @@ -29,7 +29,7 @@ module API # Get the browser detail from the database. # def get_browser_detail(key) - bd = BeEF::Extension::Initialization::Models::BrowserDetails + bd = BeEF::Core::Models::BrowserDetails (print_error "@session_id is invalid";return) if not BeEF::Filters.is_valid_hook_session_id?(@session_id) bd.get(@session_id, key) end diff --git a/extensions/admin_ui/config.yaml b/extensions/admin_ui/config.yaml index 0e29a226a..dde46ca70 100644 --- a/extensions/admin_ui/config.yaml +++ b/extensions/admin_ui/config.yaml @@ -17,9 +17,7 @@ beef: extension: admin_ui: name: 'Admin UI' - enable: true - username: "beef" - password: "beef" + enable: true favicon_file_name: "favicon.ico" favicon_dir: "/images" login_fail_delay: 1 diff --git a/extensions/admin_ui/controllers/authentication/authentication.rb b/extensions/admin_ui/controllers/authentication/authentication.rb index ad94d452e..f07a4f94e 100644 --- a/extensions/admin_ui/controllers/authentication/authentication.rb +++ b/extensions/admin_ui/controllers/authentication/authentication.rb @@ -69,7 +69,7 @@ class Authentication < BeEF::Extension::AdminUI::HttpController end # check username and password - if not (username.eql? config.get('beef.extension.admin_ui.username') and password.eql? config.get('beef.extension.admin_ui.password') ) + if not (username.eql? config.get('beef.credentials.user') and password.eql? config.get('beef.credentials.passwd') ) BeEF::Core::Logger.instance.register('Authentication', "User with ip #{@request.ip} has failed to authenticate in the application.") return end diff --git a/extensions/admin_ui/controllers/modules/modules.rb b/extensions/admin_ui/controllers/modules/modules.rb index f140ef3d5..18528ceed 100644 --- a/extensions/admin_ui/controllers/modules/modules.rb +++ b/extensions/admin_ui/controllers/modules/modules.rb @@ -23,7 +23,7 @@ module Controllers # class Modules < BeEF::Extension::AdminUI::HttpController - BD = BeEF::Extension::Initialization::Models::BrowserDetails + BD = BeEF::Core::Models::BrowserDetails def initialize super({ diff --git a/extensions/admin_ui/controllers/panel/panel.rb b/extensions/admin_ui/controllers/panel/panel.rb index 64fd04593..f50adb121 100644 --- a/extensions/admin_ui/controllers/panel/panel.rb +++ b/extensions/admin_ui/controllers/panel/panel.rb @@ -85,9 +85,9 @@ class Panel < BeEF::Extension::AdminUI::HttpController # create a hash of simple hooked browser details def get_simple_hooked_browser_hash(hooked_browser) - browser_icon = BeEF::Extension::Initialization::Models::BrowserDetails.browser_icon(hooked_browser.session) - os_icon = BeEF::Extension::Initialization::Models::BrowserDetails.os_icon(hooked_browser.session) - domain = BeEF::Extension::Initialization::Models::BrowserDetails.get(hooked_browser.session, 'HostName') + browser_icon = BeEF::Core::Models::BrowserDetails.browser_icon(hooked_browser.session) + os_icon = BeEF::Core::Models::BrowserDetails.os_icon(hooked_browser.session) + domain = BeEF::Core::Models::BrowserDetails.get(hooked_browser.session, 'HostName') return { 'session' => hooked_browser.session, diff --git a/extensions/console/lib/command_dispatcher/core.rb b/extensions/console/lib/command_dispatcher/core.rb index d766dcdaa..2a1f81a99 100644 --- a/extensions/console/lib/command_dispatcher/core.rb +++ b/extensions/console/lib/command_dispatcher/core.rb @@ -151,7 +151,7 @@ class Core ]) BeEF::Core::Models::HookedBrowser.all(:lastseen.gte => (Time.new.to_i - 30)).each do |zombie| - tbl << [zombie.id,zombie.ip,beef_logo_to_os(BeEF::Extension::Initialization::Models::BrowserDetails.os_icon(zombie.session))] + tbl << [zombie.id,zombie.ip,beef_logo_to_os(BeEF::Core::Models::BrowserDetails.os_icon(zombie.session))] end puts "\n" @@ -182,7 +182,7 @@ class Core ]) BeEF::Core::Models::HookedBrowser.all(:lastseen.lt => (Time.new.to_i - 30)).each do |zombie| - tbl << [zombie.id,zombie.ip,beef_logo_to_os(BeEF::Extension::Initialization::Models::BrowserDetails.os_icon(zombie.session))] + tbl << [zombie.id,zombie.ip,beef_logo_to_os(BeEF::Core::Models::BrowserDetails.os_icon(zombie.session))] end puts "\n" diff --git a/extensions/console/lib/shellinterface.rb b/extensions/console/lib/shellinterface.rb index 78f099e53..927686cb7 100644 --- a/extensions/console/lib/shellinterface.rb +++ b/extensions/console/lib/shellinterface.rb @@ -19,7 +19,7 @@ module Console class ShellInterface - BD = BeEF::Extension::Initialization::Models::BrowserDetails + BD = BeEF::Core::Models::BrowserDetails def initialize(config) self.config = config diff --git a/extensions/initialization/api.rb b/extensions/initialization/api.rb deleted file mode 100644 index ea3138e9d..000000000 --- a/extensions/initialization/api.rb +++ /dev/null @@ -1,38 +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. -# -module BeEF -module Extension -module Initialization - - module RegisterHttpHandler - - # Register API calls - BeEF::API::Registrar.instance.register(BeEF::Extension::Initialization::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') - - # - # Register the http handler for the initialization script that retrieves - # all the information about hooked browsers. - # - def self.mount_handler(beef_server) - beef_server.mount('/init', BeEF::Extension::Initialization::Handler) - end - - end - - -end -end -end diff --git a/extensions/initialization/config.yaml b/extensions/initialization/config.yaml deleted file mode 100644 index d83ae154c..000000000 --- a/extensions/initialization/config.yaml +++ /dev/null @@ -1,21 +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. -# -beef: - extension: - initialization: - enable: true - name: 'Initialization' - diff --git a/extensions/initialization/extension.rb b/extensions/initialization/extension.rb deleted file mode 100644 index e13f67fe0..000000000 --- a/extensions/initialization/extension.rb +++ /dev/null @@ -1,32 +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. -# -module BeEF -module Extension -module Initialization - - extend BeEF::API::Extension - - @short_name = @full_name = 'initialization' - - @description = 'retrieves information about the browser (type, version, plugins etc.)' - -end -end -end - -require 'extensions/initialization/models/browserdetails' -require 'extensions/initialization/handler' -require 'extensions/initialization/api' diff --git a/modules/debug/test_network_request/command.js b/modules/debug/test_network_request/command.js index f71ef814c..1e298d835 100644 --- a/modules/debug/test_network_request/command.js +++ b/modules/debug/test_network_request/command.js @@ -25,7 +25,7 @@ beef.execute(function() { var timeout = "<%= @timeout %>"; var dataType = "<%= @dataType %>"; - beef.net.request(scheme, method, domain, port, path, anchor, data, timeout, dataType, function(response) { beef.net.send("<%= @command_url %>", <%= @command_id %>, "response="+JSON.stringify(response)); } ); + beef.net.request(scheme, method, domain, port, path, anchor, data, timeout, dataType, function(response) { beef.net.send("<%= @command_url %>", <%= @command_id %>, JSON.stringify(response)); } ); }); diff --git a/test/common/test_constants.rb b/test/common/test_constants.rb index b7390f0ae..322010219 100644 --- a/test/common/test_constants.rb +++ b/test/common/test_constants.rb @@ -1,6 +1,17 @@ BEEF_TEST_DIR = "/tmp/beef-test/" +# General constants ATTACK_DOMAIN = "attacker.beefproject.com" VICTIM_DOMAIN = "attacker.beefproject.com" ATTACK_URL = "http://" + ATTACK_DOMAIN + ":3000/ui/panel" VICTIM_URL = "http://" + VICTIM_DOMAIN + ":3000/demos/basic.html" + +# Credentials +BEEF_USER = "beef" +BEEF_PASSWD = "beef" + +# RESTful API root endpoints +RESTAPI_HOOKS = "http://" + ATTACK_DOMAIN + ":3000/api/hooks" +RESTAPI_LOGS = "http://" + ATTACK_DOMAIN + ":3000/api/logs" +RESTAPI_MODULES = "http://" + ATTACK_DOMAIN + ":3000/api/modules" +RESTAPI_ADMIN = "http://" + ATTACK_DOMAIN + ":3000/api/admin" diff --git a/test/integration/tc_debug_modules.rb b/test/integration/tc_debug_modules.rb new file mode 100644 index 000000000..e1547b7c7 --- /dev/null +++ b/test/integration/tc_debug_modules.rb @@ -0,0 +1,144 @@ +require 'test/unit' +require 'rest_client' +require 'json' +require '../common/test_constants' +require '../common/beef_test' + +class TC_DebugModules < Test::Unit::TestCase + + @@token = nil + @@hb_session = nil + + @@mod_debug_long_string = nil + @@mod_debug_ascii_chars = nil + @@mod_debug_test_network = nil + + # Test RESTful API authentication with default credentials, returns the API token to be used later. + def test_restful_auth + response = RestClient.post "#{RESTAPI_ADMIN}/login", + { 'username' => "#{BEEF_USER}", + 'password' => "#{BEEF_PASSWD}"}.to_json, + :content_type => :json, + :accept => :json + assert_equal 200, response.code + assert_not_nil response.body + result = JSON.parse(response.body) + success = result['success'] + @@token = result['token'] + assert(success) + end + + # Test RESTful API hooks handler hooking a victim browser, and then retrieving his BeEF session + def test_restful_hooks + BeefTest.new_victim + sleep 2.0 + response = RestClient.get "#{RESTAPI_HOOKS}", {:params => {:token => @@token}} + assert_equal 200, response.code + assert_not_nil response.body + result = JSON.parse(response.body) + @@hb_session = result["hooked-browsers"]["online"]["0"]["session"] + assert_not_nil @@hb_session + end + + # Test RESTful API modules handler, retrieving the IDs of the 3 debug modules currently in the framework + def test_restful_modules + response = RestClient.get "#{RESTAPI_MODULES}", {:params => {:token => @@token}} + assert_equal 200, response.code + assert_not_nil response.body + result = JSON.parse(response.body) + result.each do |mod| + case mod[1]["class"] + when "Test_return_long_string" + @@mod_debug_long_string = mod[1]["id"] + when "Test_return_ascii_chars" + @@mod_debug_ascii_chars = mod[1]["id"] + when "Test_network_request" + @@mod_debug_test_network = mod[1]["id"] + end + end + assert_not_nil @@mod_debug_long_string + assert_not_nil @@mod_debug_ascii_chars + assert_not_nil @@mod_debug_test_network + end + + # Test debug module "Test_return_long_string" using the RESTful API + def test_return_long_string + repeat_string = "BeEF" + repeat_count = 20 + + response = RestClient.post "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_long_string}?token=#{@@token}", + { 'repeat_string' => repeat_string, + 'repeat' => repeat_count}.to_json, + :content_type => :json, + :accept => :json + assert_equal 200, response.code + assert_not_nil response.body + result = JSON.parse(response.body) + success = result['success'] + assert success + + cmd_id = result['command_id'] + sleep 3.0 + response = RestClient.get "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_long_string}/#{cmd_id}", {:params => {:token => @@token}} + assert_equal 200, response.code + assert_not_nil response.body + result = JSON.parse(response.body) + data = JSON.parse(result["data"]) + assert_not_nil data + assert_equal data["data"],(repeat_string * repeat_count) + end + + # Test debug module "Test_return_ascii_chars" using the RESTful API + def test_return_ascii_chars + response = RestClient.post "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_ascii_chars}?token=#{@@token}", + {}.to_json, # module does not expect any input + :content_type => :json, + :accept => :json + assert_equal 200, response.code + assert_not_nil response.body + result = JSON.parse(response.body) + success = result['success'] + assert success + + cmd_id = result['command_id'] + sleep 3.0 + response = RestClient.get "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_ascii_chars}/#{cmd_id}", {:params => {:token => @@token}} + assert_equal 200, response.code + assert_not_nil response.body + result = JSON.parse(response.body) + data = JSON.parse(result["data"]) + assert_not_nil data + ascii_chars = "" + (32..127).each do |i| ascii_chars << i.chr end + assert_equal ascii_chars,data["data"] + end + + # Test debug module "Test_network_request" using the RESTful API + def test_return_network_request + + # Test same-domain request (response code and content of secret_page.html) + response = RestClient.post "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_test_network}?token=#{@@token}", + #override only a few parameters, the other ones will have default values from modules's module.rb definition + {"domain" => ATTACK_DOMAIN, "port" => "3000", "path" => "/demos/secret_page.html"}.to_json, + :content_type => :json, + :accept => :json + assert_equal 200, response.code + assert_not_nil response.body + result = JSON.parse(response.body) + success = result['success'] + assert success + + cmd_id = result['command_id'] + sleep 3.0 + response = RestClient.get "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_test_network}/#{cmd_id}", {:params => {:token => @@token}} + assert_equal 200, response.code + assert_not_nil response.body + result = JSON.parse(response.body) + data = JSON.parse(result["data"]) + res = JSON.parse(data["data"]) + assert_not_nil res + assert_equal 200, res["status_code"] + assert res["response_body"].include?("However you should still be capable of accessing it\n\t\tusing the Requester") + + end +end \ No newline at end of file diff --git a/test/integration/ts_integration.rb b/test/integration/ts_integration.rb index 917de1324..b5f4d5a28 100644 --- a/test/integration/ts_integration.rb +++ b/test/integration/ts_integration.rb @@ -23,6 +23,7 @@ Capybara.run_server = false # we need to run our own BeEF server require 'selenium/webdriver' require './check_environment' # Basic log in and log out tests +require './tc_debug_modules' # RESTful API tests (as well as debug modules) require './tc_login' # Basic log in and log out tests class TS_BeefIntegrationTests @@ -30,6 +31,7 @@ class TS_BeefIntegrationTests suite = Test::Unit::TestSuite.new(name="BeEF Integration Test Suite") suite << TC_CheckEnvironment.suite + suite << TC_DebugModules.suite suite << TC_login.suite return suite