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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user