/modules/auxiliary/gather/dns_srv_enum.rb
https://gitlab.com/alx741/metasploit-framework · Ruby · 298 lines · 275 code · 18 blank · 5 comment · 22 complexity · 1255d556f72c3a52e2bd9ca091a9aa8b MD5 · raw file
- ##
- # This module requires Metasploit: http://metasploit.com/download
- # Current source: https://github.com/rapid7/metasploit-framework
- ##
- require 'msf/core'
- require "net/dns/resolver"
- require 'rex'
- class Metasploit3 < Msf::Auxiliary
- include Msf::Auxiliary::Report
- def initialize(info = {})
- super(update_info(info,
- 'Name' => 'DNS Common Service Record Enumeration',
- 'Description' => %q{
- This module enumerates common DNS service records in a given domain. By setting
- the ALL_DNS to true, all the name servers of a given domain are used for
- enumeration. Otherwise only the system dns is used for enumration. in order to get
- all the available name servers for the given domain the SOA and NS records are
- queried. In order to convert from domain names to IP addresses queries for A and
- AAAA (IPv6) records are used. For Active Directory, it is possible to specify sites.
- },
- 'Author' => [
- 'Carlos Perez <carlos_perez[at]darkoperator.com>', # First and main.
- 'Fabrice RAFART' # mainly change for AD and report.
- ],
- 'License' => BSD_LICENSE
- ))
- register_options(
- [
- OptString.new('DOMAIN', [true, "The target domain name."]),
- OptString.new('SITES', [false, "The Active Directory site names to test (comma-separated)."]),
- OptBool.new('ALL_NS', [false, "Run against all name servers for the given domain.", false])
- ], self.class)
- register_advanced_options(
- [
- OptInt.new('RETRY', [false, "Number of times to try to resolve a record if no response is received.", 2]),
- OptInt.new('RETRY_INTERVAL', [false, "Number of seconds to wait before doing a retry.", 2])
- ], self.class)
- end
- def run
- records = []
- @res = Net::DNS::Resolver.new()
- if datastore['RETRY']
- @res.retry = datastore['RETRY'].to_i
- end
- if datastore['RETRY_INTERVAL']
- @res.retry_interval = datastore['RETRY_INTERVAL'].to_i
- end
- print_status("Enumerating SRV Records for #{datastore['DOMAIN']}")
- records = records + srvqry(datastore['DOMAIN'])
- if datastore["ALL_NS"]
- get_soa(datastore['DOMAIN']).each do |s|
- switchdns(s[:address])
- records = records + srvqry(datastore['DOMAIN'])
- end
- get_ns(datastore['DOMAIN']).each do |ns|
- switchdns(ns[:address])
- records =records + srvqry(datastore['DOMAIN'])
- end
- end
- records.uniq!
- records.each do |r|
- print_good("Host: #{r[:host]} IP: #{r[:address].to_s} Service: #{r[:service]} Protocol: #{r[:proto]} Port: #{r[:port]} Query: #{r[:query]}")
- report_host(
- :host => r[:address].to_s,
- :name => r[:host]
- )
- report_service(
- :host=> r[:address].to_s,
- :port => r[:port].to_i,
- :proto => r[:proto],
- :name => r[:service],
- :host_name => r[:host]
- )
- report_note(
- :type => 'SRV record',
- :host => r[:address].to_s,
- :port => r[:port].to_i,
- :proto => r[:proto],
- :data => r[:query]
- )
- end
- end
- def get_soa(target)
- results = []
- query = @res.query(target, "SOA")
- return results if not query
- (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr|
- if Rex::Socket.dotted_ip?(rr.mname)
- record = {}
- record[:host] = rr.mname
- record[:type] = "SOA"
- record[:address] = rr.mname
- results << record
- else
- get_ip(rr.mname).each do |ip|
- record = {}
- record[:host] = rr.mname.gsub(/\.$/,'')
- record[:type] = "SOA"
- record[:address] = ip[:address].to_s
- results << record
- end
- end
- end
- return results
- end
- def srvqry(dom)
- results = []
- # Most common SRV Records
- srvrcd = [
- '_aix._tcp.',
- '_aix._tcp.',
- '_certificates._tcp.',
- '_cmp._tcp.',
- '_crl._tcp.',
- '_crls._tcp.',
- '_finger._tcp.',
- '_ftp._tcp.',
- '_gc._tcp.',
- '_gc._tcp.Default-First-Site-Name._sites.',
- '_h323be._tcp.',
- '_h323be._udp.',
- '_h323cs._tcp.',
- '_h323cs._udp.',
- '_h323ls._tcp.',
- '_h323ls._udp.',
- '_hkp._tcp.',
- '_hkps._tcp.',
- '_http._tcp.',
- '_imap.tcp.',
- '_jabber-client._tcp.',
- '_jabber-client._udp.',
- '_jabber._tcp.',
- '_jabber._udp.',
- '_kerberos._tcp.',
- '_kerberos._tcp.dc._msdcs.',
- '_kerberos._tcp.Default-First-Site-Name._sites.',
- '_kerberos._udp.',
- '_kerberos.tcp.Default-First-Site-Name._sites.dc._msdcs.',
- '_kpasswd._tcp.',
- '_kpasswd._udp.',
- '_ldap._tcp.',
- '_ldap._tcp.dc._msdcs.',
- '_ldap._tcp.Default-First-Site-Name._sites.',
- '_ldap._tcp.Default-First-Site-Name._sites.dc._msdcs.',
- '_ldap._tcp.Default-First-Site-Name._sites.gc._msdcs.',
- '_ldap._tcp.ForestDNSZones.',
- '_ldap._tcp.gc._msdcs.',
- '_ldap._tcp.pdc._msdcs.',
- '_nntp._tcp.',
- '_ocsp._tcp.',
- '_pgpkeys._tcp.',
- '_pgprevokations._tcp.',
- '_PKIXREP._tcp.',
- '_sip._tcp.',
- '_sip._tls.',
- '_sip._udp.',
- '_sipfederationtls._tcp.',
- '_sipinternal._tcp.',
- '_sipinternaltls._tcp.',
- '_sips._tcp.',
- '_smtp._tcp.',
- '_svcp._tcp.',
- '_telnet._tcp.',
- '_test._tcp.',
- '_whois._tcp.',
- '_xmpp-client._tcp.',
- '_xmpp-client._udp.',
- '_xmpp-server._tcp.',
- '_xmpp-server._udp.'
- ]
- sites = []
- if datastore['SITES']
- sites = datastore['SITES'].split(',')
- end
- sites.each do |site|
- srvrcd = srvrcd + [
- '_gc._tcp.'+site+'._sites.',
- '_kerberos._tcp.'+site+'._sites.',
- '_kerberos.tcp.'+site+'._sites.dc._msdcs.',
- '_ldap._tcp.'+site+'._sites.',
- '_ldap._tcp.'+site+'._sites.dc._msdcs.',
- '_ldap._tcp.'+site+'._sites.gc._msdcs.'
- ]
- end
- srvrcd.each do |srvt|
- trg = "#{srvt}#{dom}"
- begin
- query = @res.query(trg , Net::DNS::SRV)
- next unless query
- query.answer.each do |srv|
- if Rex::Socket.dotted_ip?(srv.host)
- record = {}
- srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0]
- record[:query] = "#{srvt}#{dom}"
- record[:host] = srv.host.gsub(/\.$/,'')
- record[:type] = "SRV"
- record[:address] = srv.host
- record[:srv] = srvt
- record[:service] = srv_info[0]
- record[:proto] = srv_info[1]
- record[:port] = srv.port
- record[:priority] = srv.priority
- results << record
- vprint_status("SRV Record: #{trg} Host: #{srv.host.gsub(/\.$/,'')} IP: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}")
- else
- get_ip(srv.host.gsub(/\.$/,'')).each do |ip|
- record = {}
- srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0]
- record[:query] = "#{srvt}#{dom}"
- record[:host] = srv.host.gsub(/\.$/,'')
- record[:type] = "SRV"
- record[:address] = ip[:address]
- record[:srv] = srvt
- record[:service] = srv_info[0]
- record[:proto] = srv_info[1]
- record[:port] = srv.port
- record[:priority] = srv.priority
- results << record
- vprint_status("SRV Record: #{trg} Host: #{srv.host} IP: #{ip[:address]} Port: #{srv.port} Priority: #{srv.priority}")
- end
- end
- end
- rescue
- end
- end
- return results
- end
- def get_ip(host)
- results = []
- query = @res.search(host, "A")
- if (query)
- query.answer.each do |rr|
- if rr.type == "CNAME"
- results = results + get_ip(rr.cname)
- else
- record = {}
- record[:host] = host
- record[:type] = "AAAA"
- record[:address] = rr.address.to_s
- results << record
- end
- end
- end
- query1 = @res.search(host, "AAAA")
- if (query1)
- query1.answer.each do |rr|
- if rr.type == "CNAME"
- results = results + get_ip(rr.cname)
- else
- record = {}
- record[:host] = host
- record[:type] = "AAAA"
- record[:address] = rr.address.to_s
- results << record
- end
- end
- end
- return results
- end
- def switchdns(ns)
- vprint_status("Enumerating SRV Records on: #{ns}")
- @res.nameserver=(ns)
- @nsinuse = ns
- end
- def get_ns(target)
- results = []
- query = @res.query(target, "NS")
- return results if not query
- (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr|
- get_ip(rr.nsdname).each do |r|
- record = {}
- record[:host] = rr.nsdname.gsub(/\.$/,'')
- record[:type] = "NS"
- record[:address] = r[:address].to_s
- results << record
- end
- end
- return results
- end
- end