|
| 1 | +## |
| 2 | +# ## This file is part of the Metasploit Framework and may be subject to |
| 3 | +# redistribution and commercial restrictions. Please see the Metasploit |
| 4 | +# web site for more information on licensing and terms of use. |
| 5 | +# http://metasploit.com/ |
| 6 | +## |
| 7 | + |
| 8 | +require 'msf/core' |
| 9 | +require "net/dns/resolver" |
| 10 | +require 'rex' |
| 11 | + |
| 12 | +class Metasploit3 < Msf::Auxiliary |
| 13 | + include Msf::Auxiliary::Report |
| 14 | + |
| 15 | + def initialize(info = {}) |
| 16 | + super(update_info(info, |
| 17 | + 'Name' => 'DNS Common Service Record Enumeration', |
| 18 | + 'Description' => %q{ |
| 19 | + This module enumerates common DNS service records in a given domain. By setting |
| 20 | + the ALL_DNS to true, all the name servers of a given domain are used for |
| 21 | + enumeration. Otherwise only the system dns is used for enumration. in order to get |
| 22 | + all the available name servers for the given domain the SOA and NS records are |
| 23 | + queried. In order to convert from domain names to IP addresses queries for A and |
| 24 | + AAAA (IPv6) records are used. |
| 25 | + }, |
| 26 | + 'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>' ], |
| 27 | + 'License' => BSD_LICENSE |
| 28 | + )) |
| 29 | + |
| 30 | + register_options( |
| 31 | + [ |
| 32 | + OptString.new('DOMAIN', [ true, "The target domain name."]), |
| 33 | + OptBool.new( 'ALL_NS', [ false, "Run against all name servers for the given domain.",false]) |
| 34 | + ], self.class) |
| 35 | + |
| 36 | + register_advanced_options( |
| 37 | + [ |
| 38 | + OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received.", 2]), |
| 39 | + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 2]) |
| 40 | + ], self.class) |
| 41 | + end |
| 42 | + |
| 43 | + def run |
| 44 | + records = [] |
| 45 | + @res = Net::DNS::Resolver.new() |
| 46 | + if datastore['RETRY'] |
| 47 | + @res.retry = datastore['RETRY'].to_i |
| 48 | + end |
| 49 | + |
| 50 | + if datastore['RETRY_INTERVAL'] |
| 51 | + @res.retry_interval = datastore['RETRY_INTERVAL'].to_i |
| 52 | + end |
| 53 | + |
| 54 | + print_status("Enumerating SRV Records for #{datastore['DOMAIN']}") |
| 55 | + records = records + srvqry(datastore['DOMAIN']) |
| 56 | + if datastore["ALL_NS"] |
| 57 | + get_soa(datastore['DOMAIN']).each do |s| |
| 58 | + switchdns(s[:address]) |
| 59 | + records = records + srvqry(datastore['DOMAIN']) |
| 60 | + end |
| 61 | + get_ns(datastore['DOMAIN']).each do |ns| |
| 62 | + switchdns(ns[:address]) |
| 63 | + records =records + srvqry(datastore['DOMAIN']) |
| 64 | + end |
| 65 | + end |
| 66 | + records.uniq! |
| 67 | + records.each do |r| |
| 68 | + print_good("Host: #{r[:host]} IP: #{r[:address].to_s} Service: #{r[:service]} Protocol: #{r[:proto]} Port: #{r[:port]}") |
| 69 | + report_host( |
| 70 | + :host => r[:address].to_s, |
| 71 | + :name => r[:host] |
| 72 | + ) |
| 73 | + report_service( |
| 74 | + :host=> r[:address].to_s, |
| 75 | + :port => r[:port].to_i, |
| 76 | + :proto => r[:proto], |
| 77 | + :name => r[:service], |
| 78 | + :host_name => r[:host] |
| 79 | + ) |
| 80 | + end |
| 81 | + |
| 82 | + end |
| 83 | + |
| 84 | + def get_soa(target) |
| 85 | + results = [] |
| 86 | + query = @res.query(target, "SOA") |
| 87 | + return results if not query |
| 88 | + (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr| |
| 89 | + if Rex::Socket.dotted_ip?(rr.mname) |
| 90 | + record = {} |
| 91 | + record[:host] = rr.mname |
| 92 | + record[:type] = "SOA" |
| 93 | + record[:address] = rr.mname |
| 94 | + results << record |
| 95 | + else |
| 96 | + get_ip(rr.mname).each do |ip| |
| 97 | + record = {} |
| 98 | + record[:host] = rr.mname.gsub(/\.$/,'') |
| 99 | + record[:type] = "SOA" |
| 100 | + record[:address] = ip[:address].to_s |
| 101 | + results << record |
| 102 | + end |
| 103 | + end |
| 104 | + end |
| 105 | + return results |
| 106 | + end |
| 107 | + |
| 108 | + def srvqry(dom) |
| 109 | + results = [] |
| 110 | + #Most common SRV Records |
| 111 | + srvrcd = [ |
| 112 | + '_gc._tcp.', '_kerberos._tcp.', '_kerberos._udp.', '_ldap._tcp.', |
| 113 | + '_test._tcp.', '_sips._tcp.', '_sip._udp.', '_sip._tcp.', '_aix._tcp.', |
| 114 | + '_aix._tcp.', '_finger._tcp.', '_ftp._tcp.', '_http._tcp.', '_nntp._tcp.', |
| 115 | + '_telnet._tcp.', '_whois._tcp.', '_h323cs._tcp.', '_h323cs._udp.', |
| 116 | + '_h323be._tcp.', '_h323be._udp.', '_h323ls._tcp.', |
| 117 | + '_h323ls._udp.', '_sipinternal._tcp.', '_sipinternaltls._tcp.', |
| 118 | + '_sip._tls.', '_sipfederationtls._tcp.', '_jabber._tcp.', |
| 119 | + '_xmpp-server._tcp.', '_xmpp-client._tcp.', '_imap.tcp.', |
| 120 | + '_certificates._tcp.', '_crls._tcp.', '_pgpkeys._tcp.', |
| 121 | + '_pgprevokations._tcp.', '_cmp._tcp.', '_svcp._tcp.', '_crl._tcp.', |
| 122 | + '_ocsp._tcp.', '_PKIXREP._tcp.', '_smtp._tcp.', '_hkp._tcp.', |
| 123 | + '_hkps._tcp.', '_jabber._udp.','_xmpp-server._udp.', '_xmpp-client._udp.', |
| 124 | + '_jabber-client._tcp.', '_jabber-client._udp.','_kerberos.tcp.dc._msdcs.', |
| 125 | + '_ldap._tcp.ForestDNSZones.', '_ldap._tcp.dc._msdcs.', '_ldap._tcp.pdc._msdcs.', |
| 126 | + '_ldap._tcp.gc._msdcs.','_kerberos._tcp.dc._msdcs.','_kpasswd._tcp.','_kpasswd._udp.' |
| 127 | + ] |
| 128 | + |
| 129 | + srvrcd.each do |srvt| |
| 130 | + trg = "#{srvt}#{dom}" |
| 131 | + begin |
| 132 | + |
| 133 | + query = @res.query(trg , Net::DNS::SRV) |
| 134 | + next unless query |
| 135 | + query.answer.each do |srv| |
| 136 | + if Rex::Socket.dotted_ip?(srv.host) |
| 137 | + record = {} |
| 138 | + srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] |
| 139 | + record[:host] = srv.host.gsub(/\.$/,'') |
| 140 | + record[:type] = "SRV" |
| 141 | + record[:address] = srv.host |
| 142 | + record[:srv] = srvt |
| 143 | + record[:service] = srv_info[0] |
| 144 | + record[:proto] = srv_info[1] |
| 145 | + record[:port] = srv.port |
| 146 | + record[:priority] = srv.priority |
| 147 | + results << record |
| 148 | + vprint_status("SRV Record: #{trg} Host: #{srv.host.gsub(/\.$/,'')} IP: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}") |
| 149 | + else |
| 150 | + get_ip(srv.host.gsub(/\.$/,'')).each do |ip| |
| 151 | + record = {} |
| 152 | + srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] |
| 153 | + record[:host] = srv.host.gsub(/\.$/,'') |
| 154 | + record[:type] = "SRV" |
| 155 | + record[:address] = ip[:address] |
| 156 | + record[:srv] = srvt |
| 157 | + record[:service] = srv_info[0] |
| 158 | + record[:proto] = srv_info[1] |
| 159 | + record[:port] = srv.port |
| 160 | + record[:priority] = srv.priority |
| 161 | + results << record |
| 162 | + vprint_status("SRV Record: #{trg} Host: #{srv.host} IP: #{ip[:address]} Port: #{srv.port} Priority: #{srv.priority}") |
| 163 | + end |
| 164 | + end |
| 165 | + end |
| 166 | + rescue |
| 167 | + end |
| 168 | + end |
| 169 | + return results |
| 170 | + end |
| 171 | + |
| 172 | + def get_ip(host) |
| 173 | + results = [] |
| 174 | + query = @res.search(host, "A") |
| 175 | + if (query) |
| 176 | + query.answer.each do |rr| |
| 177 | + if rr.type == "CNAME" |
| 178 | + results = results + get_ip(rr.cname) |
| 179 | + else |
| 180 | + record = {} |
| 181 | + record[:host] = host |
| 182 | + record[:type] = "AAAA" |
| 183 | + record[:address] = rr.address.to_s |
| 184 | + results << record |
| 185 | + end |
| 186 | + end |
| 187 | + end |
| 188 | + query1 = @res.search(host, "AAAA") |
| 189 | + if (query1) |
| 190 | + query1.answer.each do |rr| |
| 191 | + if rr.type == "CNAME" |
| 192 | + results = results + get_ip(rr.cname) |
| 193 | + else |
| 194 | + record = {} |
| 195 | + record[:host] = host |
| 196 | + record[:type] = "AAAA" |
| 197 | + record[:address] = rr.address.to_s |
| 198 | + results << record |
| 199 | + end |
| 200 | + end |
| 201 | + end |
| 202 | + return results |
| 203 | + end |
| 204 | + |
| 205 | + def switchdns(ns) |
| 206 | + vprint_status("Enumerating SRV Records on: #{ns}") |
| 207 | + @res.nameserver=(ns) |
| 208 | + @nsinuse = ns |
| 209 | + end |
| 210 | + |
| 211 | + def get_ns(target) |
| 212 | + results = [] |
| 213 | + query = @res.query(target, "NS") |
| 214 | + return results if not query |
| 215 | + (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr| |
| 216 | + get_ip(rr.nsdname).each do |r| |
| 217 | + record = {} |
| 218 | + record[:host] = rr.nsdname.gsub(/\.$/,'') |
| 219 | + record[:type] = "NS" |
| 220 | + record[:address] = r[:address].to_s |
| 221 | + results << record |
| 222 | + end |
| 223 | + end |
| 224 | + return results |
| 225 | + end |
| 226 | +end |
| 227 | + |
0 commit comments