New DNS entries can now be added dynamically without a server restart.

Database is checked every five seconds and adds new rules if there
were any changes.
This commit is contained in:
soh_cah_toa
2013-05-10 23:01:10 -04:00
parent c7eb1c7fc9
commit d622bf3e5e
2 changed files with 72 additions and 36 deletions

View File

@@ -16,16 +16,6 @@ module DNS
RubyDNS::run_server(:listen => [[:udp, address, port]]) do
upstream = RubyDNS::Resolver.new([[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]])
BeEF::Core::Models::DNS.each do |record|
name = record.name
type = BeEF::Extension::DNS::DNS.parse_type(record.type)
value = record.value
match(name, type) do |transaction|
transaction.respond!(value)
end
end
otherwise do |transaction|
transaction.passthrough!(upstream)
end
@@ -34,28 +24,21 @@ module DNS
end
def add_rule(name, type, value)
d = BeEF::Core::Models::DNS.new(
:name => name,
:type => type,
:value => value
).save
catch(:match) do
BeEF::Core::Models::DNS.each do |rule|
n = rule.name
t = rule.type
v = rule.value
type = BeEF::Extension::DNS::DNS.parse_type(type)
throw :match if [n, t, v] == [name, type, value]
end
RubyDNS::stop_server
run_server
end
# XXX Why must this be a class method? As a private instance method,
# it throws NoMethodError.
def self.parse_type(type)
resolv = 'Resolv::DNS::Resource'
if type =~ /(A|AAAA|SRV|WKS)/
resolv += '::IN'
BeEF::Core::Models::DNS.create(
:name => name,
:type => type,
:value => value
)
end
eval "#{resolv}::#{type}"
end
end

View File

@@ -3,9 +3,14 @@
# Browser Exploitation Framework (BeEF) - http://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
require 'rubygems'
require 'rubydns'
module RubyDNS
# Behaves exactly the same, minus the output
# Behaves exactly the same, except without any output and an added periodic
# timer that checks for new DNS rules every five seconds
def self.run_server(options = {}, &block)
server = RubyDNS::Server.new(&block)
@@ -16,22 +21,21 @@ module RubyDNS
options[:listen].each do |spec|
if spec[0] == :udp
@signature = EventMachine.open_datagram_socket(spec[1], spec[2], UDPHandler, server)
EventMachine.open_datagram_socket(spec[1], spec[2], UDPHandler, server)
elsif spec[0] == :tcp
@signature = EventMachine.start_server(spec[1], spec[2], TCPHandler, server)
EventMachine.start_server(spec[1], spec[2], TCPHandler, server)
end
end
server.load_rules
EventMachine.add_periodic_timer(5) { server.check_rules }
server.fire(:start)
end
server.fire(:stop)
end
def self.stop_server
EventMachine.stop_server(@signature)
end
class Transaction
# Behaves exactly the same, except using debug logger instead of info
@@ -52,4 +56,53 @@ module RubyDNS
end
class Server
# Reads current DNS entries in database and adds them as new rules
def load_rules
rules = get_rules
@rule_count = rules.count
rules.each do |rule|
match(rule[0], parse_type(rule[1])) do |transaction|
transaction.respond!(rule[2])
end
end
end
# Re-loads ruleset if new entries have been added to database
def check_rules
load_rules if get_rules.count != @rule_count
end
private
# Returns an AoA where each element is a rule of the form [name, type, value]
def get_rules
rules = []
BeEF::Core::Models::DNS.each do |record|
name = record.name
type = record.type
value = record.value
rules << [name, type, value]
end
rules
end
# Convenience method for fully-qualifying Resolv::DNS::Resource types
def parse_type(type)
resolv = 'Resolv::DNS::Resource'
if type =~ /(A|AAAA|SRV|WKS)/
resolv += '::IN'
end
eval "#{resolv}::#{type}"
end
end
end