Implemented POST handler for /api/dns/rule which adds a new rule.

A host of other changes got roped into this as well. #match now
silently handles blocks passed as a String in order to handle
the 'block' JSON parameter. This is because sourcify doesn't
work with eval'd data.

Rule id's are no longer incremental integers. It's now a 7-character
"token" generated from #secure_token and is managed by the RubyDNS
module.
This commit is contained in:
soh_cah_toa
2013-05-26 22:44:11 -04:00
parent c6f38324d1
commit 27b1b530ef
5 changed files with 137 additions and 26 deletions

View File

@@ -25,7 +25,6 @@ module DNS
def initialize
@lock = Mutex.new
@server = nil
@next_id = 0
end
# Starts the main DNS server run-loop.
@@ -73,9 +72,7 @@ module DNS
# @see http://rubydoc.info/gems/rubydns/RubyDNS/Transaction
def add_rule(pattern, type, &block)
@lock.synchronize do
@next_id += 1
@server.match(@next_id, pattern, type, block)
@next_id
return @server.match(pattern, type, block)
end
end
@@ -86,7 +83,6 @@ module DNS
def remove_rule(id)
@lock.synchronize do
@server.remove_rule(id)
@next_id -= 1
end
end

View File

@@ -14,10 +14,10 @@ module DNS
storage_names[:default] = 'extension_dns_rules'
property :id, Serial # 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

View File

@@ -33,12 +33,65 @@ module DNS
# Returns a specific rule given its id
get '/rule/:id' do
id = params[:id]
begin
id = params[:id]
halt 401 unless BeEF::Filters.nums_only?(id)
unless BeEF::Filters.alphanums_only?(id)
raise StandardError, 'Invalid id passed to endpoint /api/dns/rule/:id'
end
result = BeEF::Extension::DNS::DNS.instance.get_rule(id)
result.to_json
result = BeEF::Extension::DNS::DNS.instance.get_rule(id)
result.to_json
rescue StandardError => e
print_error e.message
halt 400
end
end
# Adds a new DNS rule
post '/rule' do
begin
body = JSON.parse(request.body.read)
pattern = body['pattern']
type = eval body['type']
block = body['block']
# Validate required JSON keys
unless [pattern, type, block].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
if type.superclass != Resolv::DNS::Resource
raise StandardError, 'Invalid resource type given in "type" key'
end
unless BeEF::Filters.is_non_empty_string?(block)
raise StandardError, 'Invalid code block given in "block" key'
end
id = ''
# Bypass #add_rule so that 'block' can be passed as a String
BeEF::Extension::DNS::DNS.instance.instance_eval do
id = @server.match(pattern, type, block)
end
result = {}
result['success'] = true
result['id'] = id
result.to_json
end
rescue StandardError => e
print_error e.message
halt 400
rescue Exception => e
print_error "Invalid JSON input passed to endpoint /api/dns/rule"
halt 400
end
end
end

View File

@@ -4,7 +4,7 @@
# See the file 'doc/COPYING' for copying permission
#
# Overrives the logger used by RubyDNS to use BeEF's print_info() and friends
# Overrives the logger used by RubyDNS to use BeEF's {#print_info} and friends.
class Logger
def debug(msg)

View File

@@ -3,6 +3,17 @@
# Browser Exploitation Framework (BeEF) - http://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# This module is a modified version of RubyDNS built to be compatible with BeEF.
# For the most part, it will behave exactly the same except where otherwise noted.
#
# Additional features include database support, BeEF logger, assignment of unique
# identifiers to rules, rule removal, and more.
#
# The core functionality of BeEF's DNS server is implemented here, whereas
# BeEF::Extension::DNS::DNS is simply a small wrapper around it.
#
# @see http://rubydoc.info/gems/rubydns/frames
module RubyDNS
# Behaves exactly the same, except without any logger output
@@ -33,6 +44,7 @@ module RubyDNS
class Rule
# XXX Can this be removed?
attr_accessor :id
# Now uses an 'id' parameter to uniquely identify rules
@@ -44,22 +56,56 @@ module RubyDNS
end
# Now uses an 'id' parameter to uniquely identify rules
def match(id, *pattern, block)
# Now includes BeEF database support and checks for already present rules
def match(*pattern, block)
id = ''
catch :match do
# Check if rule is already present
BeEF::Core::Models::DNS::Rule.each { |rule| throw :match if rule.id == id }
begin
# Sourcify block (already a string only for RESTful API calls)
block_src = case block.class.name
when String then block
when Proc then block.to_source
end
@rules << Rule.new(id, pattern, block)
# 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
# Add new rule to database
BeEF::Core::Models::DNS::Rule.create(
:id => id,
:pattern => pattern[0],
:type => pattern[1],
:block => block.to_source
)
id = rule.id
throw :match
end
end
id = generate_id
case block.class.name
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],
:type => pattern[1],
:block => block_src
)
rescue Sourcify::CannotHandleCreatedOnTheFlyProcError,
Sourcify::CannotParseEvalCodeError,
Sourcify::MultipleMatchingProcsPerLineError,
Sourcify::NoMatchingProcError,
Sourcify::ParserInternalError
@logger.error "Failed to sourcify block for DNS rule '#{id}'"
raise
end
end
id
end
# New method that removes a rule given its id
@@ -120,6 +166,22 @@ module RubyDNS
result
end
private
# New method that generates a unique id for a rule
def generate_id
begin
id = BeEF::Core::Crypto::secure_token.byteslice(0..6)
# Make sure id isn't already in use
BeEF::Core::Models::DNS::Rule.each { |rule| throw StandardError if id == rule.id }
rescue StandardError
retry
end
id
end
end
class Transaction