A dirty patch for a number of Net::DNS/dns_enum issues

bug/bundler_fix
HD Moore 2015-06-06 13:48:52 -05:00
parent dca2607d54
commit c80017992a
3 changed files with 136 additions and 181 deletions

View File

@ -87,6 +87,9 @@ module Net # :nodoc:
#
class Resolver
class NextNameserver < RuntimeError
end
# An hash with the defaults values of almost all the
# configuration parameters of a resolver object. See
# the description for each parameter to have an
@ -109,7 +112,7 @@ module Net # :nodoc:
:ignore_truncated => false,
:packet_size => 512,
:tcp_timeout => TcpTimeout.new(120),
:udp_timeout => UdpTimeout.new(0)}
:udp_timeout => UdpTimeout.new(5)}
# Create a new resolver object.
#
@ -887,8 +890,11 @@ module Net # :nodoc:
end
@logger.debug "Query(#{name},#{Net::DNS::RR::Types.new(type)},#{Net::DNS::RR::Classes.new(cls)})"
send(name,type,cls)
begin
send(name,type,cls)
rescue ::NoResponseError
return
end
end
@ -1011,13 +1017,13 @@ module Net # :nodoc:
packet_data = packet.data
packet_size = packet_data.size
if @raw
@logger.warn "AXFR query, switching to TCP over RAW socket"
method = :send_raw_tcp
else
@logger.warn "AXFR query, switching to TCP"
method = :send_tcp
end
if @raw
@logger.warn "AXFR query, switching to TCP over RAW socket"
method = :send_raw_tcp
else
@logger.warn "AXFR query, switching to TCP"
method = :send_tcp
end
answers = []
soa = 0
@ -1026,7 +1032,7 @@ module Net # :nodoc:
begin
response = Net::DNS::Packet.parse(ans[0],ans[1])
if response.answer[0].type == "SOA"
if response && response.answer && response.answer[0] && response.answer[0].type == "SOA"
soa += 1
if soa >= 2
break
@ -1167,50 +1173,54 @@ module Net # :nodoc:
sockaddr = Socket.pack_sockaddr_in(@config[:port],ns.to_s)
@config[:tcp_timeout].timeout do
catch "next nameserver" do
socket.connect(sockaddr)
@logger.info "Contacting nameserver #{ns} port #{@config[:port]}"
socket.write(length+packet_data)
got_something = false
loop do
buffer = ""
socket.connect(sockaddr)
@logger.info "Contacting nameserver #{ns} port #{@config[:port]}"
socket.write(length+packet_data)
got_something = false
loop do
buffer = ""
begin
ans = socket.recv(Net::DNS::INT16SZ)
if ans.size == 0
if got_something
break #Proper exit from loop
else
@logger.warn "Connection reset to nameserver #{ns}, trying next."
throw "next nameserver"
end
end
got_something = true
len = ans.unpack("n")[0]
@logger.info "Receiving #{len} bytes..."
if len == 0
@logger.warn "Receiving 0 length packet from nameserver #{ns}, trying next."
throw "next nameserver"
end
while (buffer.size < len)
left = len - buffer.size
temp,from = socket.recvfrom(left)
buffer += temp
end
unless buffer.size == len
@logger.warn "Malformed packet from nameserver #{ns}, trying next."
throw "next nameserver"
end
if block_given?
yield [buffer,["",@config[:port],ns.to_s,ns.to_s]]
rescue ::Errno::ECONNRESET
ans = ""
end
if ans.size == 0
if got_something
break #Proper exit from loop
else
return [buffer,["",@config[:port],ns.to_s,ns.to_s]]
@logger.warn "Connection reset to nameserver #{ns}, trying next."
raise NextNameserver
end
end
got_something = true
len = ans.unpack("n")[0]
@logger.info "Receiving #{len} bytes..."
if len == 0
@logger.warn "Receiving 0 length packet from nameserver #{ns}, trying next."
raise NextNameserver
end
while (buffer.size < len)
left = len - buffer.size
temp,from = socket.recvfrom(left)
buffer += temp
end
unless buffer.size == len
@logger.warn "Malformed packet from nameserver #{ns}, trying next."
raise NextNameserver
end
if block_given?
yield [buffer,["",@config[:port],ns.to_s,ns.to_s]]
else
return [buffer,["",@config[:port],ns.to_s,ns.to_s]]
end
end
end
rescue NextNameserver
next
rescue Timeout::Error
@logger.warn "Nameserver #{ns} not responding within TCP timeout, trying next one"
next

View File

@ -1,6 +1,6 @@
# -*- coding: binary -*-
#
# $Id: RR.rb,v 1.19 2006/07/28 07:33:36 bluemonk Exp $
# $Id: RR.rb,v 1.19 2006/07/28 07:33:36 bluemonk Exp $
#
require 'net/dns/names/names'
@ -13,37 +13,37 @@ require 'net/dns/rr/classes'
end
module Net # :nodoc:
module DNS
module DNS
# =Name
#
# Net::DNS::RR - DNS Resource Record class
#
# =Synopsis
#
#
# require 'net/dns/rr'
#
# =Description
#
# The Net::DNS::RR is the base class for DNS Resource
#
# The Net::DNS::RR is the base class for DNS Resource
# Record (RR) objects. A RR is a pack of data that represents
# resources for a DNS zone. The form in which this data is
# resources for a DNS zone. The form in which this data is
# shows can be drawed as follow:
#
# "name ttl class type data"
#
#
# The +name+ is the name of the resource, like an canonical
# name for an +A+ record (internet ip address). The +ttl+ is the
# time to live, expressed in seconds. +type+ and +class+ are
# time to live, expressed in seconds. +type+ and +class+ are
# respectively the type of resource (+A+ for ip addresses, +NS+
# for nameservers, and so on) and the class, which is almost
# for nameservers, and so on) and the class, which is almost
# always +IN+, the Internet class. At the end, +data+ is the
# value associated to the name for that particular type of
# value associated to the name for that particular type of
# resource record. An example:
#
# # A record for IP address
# "www.example.com 86400 IN A 172.16.100.1"
#
#
# # NS record for name server
# "www.example.com 86400 IN NS ns.example.com"
#
@ -61,20 +61,20 @@ module Net # :nodoc:
# * RRDataError: Error in parsing binary data, maybe from a malformed packet
#
# =Copyright
#
#
# Copyright (c) 2006 Marco Ceresa
#
# All rights reserved. This program is free software; you may redistribute
# All rights reserved. This program is free software; you may redistribute
# it and/or modify it under the same terms as Ruby itself.
#
class RR
include Net::DNS::Names
# Regexp matching an RR string
RR_REGEXP = Regexp.new("^\\s*(\\S+)\\s*(\\d+)?\\s+(" +
Net::DNS::RR::Classes.regexp +
Net::DNS::RR::Classes.regexp +
"|CLASS\\d+)?\\s*(" +
Net::DNS::RR::Types.regexp +
Net::DNS::RR::Types.regexp +
"|TYPE\\d+)?\\s*(.*)$", Regexp::IGNORECASE, 'n')
# Dimension of the sum of class, type, TTL and rdlength fields in a
@ -85,13 +85,13 @@ module Net # :nodoc:
attr_reader :name
# TTL time (in seconds) of the RR
attr_reader :ttl
# Data belonging to that appropriate class,
# Data belonging to that appropriate class,
# not to be used (use real accessors instead)
attr_reader :rdata
# Create a new instance of Net::DNS::RR class, or an instance of
# any of the subclass of the appropriate type.
#
#
# Argument can be a string or an hash. With a sting, we can pass
# a RR resource record in the canonical format:
#
@ -101,12 +101,12 @@ module Net # :nodoc:
# txt = Net::DNS::RR.new('baz.example.com 3600 HS TXT "text record"')
#
# Incidentally, +a+, +mx+, +cname+ and +txt+ objects will be instances of
# respectively Net::DNS::RR::A, Net::DNS::RR::MX, Net::DNS::RR::CNAME and
# respectively Net::DNS::RR::A, Net::DNS::RR::MX, Net::DNS::RR::CNAME and
# Net::DNS::RR::TXT classes.
#
# The name and RR data are required; all other informations are optional.
# The name and RR data are required; all other informations are optional.
# If omitted, the +TTL+ defaults to 10800, +type+ default to +A+ and the RR class
# defaults to +IN+. Omitting the optional fields is useful for creating the
# defaults to +IN+. Omitting the optional fields is useful for creating the
# empty RDATA sections required for certain dynamic update operations.
# All names must be fully qualified. The trailing dot (.) is optional.
#
@ -125,12 +125,12 @@ module Net # :nodoc:
# :rdata => "10.1.2.3"
# )
#
# Name and data are required; all the others fields are optionals like
# we've seen before. The data field can be specified either with the
# Name and data are required; all the others fields are optionals like
# we've seen before. The data field can be specified either with the
# right name of the resource (+:address+ in the example above) or with
# the generic key +:rdata+. Consult documentation to find the exact name
# for the resource in each subclass.
#
#
def initialize(arg)
case arg
when String
@ -157,18 +157,18 @@ module Net # :nodoc:
#
# This method is used when parsing a binary packet by the Packet
# class.
#
#
def RR.parse(data)
o = allocate
obj,offset = o.send(:new_from_binary, data, 0)
return obj
end
# Same as RR.parse, but takes an entire packet binary data to
# Same as RR.parse, but takes an entire packet binary data to
# perform name expansion. Default when analizing a packet
# just received from a network stream.
#
# Return an instance of appropriate class and the offset
# Return an instance of appropriate class and the offset
# pointing at the end of the data parsed.
#
def RR.parse_packet(data,offset)
@ -176,12 +176,12 @@ module Net # :nodoc:
o.send(:new_from_binary,data,offset)
end
# Return the RR object in binary data format, suitable
# for using in network streams, with names compressed.
# Return the RR object in binary data format, suitable
# for using in network streams, with names compressed.
# Must pass as arguments the offset inside the packet
# and an hash of compressed names.
#
# This method is to be used in other classes and is
# This method is to be used in other classes and is
# not intended for user space programs.
#
# TO FIX in one of the future releases
@ -193,8 +193,8 @@ module Net # :nodoc:
offset += Net::DNS::RRFIXEDSZ
return str,offset,names
end
# Return the RR object in binary data format, suitable
# Return the RR object in binary data format, suitable
# for using in network streams.
#
# raw_data = rr.data
@ -205,17 +205,17 @@ module Net # :nodoc:
str = pack_name(@name)
return str + [type,cls,@ttl,@rdlength].pack("n2 N n") + get_data
end
# Canonical inspect method
# Canonical inspect method
#
# mx = Net::DNS::RR.new("example.com. 7200 MX 10 mailhost.example.com.")
# #=> example.com. 7200 IN MX 10 mailhost.example.com.
#
def inspect
data = get_inspect
data = get_inspect
# Returns the preformatted string
if @name.size < 24
[@name, @ttl.to_s, @cls.to_s, @type.to_s,
[@name, @ttl.to_s, @cls.to_s, @type.to_s,
data].pack("A24 A8 A8 A8 A*")
else
to_a.join(" ")
@ -241,26 +241,26 @@ module Net # :nodoc:
def to_a
[@name,@ttl,@cls.to_s,@type.to_s,get_inspect]
end
# Type accessor
def type
@type.to_s
end
# Class accessor
def cls
@cls.to_s
end
private
#---
# New RR with argument in string form
#---
def new_from_string(rrstring)
unless rrstring =~ RR_REGEXP
raise RRArgumentError,
raise RRArgumentError,
"Format error for RR string (maybe CLASS and TYPE not valid?)"
end
@ -270,19 +270,19 @@ module Net # :nodoc:
rescue NoMethodError
raise RRArgumentError, "Missing name field in RR string #{rrstring}"
end
# Time to live for RR, default 3 hours
@ttl = $2 ? $2.to_i : 10800
# RR class, default to IN
@cls = Net::DNS::RR::Classes.new $3
# RR type, default to A
@type = Net::DNS::RR::Types.new $4
# All the rest is data
@rdata = $5 ? $5.strip : ""
# All the rest is data
@rdata = $5 ? $5.strip : ""
if self.class == Net::DNS::RR
(eval "Net::DNS::RR::#@type").new(rrstring)
else
@ -290,11 +290,11 @@ module Net # :nodoc:
self.class
end
end
def new_from_hash(args)
# Name field is mandatory
unless args.has_key? :name
# Name field is mandatory
unless args.has_key? :name
raise RRArgumentError, "RR argument error: need at least RR name"
end
@ -302,7 +302,7 @@ module Net # :nodoc:
@ttl = args[:ttl] ? args[:ttl].to_i : 10800 # Default 3 hours
@type = Net::DNS::RR::Types.new args[:type]
@cls = Net::DNS::RR::Classes.new args[:cls]
@rdata = args[:rdata] ? args[:rdata].strip : ""
@rdlength = args[:rdlength] || @rdata.size
@ -323,6 +323,7 @@ module Net # :nodoc:
if self.class == Net::DNS::RR
temp = dn_expand(data,offset)[1]
type = Net::DNS::RR::Types.new data.unpack("@#{temp} n")[0]
return unless Net::DNS::RR.const_defined?(type.to_s)
(eval "Net::DNS::RR::#{type}").parse_packet(data,offset)
else
@name,offset = dn_expand(data,offset)
@ -338,7 +339,7 @@ module Net # :nodoc:
# rescue StandardError => err
# raise RRDataError, "Caught exception, maybe packet malformed: #{err}"
end
# Methods to be overridden by subclasses
def subclass_new_from_array(arr)
end
@ -369,9 +370,9 @@ module Net # :nodoc:
return o
end
end
end # class RR
end # module DNS
end # module Net
@ -381,10 +382,10 @@ class RRDataError < StandardError # :nodoc:
end
module ExtendHash # :nodoc:
# Performs a sort of group difference
# Performs a sort of group difference
# operation on hashes or arrays
#
#
# a = {:a=>1,:b=>2,:c=>3}
# b = {:a=>1,:b=>2}
# c = [:a,:c]

View File

@ -296,6 +296,7 @@ class Metasploit3 < Msf::Auxiliary
tl << framework.threads.spawn("Module(#{self.refname})-#{ip}", false, ip.dup) do |tip|
begin
query = @res.query(tip)
raise ::Rex::ConnectionError
query.each_ptr do |addresstp|
print_status("Hostname: #{addresstp} IP address: #{tip.to_s}")
report_note(:host => @nsinuse.to_s,
@ -342,12 +343,13 @@ class Metasploit3 < Msf::Auxiliary
srvrcd.each do |srvt|
trg = "#{srvt}#{dom}"
query = @res.query(trg , Net::DNS::SRV)
if query
query.answer.each do |srv|
print_status("SRV Record: #{trg} Host: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}") if srv.type != "CNAME"
end
next unless query
query.answer.each do |srv|
next if srv.type == "CNAME"
print_status("SRV Record: #{trg} Host: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}")
end
end
print_status("Done")
end
# For Performing Zone Transfers
@ -359,7 +361,7 @@ class Metasploit3 < Msf::Auxiliary
end
@res.tcp_timeout=15
query = @res.query(target, "NS")
if (query.answer.length != 0)
if query && query.answer.length != 0
(query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |nsrcd|
print_status("Testing nameserver: #{nsrcd.nsdname}")
nssrvquery = @res.query(nsrcd.nsdname, "A")
@ -372,7 +374,12 @@ class Metasploit3 < Msf::Auxiliary
@res.nameserver=(nssrvip)
@nsinuse = nssrvip
zone = []
zone = @res.axfr(target)
begin
zone = @res.axfr(target)
rescue ::NoResponseError
end
if zone.length != 0
print_status("Zone transfer successful")
report_note(:host => nssrvip,
@ -381,7 +388,7 @@ class Metasploit3 < Msf::Auxiliary
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "Zone transfer successful")
:data => zone)
# Prints each record according to its type
zone.each do |response|
response.answer.each do |rr|
@ -389,85 +396,22 @@ class Metasploit3 < Msf::Auxiliary
case rr.type
when "A"
print_status("Name: #{rr.name} IP address: #{rr.address} Record: A ")
report_note(:host => nssrvip,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.address.to_s},#{rr.name},A")
when "SOA"
print_status("Name: #{rr.mname} Record: SOA")
report_note(:host => nssrvip,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.name},SOA")
when "MX"
print_status("Name: #{rr.exchange} Preference: #{rr.preference} Record: MX")
report_note(:host => nssrvip,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.exchange},MX")
when "CNAME"
print_status("Name: #{rr.cname} Record: CNAME")
report_note(:host => nssrvip,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.cname},CNAME")
when "HINFO"
print_status("CPU: #{rr.cpu} OS: #{rr.os} Record: HINFO")
report_note(:host => nssrvip,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "CPU:#{rr.cpu},OS:#{rr.os},HINFO")
when "AAAA"
print_status("IPv6 Address: #{rr.address} Record: AAAA")
report_note(:host => nssrvip,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.address.to_s}, AAAA")
when "NS"
print_status("Name: #{rr.nsdname} Record: NS")
report_note(:host => nssrvip,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.nsdname},NS")
when "TXT"
print_status("Text: #{rr.inspect}")
report_note(:host => nssrvip,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => rr.inspect)
when "SRV"
print_status("Host: #{rr.host} Port: #{rr.port} Priority: #{rr.priority} Record: SRV")
report_note(:host => nssrvip,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.host},#{rr.port},#{rr.priority},SRV")
end
rescue ActiveRecord::RecordInvalid
# Do nothing. Probably tried to store :host => 127.0.0.1