Fix axfr support for auxiliary/gather/enum_dns
AXFR support in net-dns is broken. This fixes it, and makes the requisite modifications to enum_dns module. Basic problem is that AXFR responses consist of a chain of DNS replies, not a single reply with multiple answers. Previously, only the first of these replies, the SOA record, was returned. Also added some exception handling to avoid problems like #483.unstable
parent
0311caf4df
commit
7005216d1f
|
@ -995,12 +995,107 @@ module Net # :nodoc:
|
||||||
#
|
#
|
||||||
# Performs a zone transfer for the zone passed as a parameter.
|
# Performs a zone transfer for the zone passed as a parameter.
|
||||||
#
|
#
|
||||||
# It is actually only a wrapper to a send with type set as Net::DNS::AXFR,
|
# Returns a list of Net::DNS::Packet (not answers!)
|
||||||
# since it is using the same infrastucture.
|
|
||||||
#
|
#
|
||||||
def axfr(name,cls=Net::DNS::IN)
|
def axfr(name,cls=Net::DNS::IN)
|
||||||
@logger.info "Requested AXFR transfer, zone #{name} class #{cls}"
|
@logger.info "Requested AXFR transfer, zone #{name} class #{cls}"
|
||||||
send(name,Net::DNS::AXFR,cls)
|
if @config[:nameservers].size == 0
|
||||||
|
raise Resolver::Error, "No nameservers specified!"
|
||||||
|
end
|
||||||
|
|
||||||
|
method = :query_tcp
|
||||||
|
packet = make_query_packet(name, Net::DNS::AXFR, cls)
|
||||||
|
|
||||||
|
# Store packet_data for performance improvements,
|
||||||
|
# so methods don't keep on calling Packet#data
|
||||||
|
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 = :query_tcp
|
||||||
|
end
|
||||||
|
|
||||||
|
answers = []
|
||||||
|
length = [packet_data.size].pack("n")
|
||||||
|
|
||||||
|
@config[:nameservers].each do |ns|
|
||||||
|
begin
|
||||||
|
socket = Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)
|
||||||
|
socket.bind(Socket.pack_sockaddr_in(@config[:source_port],@config[:source_address].to_s))
|
||||||
|
|
||||||
|
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)
|
||||||
|
soa = 0
|
||||||
|
while soa < 2 do
|
||||||
|
buffer = ""
|
||||||
|
ans = socket.recv(Net::DNS::INT16SZ)
|
||||||
|
if ans.size == 0
|
||||||
|
if soa == 1
|
||||||
|
break #No records in zone
|
||||||
|
else
|
||||||
|
@logger.warn "Couldn't recv from nameserver #{ns}, trying next."
|
||||||
|
throw "next nameserver"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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
|
||||||
|
@logger.info "Received #{buffer.size} bytes from #{ns.to_s}:#{@config[:port].to_s}"
|
||||||
|
begin
|
||||||
|
response = Net::DNS::Packet.parse(buffer,["",@config[:port],ns.to_s,ns.to_s])
|
||||||
|
if response.answer[0].type == "SOA"
|
||||||
|
soa += 1
|
||||||
|
end
|
||||||
|
answers << response
|
||||||
|
rescue NameError => e
|
||||||
|
@logger.warn "Error parsing axfr response: #{e.message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if soa == 2
|
||||||
|
answers.pop #Remove duplicate SOA
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue TimeoutError
|
||||||
|
@logger.warn "Nameserver #{ns} not responding within TCP timeout, trying next one"
|
||||||
|
answers = []
|
||||||
|
next
|
||||||
|
ensure
|
||||||
|
socket.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unless answers
|
||||||
|
message = "No response from nameservers list"
|
||||||
|
@logger.fatal(message)
|
||||||
|
raise NoResponseError, message
|
||||||
|
end
|
||||||
|
return answers
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -369,8 +369,8 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
begin
|
begin
|
||||||
@res.nameserver=(nssrvip)
|
@res.nameserver=(nssrvip)
|
||||||
zone = []
|
zone = []
|
||||||
zone = @res.query(target,Net::DNS::AXFR)
|
zone = @res.axfr(target)
|
||||||
if zone.answer.length != 0
|
if zone.length != 0
|
||||||
print_status("Zone transfer successful")
|
print_status("Zone transfer successful")
|
||||||
report_note(:host => nssrvip,
|
report_note(:host => nssrvip,
|
||||||
:proto => 'udp',
|
:proto => 'udp',
|
||||||
|
@ -379,7 +379,9 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
:type => 'dns.enum',
|
:type => 'dns.enum',
|
||||||
:data => "Zone transfer successful")
|
:data => "Zone transfer successful")
|
||||||
#Prints each record according to its type
|
#Prints each record according to its type
|
||||||
zone.answer.each do |rr|
|
zone.each do |response|
|
||||||
|
response.answer.each do |rr|
|
||||||
|
begin
|
||||||
case rr.type
|
case rr.type
|
||||||
when "A"
|
when "A"
|
||||||
print_status("Name: #{rr.name} IP address: #{rr.address} Record: A ")
|
print_status("Name: #{rr.name} IP address: #{rr.address} Record: A ")
|
||||||
|
@ -454,6 +456,10 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
:type => 'dns.enum',
|
:type => 'dns.enum',
|
||||||
:data => "#{rr.host},#{rr.port},#{rr.priority},SRV")
|
:data => "#{rr.host},#{rr.port},#{rr.priority},SRV")
|
||||||
end
|
end
|
||||||
|
rescue ActiveRecord::RecordInvalid
|
||||||
|
#Do nothing. Probably tried to store :host => 127.0.0.1
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
print_error("Zone transfer failed (length was zero)")
|
print_error("Zone transfer failed (length was zero)")
|
||||||
|
|
Loading…
Reference in New Issue