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