Migrate native DNS services to Dnsruby data format
Dnsruby provides advanced options like DNSSEC in its data format and is a current and well supported library. The infrastructure services - resolver, server, etc, were designed for a standalone configuration, and carry entirely too much weight and redundancy to implement for this context. Instead of porting over their native resolver, update the Net::DNS subclassed Rex Resolver to use Dnsruby data formats and method calls. Update the Msf namespace infrastructure mixins and native server module with new method calls and workarounds for some instance variables having only readers without writers. Implement the Rex ServerManager to start and stop the DNS service adding relevant alias methods to the Rex::Proto::DNS::Server class. Rex services are designed to be modular and lightweight, as well as implement the sockets, threads, and other low-level interfaces. Dnsruby's operations classes implement their own threading and socket semantics, and do not fit with the modular mixin workflow used throughout Framework. So while the updated resolver can be seen as adding rubber to the tire fire, converting to dnsruby's native classes for resolvers, servers, and caches, would be more like adding oxy acetylene and heavy metals. Testing: Internal tests for resolution of different record types locally and over pivot sessions.MS-2855/keylogger-mettle-extension
parent
f76adf6a62
commit
c65c03722c
|
@ -47,8 +47,8 @@ module Client
|
|||
], Exploit::Remote::DNS::Client
|
||||
)
|
||||
|
||||
register_autofilter_ports([ 53 ])
|
||||
register_autofilter_services(%W{ dns })
|
||||
register_autofilter_ports([ 53 ]) if respond_to?(:register_autofilter_ports)
|
||||
register_autofilter_services(%W{ dns }) if respond_to?(:register_autofilter_services)
|
||||
end
|
||||
|
||||
|
||||
|
@ -58,7 +58,7 @@ module Client
|
|||
# @param domain [String] Domain for which to request a record
|
||||
# @param type [String] Type of record to request for domain
|
||||
#
|
||||
# @return [Net::DNS::RR] DNS response
|
||||
# @return [Dnsruby::RR] DNS response
|
||||
def query(domain = datastore['DOMAIN'], type = 'A')
|
||||
client.query(domain, type)
|
||||
end
|
||||
|
@ -110,7 +110,7 @@ module Client
|
|||
if datastore['NS'].blank?
|
||||
resp_soa = client.query(target, "SOA")
|
||||
if (resp_soa)
|
||||
(resp_soa.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr|
|
||||
(resp_soa.answer.select { |i| i.is_a?(Dnsruby::RR::SOA)}).each do |rr|
|
||||
resp_1_soa = client.search(rr.mname)
|
||||
if (resp_1_soa and resp_1_soa.answer[0])
|
||||
set_nameserver(resp_1_soa.answer.map(&:address).compact.map(&:to_s))
|
||||
|
@ -139,7 +139,7 @@ module Client
|
|||
if response.answer.length != 0
|
||||
vprint_status("This domain has wildcards enabled!!")
|
||||
response.answer.each do |rr|
|
||||
print_status("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME
|
||||
print_status("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Dnsruby::RR::CNAME
|
||||
addr = rr.address.to_s
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
require 'rex/proto/dns'
|
||||
|
||||
require 'msf/core/exploit/dns/common'
|
||||
|
||||
module Msf
|
||||
|
||||
|
@ -12,7 +12,7 @@ module Msf
|
|||
###
|
||||
module Exploit::Remote::DNS
|
||||
module Server
|
||||
include Common
|
||||
include Exploit::Remote::DNS::Common
|
||||
include Exploit::Remote::SocketServer
|
||||
|
||||
#
|
||||
|
@ -110,7 +110,8 @@ module Server
|
|||
begin
|
||||
|
||||
comm = _determine_server_comm
|
||||
self.service = Rex::Proto::DNS::Server.new(
|
||||
self.service = Rex::ServiceManager.start(
|
||||
Rex::Proto::DNS::Server,
|
||||
datastore['SRVHOST'],
|
||||
datastore['SRVPORT'],
|
||||
datastore['DnsServerUdp'],
|
||||
|
@ -154,7 +155,7 @@ module Server
|
|||
# Stops the server
|
||||
# @param destroy [TrueClass,FalseClass] Dereference the server object
|
||||
def stop_service(destroy = false)
|
||||
self.service.stop unless self.service.nil?
|
||||
Rex::ServiceManager.stop_service(self.service) if self.service
|
||||
if destroy
|
||||
@dns_resolver = nil
|
||||
self.service = nil
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'net/dns'
|
||||
require 'resolv'
|
||||
require 'dnsruby'
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
|
@ -21,26 +24,26 @@ module Packet
|
|||
# Reconstructs a packet with both standard DNS libraries
|
||||
# Ensures that headers match the payload
|
||||
#
|
||||
# @param packet [String, Net::DNS::Packet] Data to be validated
|
||||
# @param packet [String, Net::DNS::Packet, Dnsruby::Message] Data to be validated
|
||||
#
|
||||
# @return [Net::DNS::Packet]
|
||||
# @return [Dnsruby::Message]
|
||||
def self.validate(packet)
|
||||
self.encode_net(self.encode_res(self.encode_raw(packet)))
|
||||
self.encode_drb(self.encode_net(self.encode_res(packet)))
|
||||
end
|
||||
|
||||
#
|
||||
# Sets header values to match packet content
|
||||
#
|
||||
# @param packet [String] Net::DNS::Packet, Resolv::DNS::Message]
|
||||
# @param packet [String] Net::DNS::Packet, Resolv::DNS::Message, Dnsruby::Message]
|
||||
#
|
||||
# @return [Net::DNS::Packet]
|
||||
# @return [Dnsruby::Message]
|
||||
def self.recalc_headers(packet)
|
||||
packet = self.encode_net(packet)
|
||||
packet = self.encode_drb(packet)
|
||||
{
|
||||
:qdCount= => :question,
|
||||
:anCount= => :answer,
|
||||
:nsCount= => :authority,
|
||||
:arCount= => :additional
|
||||
:qdcount= => :question,
|
||||
:ancount= => :answer,
|
||||
:nscount= => :authority,
|
||||
:arcount= => :additional
|
||||
}.each do |header,body|
|
||||
packet.header.send(header,packet.send(body).count)
|
||||
end
|
||||
|
@ -51,36 +54,48 @@ module Packet
|
|||
#
|
||||
# Reads a packet into the Net::DNS::Packet format
|
||||
#
|
||||
# @param data [String, Net::DNS::Packet, Resolv::DNS::Message] Input data
|
||||
# @param data [String, Net::DNS::Packet, Resolv::DNS::Message, Dnsruby::Message] Input data
|
||||
#
|
||||
# @return [Net::DNS::Packet]
|
||||
def self.encode_net(packet)
|
||||
return packet if packet.respond_to?(:data)
|
||||
return packet if packet.is_a?(Net::DNS::Packet)
|
||||
Net::DNS::Packet.parse(
|
||||
packet.respond_to?(:encode) ? packet.encode : packet
|
||||
self.encode_raw(packet)
|
||||
)
|
||||
end
|
||||
|
||||
# Reads a packet into the Resolv::DNS::Message format
|
||||
#
|
||||
# @param data [String, Net::DNS::Packet, Resolv::DNS::Message] Input data
|
||||
# @param data [String, Net::DNS::Packet, Resolv::DNS::Message, Dnsruby::Message] Input data
|
||||
#
|
||||
# @return [Resolv::DNS::Message]
|
||||
def self.encode_res(packet)
|
||||
return packet if packet.respond_to?(:encode)
|
||||
return packet if packet.is_a?(Resolv::DNS::Message)
|
||||
Resolv::DNS::Message.decode(
|
||||
packet.respond_to?(:data) ? packet.data : packet
|
||||
self.encode_raw(packet)
|
||||
)
|
||||
end
|
||||
|
||||
# Reads a packet into the Dnsruby::Message format
|
||||
#
|
||||
# @param data [String, Net::DNS::Packet, Resolv::DNS::Message, Dnsruby::Message] Input data
|
||||
#
|
||||
# @return [Dnsruby::Message]
|
||||
def self.encode_drb(packet)
|
||||
return packet if packet.is_a?(Dnsruby::Message)
|
||||
Dnsruby::Message.decode(
|
||||
self.encode_raw(packet)
|
||||
)
|
||||
end
|
||||
|
||||
# Reads a packet into the raw String format
|
||||
#
|
||||
# @param data [String, Net::DNS::Packet, Resolv::DNS::Message] Input data
|
||||
# @param data [String, Net::DNS::Packet, Resolv::DNS::Message, Dnsruby::Message] Input data
|
||||
#
|
||||
# @return [Resolv::DNS::Message]
|
||||
# @return [String]
|
||||
def self.encode_raw(packet)
|
||||
return packet unless packet.respond_to?(:encode) or packet.respond_to?(:data)
|
||||
packet.respond_to?(:data) ? packet.data : packet.encode
|
||||
(packet.respond_to?(:data) ? packet.data : packet.encode).force_encoding('binary')
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -91,16 +106,16 @@ module Packet
|
|||
# @param cls [Fixnum] Class of dns record to query
|
||||
# @param recurse [Fixnum] Recursive query or not
|
||||
#
|
||||
# @return [Net::DNS::Packet] request packet
|
||||
def self.generate_request(subject, type = Net::DNS::A, cls = Net::DNS::IN, recurse = 1)
|
||||
# @return [Dnsruby::Message] request packet
|
||||
def self.generate_request(subject, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN, recurse = 1)
|
||||
case subject
|
||||
when IPAddr
|
||||
name = subject.reverse
|
||||
type = Net::DNS::PTR
|
||||
type = Dnsruby::Types::PTR
|
||||
when /\d/ # Contains a number, try to see if it's an IP or IPv6 address
|
||||
begin
|
||||
name = IPAddr.new(subject).reverse
|
||||
type = Net::DNS::PTR
|
||||
type = Dnsruby::Types::PTR
|
||||
rescue ArgumentError
|
||||
name = subject if self.valid_hostname?(subject)
|
||||
end
|
||||
|
@ -109,9 +124,9 @@ module Packet
|
|||
end
|
||||
|
||||
# Create the packet
|
||||
packet = Net::DNS::Packet.new(name,type,cls)
|
||||
packet = Dnsruby::Message.new(name, type, cls)
|
||||
|
||||
if packet.query?
|
||||
if packet.header.opcode == Dnsruby::OpCode::Query
|
||||
packet.header.recursive = recurse
|
||||
end
|
||||
|
||||
|
@ -128,26 +143,26 @@ module Packet
|
|||
# @param authority [Array] Set of authority records to provide in the response
|
||||
# @param additional [Array] Set of additional records to provide in the response
|
||||
#
|
||||
# @return [Net::DNS::Packet] Response packet
|
||||
# @return [Dnsruby::Message] Response packet
|
||||
def self.generate_response(request, answer = nil, authority = nil, additional = nil)
|
||||
packet = self.encode_net(request)
|
||||
packet = self.encode_drb(request)
|
||||
packet.answer = answer if answer
|
||||
packet.authority = authority if authority
|
||||
packet.additional = additional if additional
|
||||
packet = self.recalc_headers(packet)
|
||||
|
||||
# Set error code for NXDomain or unset it if reprocessing a response
|
||||
if packet.header.anCount < 1
|
||||
packet.header.rCode = 3
|
||||
if packet.header.ancount < 1
|
||||
packet.header.rcode = Dnsruby::RCode::NXDOMAIN
|
||||
else
|
||||
if packet.header.response? and packet.header.rCode.code == 3
|
||||
packet.header.rCode = 0
|
||||
if packet.header.qr and packet.header.get_header_rcode.to_i == 3
|
||||
packet.header.rcode = Dnsruby::RCode::NOERROR
|
||||
end
|
||||
end
|
||||
# Set response bit last to allow reprocessing of responses
|
||||
packet.header.qr = 1
|
||||
packet.header.qr = true
|
||||
# Set recursion available bit if recursion desired
|
||||
packet.header.ra = 1 if packet.header.recursive?
|
||||
packet.header.ra = true if packet.header.rd
|
||||
return packet
|
||||
end
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'net/dns/resolver'
|
||||
|
||||
module Rex
|
||||
|
@ -6,6 +8,7 @@ module DNS
|
|||
|
||||
##
|
||||
# Provides Rex::Sockets compatible version of Net::DNS::Resolver
|
||||
# Modified to work with Dnsruby::Messages, their resolvers are too heavy
|
||||
##
|
||||
class Resolver < Net::DNS::Resolver
|
||||
|
||||
|
@ -112,24 +115,25 @@ module DNS
|
|||
# @param argument
|
||||
# @param type [Fixnum] Type of record to look up
|
||||
# @param cls [Fixnum] Class of question to look up
|
||||
def send(argument,type=Net::DNS::A,cls=Net::DNS::IN)
|
||||
def send(argument, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN)
|
||||
if @config[:nameservers].size == 0
|
||||
raise ResolverError, "No nameservers specified!"
|
||||
end
|
||||
|
||||
method = self.use_tcp? ? :send_tcp : :send_udp
|
||||
|
||||
if argument.kind_of? Net::DNS::Packet
|
||||
case argument
|
||||
when Dnsruby::Message
|
||||
packet = argument
|
||||
elsif argument.kind_of? Resolv::DNS::Message
|
||||
packet = Net::DNS::Packet.parse(argument.encode)
|
||||
when Net::DNS::Packet, Resolv::DNS::Message
|
||||
packet = Rex::Proto::DNS::Packet.encode_drb(argument)
|
||||
else
|
||||
packet = make_query_packet(argument,type,cls)
|
||||
end
|
||||
|
||||
# Store packet_data for performance improvements,
|
||||
# so methods don't keep on calling Packet#data
|
||||
packet_data = packet.data
|
||||
# so methods don't keep on calling Packet#encode
|
||||
packet_data = packet.encode
|
||||
packet_size = packet_data.size
|
||||
|
||||
# Choose whether use TCP, UDP
|
||||
|
@ -146,7 +150,7 @@ module DNS
|
|||
end
|
||||
end
|
||||
|
||||
if type == Net::DNS::AXFR
|
||||
if type == Dnsruby::Types::AXFR
|
||||
@logger.warn "AXFR query, switching to TCP" unless method == :send_tcp
|
||||
method = :send_tcp
|
||||
end
|
||||
|
@ -160,9 +164,10 @@ module DNS
|
|||
end
|
||||
|
||||
@logger.info "Received #{ans[0].size} bytes from #{ans[1][2]+":"+ans[1][1].to_s}"
|
||||
response = Net::DNS::Packet.parse(ans[0],ans[1])
|
||||
# response = Net::DNS::Packet.parse(ans[0],ans[1])
|
||||
response = Dnsruby::Message.decode(ans[0])
|
||||
|
||||
if response.header.truncated? and not ignore_truncated?
|
||||
if response.header.tc and not ignore_truncated?
|
||||
@logger.warn "Packet truncated, retrying using TCP"
|
||||
self.use_tcp = true
|
||||
begin
|
||||
|
@ -215,7 +220,7 @@ module DNS
|
|||
got_something = false
|
||||
loop do
|
||||
buffer = ""
|
||||
ans = socket.recv(Net::DNS::INT16SZ)
|
||||
ans = socket.recv(2)
|
||||
if ans.size == 0
|
||||
if got_something
|
||||
break #Proper exit from loop
|
||||
|
@ -305,8 +310,69 @@ module DNS
|
|||
end
|
||||
return ans
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Perform search using the configured searchlist and resolvers
|
||||
#
|
||||
# @param name
|
||||
# @param type [Fixnum] Type of record to look up
|
||||
# @param cls [Fixnum] Class of question to look up
|
||||
#
|
||||
# @return ans [Dnsruby::Message] DNS Response
|
||||
def search(name, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN)
|
||||
|
||||
return query(name,type,cls) if name.class == IPAddr
|
||||
|
||||
# If the name contains at least one dot then try it as is first.
|
||||
if name.include? "."
|
||||
@logger.debug "Search(#{name},#{Dnsruby::Types.new(type)},#{Dnsruby::Classes.new(cls)})"
|
||||
ans = query(name,type,cls)
|
||||
return ans if ans.header.ancount > 0
|
||||
end
|
||||
|
||||
# If the name doesn't end in a dot then apply the search list.
|
||||
if name !~ /\.$/ and @config[:dns_search]
|
||||
@config[:searchlist].each do |domain|
|
||||
newname = name + "." + domain
|
||||
@logger.debug "Search(#{newname},#{Dnsruby::Types.new(type)},#{Dnsruby::Classes.new(cls)})"
|
||||
ans = query(newname,type,cls)
|
||||
return ans if ans.header.ancount > 0
|
||||
end
|
||||
end
|
||||
|
||||
# Finally, if the name has no dots then try it as is.
|
||||
@logger.debug "Search(#{name},#{Dnsruby::Types.new(type)},#{Dnsruby::Classes.new(cls)})"
|
||||
return query(name+".",type,cls)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Perform query with default domain validation
|
||||
#
|
||||
# @param name
|
||||
# @param type [Fixnum] Type of record to look up
|
||||
# @param cls [Fixnum] Class of question to look up
|
||||
#
|
||||
# @return ans [Dnsruby::Message] DNS Response
|
||||
def query(name, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN)
|
||||
|
||||
return send(name,type,cls) if name.class == IPAddr
|
||||
|
||||
# If the name doesn't contain any dots then append the default domain.
|
||||
if name !~ /\./ and name !~ /:/ and @config[:defname]
|
||||
name += "." + @config[:domain]
|
||||
end
|
||||
|
||||
@logger.debug "Query(#{name},#{Dnsruby::Types.new(type)},#{Dnsruby::Classes.new(cls)})"
|
||||
|
||||
return send(name,type,cls)
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,7 +39,7 @@ class Server
|
|||
)
|
||||
end.keys.map do |record|
|
||||
if search.to_s.match(MATCH_HOSTNAME) and record.name == '*'
|
||||
record = Net::DNS::RR.new(:name => search, :address => record.address)
|
||||
record = Dnsruby::RR.create(name: name, type: type, address: address)
|
||||
else
|
||||
record
|
||||
end
|
||||
|
@ -49,10 +49,10 @@ class Server
|
|||
#
|
||||
# Add record to cache, only when "running"
|
||||
#
|
||||
# @param record [Net::DNS::RR] Record to cache
|
||||
# @param record [Dnsruby::RR] Record to cache
|
||||
def cache_record(record)
|
||||
return unless @monitor_thread
|
||||
if record.class.ancestors.include?(Net::DNS::RR) and
|
||||
if record.is_a?(Dnsruby::RR) and
|
||||
(!record.respond_to?(:address) or Rex::Socket.is_ip_addr?(record.address.to_s)) and
|
||||
record.name.to_s.match(MATCH_HOSTNAME)
|
||||
add(record, Time.now.to_i + record.ttl)
|
||||
|
@ -73,7 +73,7 @@ class Server
|
|||
find(name, type).each do |found|
|
||||
delete(found)
|
||||
end if replace
|
||||
add(Net::DNS::RR.new(:name => name, :address => address),0)
|
||||
add(Dnsruby::RR.create(name: name, type: type, address: address),0)
|
||||
else
|
||||
raise "Invalid parameters for static entry - #{name}, #{address}, #{type}"
|
||||
end
|
||||
|
@ -120,7 +120,7 @@ class Server
|
|||
#
|
||||
# Add a record to the cache with thread safety
|
||||
#
|
||||
# @param record [Net::DNS::RR] Record to add
|
||||
# @param record [Dnsruby::RR] Record to add
|
||||
# @param expire [Fixnum] Time in seconds when record becomes stale
|
||||
def add(record, expire = 0)
|
||||
self.lock.synchronize do
|
||||
|
@ -131,7 +131,7 @@ class Server
|
|||
#
|
||||
# Delete a record from the cache with thread safety
|
||||
#
|
||||
# @param record [Net::DNS::RR] Record to delete
|
||||
# @param record [Dnsruby::RR] Record to delete
|
||||
def delete(record)
|
||||
self.lock.synchronize do
|
||||
self.records.delete(record)
|
||||
|
@ -285,11 +285,12 @@ class Server
|
|||
# @param cli [Rex::Socket::Tcp, Rex::Socket::Udp] Client sending the request
|
||||
# @param data [String] raw DNS request data
|
||||
def default_dispatch_request(cli,data)
|
||||
req = Packet.encode_net(data)
|
||||
return if data.strip.empty?
|
||||
req = Packet.encode_drb(data)
|
||||
forward = req.dup
|
||||
# Find cached items, remove request from forwarded packet
|
||||
req.question.each do |ques|
|
||||
cached = self.cache.find(ques.qName, ques.qType.to_s)
|
||||
cached = self.cache.find(ques.qname, ques.qtype.to_s)
|
||||
if cached.empty?
|
||||
next
|
||||
else
|
||||
|
@ -304,17 +305,32 @@ class Server
|
|||
forwarded.answer.each do |ans|
|
||||
self.cache.cache_record(ans)
|
||||
end
|
||||
req.header.ra = 1 # Set recursion bit
|
||||
req.header.ra = true # Set recursion bit
|
||||
end
|
||||
# Finalize answers in response
|
||||
# Check for empty response prior to sending
|
||||
if req.answer.size < 1
|
||||
req.header.rCode = 3
|
||||
req.header.rCode = Dnsruby::RCode::NOERROR
|
||||
end
|
||||
req.header.qr = 1 # Set response bit
|
||||
req.header.qr = true # Set response bit
|
||||
send_response(cli, validate_packet(req).data)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the hardcore alias for the DNS service
|
||||
#
|
||||
def self.hardcore_alias(*args)
|
||||
"#{(args[0] || '')}#{(args[1] || '')}"
|
||||
end
|
||||
|
||||
#
|
||||
# DNS server.
|
||||
#
|
||||
def alias
|
||||
"DNS Server"
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
#
|
||||
# This method monitors the listener socket for new connections and calls
|
||||
|
|
|
@ -45,35 +45,37 @@ class MetasploitModule < Msf::Auxiliary
|
|||
# Creates Proc to handle incoming requests
|
||||
#
|
||||
def on_dispatch_request(cli,data)
|
||||
req = Packet.encode_net(data)
|
||||
return if data.strip.empty?
|
||||
req = Packet.encode_drb(data)
|
||||
peer = "#{cli.peerhost}:#{cli.peerport}"
|
||||
asked = req.question.map(&:qName).join(', ')
|
||||
asked = req.question.map(&:qname).map(&:to_s).join(', ')
|
||||
vprint_status("Received request for #{asked} from #{peer}")
|
||||
answered = []
|
||||
# Find cached items, remove request from forwarded packet
|
||||
req.question.each do |ques|
|
||||
cached = service.cache.find(ques.qName, ques.qType.to_s)
|
||||
cached = service.cache.find(ques.qname, ques.qtype.to_s)
|
||||
if cached.empty?
|
||||
next
|
||||
else
|
||||
req.answer = (req.answer + cached).uniq
|
||||
req.instance_variable_set(:@answer, (req.answer + cached).uniq)
|
||||
answered << ques
|
||||
cached.map do |hit|
|
||||
if hit.respond_to?(:address)
|
||||
hit.name + ':' + hit.address.to_s + ' ' + hit.type
|
||||
hit.name.to_s + ':' + hit.address.to_s + ' ' + hit.type.to_s
|
||||
else
|
||||
hit.name + ' ' + hit.type
|
||||
hit.name.to_s + ' ' + hit.type.to_s
|
||||
end
|
||||
end.each {|h| vprint_status("Cache hit for #{h}")}
|
||||
end
|
||||
end unless service.cache.nil?
|
||||
# Forward remaining requests, cache responses
|
||||
if answered.count < req.question.count and service.fwd_res
|
||||
if !req.header.recursive?
|
||||
if !req.header.rd
|
||||
vprint_status("Recursion forbidden in query for #{req.question.first.name} from #{peer}")
|
||||
else
|
||||
forward = req.dup
|
||||
forward.question = req.question - answered
|
||||
# forward.question = req.question - answered
|
||||
forward.instance_variable_set(:@question, req.question - answered)
|
||||
forwarded = service.fwd_res.send(Packet.validate(forward))
|
||||
forwarded.answer.each do |ans|
|
||||
rstring = ans.respond_to?(:address) ? "#{ans.name}:#{ans.address}" : ans.name
|
||||
|
@ -81,20 +83,20 @@ class MetasploitModule < Msf::Auxiliary
|
|||
service.cache.cache_record(ans)
|
||||
end unless service.cache.nil?
|
||||
# Merge the answers and use the upstream response
|
||||
forwarded.answer = (req.answer + forwarded.answer).uniq
|
||||
forward.instance_variable_set(:@question, (req.answer + forwarded.answer).uniq)
|
||||
req = forwarded
|
||||
end
|
||||
end
|
||||
service.send_response(cli, Packet.validate(Packet.generate_response(req)).data)
|
||||
service.send_response(cli, Packet.validate(Packet.generate_response(req)).encode)
|
||||
end
|
||||
|
||||
#
|
||||
# Creates Proc to handle outbound responses
|
||||
#
|
||||
def on_send_response(cli,data)
|
||||
res = Packet.encode_net(data)
|
||||
res = Packet.encode_drb(data)
|
||||
peer = "#{cli.peerhost}:#{cli.peerport}"
|
||||
asked = res.question.map(&:qName).join(', ')
|
||||
asked = res.question.map(&:qname).map(&:to_s).join(', ')
|
||||
vprint_status("Sending response for #{asked} to #{peer}")
|
||||
cli.write(data)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue