From 7386a7708beb3a8077b47ebebceceb27ad594bad Mon Sep 17 00:00:00 2001 From: soh_cah_toa Date: Wed, 23 Apr 2014 11:14:35 -0400 Subject: [PATCH] Changed Dns::Server to use RubyDNS 0.7.x API. At this point, it is just a prototype that resolves any request to 1.1.1.1. --- extensions/dns/api.rb | 48 +++++++---- extensions/dns/dns.rb | 160 ++++-------------------------------- extensions/dns/extension.rb | 12 +-- 3 files changed, 54 insertions(+), 166 deletions(-) diff --git a/extensions/dns/api.rb b/extensions/dns/api.rb index 5070a3ac2..cac80f2d6 100644 --- a/extensions/dns/api.rb +++ b/extensions/dns/api.rb @@ -1,5 +1,5 @@ # -# Copyright (c) 2006-2013 Wade Alcorn - wade@bindshell.net +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - http://beefproject.com # See the file 'doc/COPYING' for copying permission # @@ -11,34 +11,41 @@ module BeEF module NameserverHandler BeEF::API::Registrar.instance.register( - BeEF::Extension::Dns::API::NameserverHandler, - BeEF::API::Server, - 'pre_http_start' + 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::Extension::Dns::API::NameserverHandler, + BeEF::API::Server, + 'mount_handler' ) - # Begins main DNS server run-loop at BeEF startup + # Starts the DNS nameserver at BeEF startup. + # + # @param http_hook_server [BeEF::Core::Server] HTTP server instance def self.pre_http_start(http_hook_server) dns_config = BeEF::Core::Configuration.instance.get('beef.extension.dns') + dns = BeEF::Extension::Dns::Server.instance + protocol = dns_config['protocol'].to_sym address = dns_config['address'] port = dns_config['port'] + interfaces = [[protocol, address, port]] - dns = BeEF::Extension::Dns::Server.instance - dns.run_server(address, port) + Thread.new { EventMachine.next_tick { dns.run(:listen => interfaces) } } - print_info "DNS Server: #{address}:#{port}" + print_info "DNS Server: #{address}:#{port} (#{protocol})" + + # @todo Upstream servers are not yet supported. Uncomment this section when they are. +=begin servers = [] + unless dns_config['upstream'].nil? dns_config['upstream'].each do |server| - if server[1].nil? or server[2].nil? - next - end + next if server[1].nil? or server[2].nil? + if server[0] == 'tcp' servers << ['tcp', server[1], server[2]] elsif server[0] == 'udp' @@ -46,20 +53,27 @@ module BeEF end end end + if servers.empty? servers << ['tcp', '8.8.8.8', 53] servers << ['udp', '8.8.8.8', 53] end + upstream_servers = '' servers.each do |server| - upstream_servers << "Upstream server: #{server[1]}:#{server[2]} (#{server[0]})\n" + upstream_servers << "Upstream Server: #{server[1]}:#{server[2]} (#{server[0]})\n" end + print_more upstream_servers +=end end - # Mounts handler for processing RESTful API calls + # Mounts the handler for processing DNS RESTful API requests. + # + # @param beef_server [BeEF::Core::Server] HTTP server instance def self.mount_handler(beef_server) - beef_server.mount('/api/dns', BeEF::Extension::Dns::DnsRest.new) + # @todo Uncomment when RESTful API is DNS 2.0 compliant. + #beef_server.mount('/api/dns', BeEF::Extension::Dns::DnsRest.new) end end diff --git a/extensions/dns/dns.rb b/extensions/dns/dns.rb index 6803de477..ac18ce303 100644 --- a/extensions/dns/dns.rb +++ b/extensions/dns/dns.rb @@ -1,5 +1,5 @@ # -# Copyright (c) 2006-2013 Wade Alcorn - wade@bindshell.net +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - http://beefproject.com # See the file 'doc/COPYING' for copying permission # @@ -7,156 +7,30 @@ module BeEF 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 + # @todo Add option for configuring upstream servers. + + # Provides the core DNS nameserver functionality. The nameserver handles incoming requests + # using a rule-based system. A list of user-defined rules is used to match against incoming + # DNS requests. These rules generate a response that is either a resource record or a + # failure code. + class Server < RubyDNS::Server include Singleton - attr_reader :address, :port - - # @!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 + super() @lock = Mutex.new - @server = nil end - def set_server(server) - @server = server - end - - def get_server - @server - end - - # Starts the main DNS server run-loop in a new thread. + # Entry point for processing incoming DNS requests. Attempts to find a matching rule and + # sends back its associated response. # - # @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 - Thread.new do - sleep(2) - - # antisnatchor: RubyDNS is already implemented with EventMachine - run_server_block(@address, @port) - 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: - # - # * :id - # * :pattern - # * :type - # * :response - # - # @return [Array] 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 - # Pass unmatched queries upstream to root nameservers - dns_config = BeEF::Core::Configuration.instance.get('beef.extension.dns') - unless dns_config['upstream'].nil? - dns_config['upstream'].each do |server| - if server[1].nil? or server[2].nil? - print_error "Invalid server '#{server[1]}:#{server[2]}' specified for upstream DNS server." - next - elsif server[0] == 'tcp' - servers << [:tcp, server[1], server[2]] - elsif server[0] == 'udp' - servers << [:udp, server[1], server[2]] - else - print_error "Invalid protocol '#{server[0]}' specified for upstream DNS server." - end - end - end - if servers.empty? - print_debug "No upstream DNS servers specified. Using '8.8.8.8'" - servers << [:tcp, '8.8.8.8', 53] - servers << [:udp, '8.8.8.8', 53] - end - otherwise do |transaction| - transaction.passthrough!( - RubyDNS::Resolver.new servers - ) - end + # @param name [String] name of the resource record being looked up + # @param resource [Resolv::DNS::Resource::IN] query type (e.g. A, CNAME, NS, etc.) + # @param transaction [RubyDNS::Transaction] internal RubyDNS class detailing DNS question/answer + def process(name, resource, transaction) + @lock.synchronize do + transaction.respond!('1.1.1.1') end end diff --git a/extensions/dns/extension.rb b/extensions/dns/extension.rb index fd909f01b..b7732a576 100644 --- a/extensions/dns/extension.rb +++ b/extensions/dns/extension.rb @@ -1,5 +1,5 @@ # -# Copyright (c) 2006-2013 Wade Alcorn - wade@bindshell.net +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - http://beefproject.com # See the file 'doc/COPYING' for copying permission # @@ -18,9 +18,9 @@ module BeEF end end -#TODO antisnatchor: uncomment this when code will be stable -#require 'extensions/dns/api' -#require 'extensions/dns/dns' -#require 'extensions/dns/model' +require 'extensions/dns/api' +require 'extensions/dns/dns' +require 'extensions/dns/logger' +require 'extensions/dns/model' +# @todo Uncomment when RESTful API is DNS 2.0 compliant. #require 'extensions/dns/rest/dns' -#require 'extensions/dns/ruby'