PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/auxiliary/gather/enum_dns.rb

https://bitbucket.org/technopunk2099/metasploit-framework
Ruby | 546 lines | 499 code | 25 blank | 22 comment | 60 complexity | 1ec70c6328c71d4213aa56b11b5a1ad9 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, LGPL-2.1, GPL-2.0, MIT
  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. require 'msf/core'
  8. require "net/dns/resolver"
  9. class Metasploit3 < Msf::Auxiliary
  10. include Msf::Auxiliary::Report
  11. def initialize(info = {})
  12. super(update_info(info,
  13. 'Name' => 'DNS Record Scanner and Enumerator ',
  14. 'Description' => %q{
  15. This module can be used to gather information about a domain from a
  16. given DNS server by performing various DNS queries such as zone
  17. transfers, reverse lookups, SRV record bruteforcing, and other techniques.
  18. },
  19. 'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>' ],
  20. 'License' => MSF_LICENSE,
  21. 'References' =>
  22. [
  23. ['CVE', '1999-0532'],
  24. ['OSVDB', '492'],
  25. ]
  26. ))
  27. register_options(
  28. [
  29. OptString.new('DOMAIN', [ true, "The target domain name"]),
  30. OptBool.new('ENUM_AXFR', [ true, 'Initiate a zone transfer against each NS record', true]),
  31. OptBool.new('ENUM_TLD', [ true, 'Perform a TLD expansion by replacing the TLD with the IANA TLD list', false]),
  32. OptBool.new('ENUM_STD', [ true, 'Enumerate standard record types (A,MX,NS,TXT and SOA)', true]),
  33. OptBool.new('ENUM_BRT', [ true, 'Brute force subdomains and hostnames via the supplied wordlist', false]),
  34. OptBool.new('ENUM_IP6', [ true, 'Brute force hosts with IPv6 AAAA records',false]),
  35. OptBool.new('ENUM_RVL', [ true, 'Reverse lookup a range of IP addresses', false]),
  36. OptBool.new('ENUM_SRV', [ true, 'Enumerate the most common SRV records', true]),
  37. OptPath.new('WORDLIST', [ false, "Wordlist for domain name bruteforcing", ::File.join(Msf::Config.install_root, "data", "wordlists", "namelist.txt")]),
  38. OptAddress.new('NS', [ false, "Specify the nameserver to use for queries (default is system DNS)" ]),
  39. OptAddressRange.new('IPRANGE', [false, "The target address range or CIDR identifier"]),
  40. OptBool.new('STOP_WLDCRD', [ true, 'Stops bruteforce enumeration if wildcard resolution is detected', false])
  41. ], self.class)
  42. register_advanced_options(
  43. [
  44. OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 2]),
  45. OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 2]),
  46. OptBool.new('TCP_DNS', [false, "Run queries over TCP", false]),
  47. ], self.class)
  48. end
  49. #---------------------------------------------------------------------------------
  50. def switchdns(target)
  51. if not datastore['NS'].nil?
  52. print_status("Using DNS Server: #{datastore['NS']}")
  53. @res.nameserver=(datastore['NS'])
  54. @nsinuse = datastore['NS']
  55. else
  56. querysoa = @res.query(target, "SOA")
  57. if (querysoa)
  58. (querysoa.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr|
  59. query1soa = @res.search(rr.mname)
  60. if (query1soa and query1soa.answer[0])
  61. print_status("Setting DNS Server to #{target} NS: #{query1soa.answer[0].address}")
  62. @res.nameserver=(query1soa.answer[0].address)
  63. @nsinuse = query1soa.answer[0].address
  64. end
  65. end
  66. end
  67. end
  68. end
  69. #---------------------------------------------------------------------------------
  70. def wildcard(target)
  71. rendsub = rand(10000).to_s
  72. query = @res.query("#{rendsub}.#{target}", "A")
  73. if query.answer.length != 0
  74. print_status("This domain has wildcards enabled!!")
  75. query.answer.each do |rr|
  76. print_status("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME
  77. end
  78. return true
  79. else
  80. return false
  81. end
  82. end
  83. #---------------------------------------------------------------------------------
  84. def genrcd(target)
  85. print_status("Retrieving general DNS records")
  86. query = @res.search(target)
  87. if (query)
  88. query.answer.each do |rr|
  89. next unless rr.class == Net::DNS::RR::A
  90. print_status("Domain: #{target} IP address: #{rr.address} Record: A ")
  91. report_note(:host => @nsinuse.to_s,
  92. :proto => 'udp',
  93. :sname => 'dns',
  94. :port => 53 ,
  95. :type => 'dns.enum',
  96. :update => :unique_data,
  97. :data => "#{rr.address.to_s},#{target},A")
  98. end
  99. end
  100. query = @res.query(target, "SOA")
  101. if (query)
  102. (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr|
  103. query1 = @res.search(rr.mname)
  104. if (query1)
  105. query1.answer.each do |ip|
  106. print_status("Start of Authority: #{rr.mname} IP address: #{ip.address} Record: SOA")
  107. report_note(:host => @nsinuse.to_s,
  108. :proto => 'udp',
  109. :sname => 'dns',
  110. :port => 53 ,
  111. :type => 'dns.enum',
  112. :update => :unique_data,
  113. :data => "#{ip.address.to_s},#{rr.mname},SOA")
  114. end
  115. end
  116. end
  117. end
  118. query = @res.query(target, "NS")
  119. if (query)
  120. (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr|
  121. query1 = @res.search(rr.nsdname)
  122. if (query1)
  123. query1.answer.each do |ip|
  124. next unless ip.class == Net::DNS::RR::A
  125. print_status("Name Server: #{rr.nsdname} IP address: #{ip.address} Record: NS")
  126. report_note(:host => @nsinuse.to_s,
  127. :proto => 'udp',
  128. :sname => 'dns',
  129. :port => 53 ,
  130. :type => 'dns.enum',
  131. :update => :unique_data,
  132. :data => "#{ip.address.to_s},#{rr.nsdname},NS")
  133. end
  134. end
  135. end
  136. end
  137. query = @res.query(target, "MX")
  138. if (query)
  139. (query.answer.select { |i| i.class == Net::DNS::RR::MX}).each do |rr|
  140. print_status("Name: #{rr.exchange} Preference: #{rr.preference} Record: MX")
  141. report_note(:host => @nsinuse.to_s,
  142. :proto => 'udp',
  143. :sname => 'dns',
  144. :port => 53 ,
  145. :type => 'dns.enum',
  146. :update => :unique_data,
  147. :data => "#{rr.exchange},MX")
  148. end
  149. end
  150. query = @res.query(target, "TXT")
  151. if (query)
  152. query.answer.each do |rr|
  153. print_status(rr.inspect)
  154. print_status("Text: #{rr.inspect}")
  155. report_note(:host => @nsinuse.to_s,
  156. :proto => 'udp',
  157. :sname => 'dns',
  158. :port => 53 ,
  159. :type => 'dns.enum',
  160. :update => :unique_data,
  161. :data => rr.inspect)
  162. end
  163. end
  164. end
  165. #---------------------------------------------------------------------------------
  166. def tldexpnd(targetdom,nssrv)
  167. target = targetdom.scan(/(\S*)[.]\w*\z/).join
  168. target.chomp!
  169. if not nssrv.nil?
  170. @res.nameserver=(nssrv)
  171. @nsinuse = nssrv
  172. end
  173. i, a = 0, []
  174. tlds = [
  175. "com", "org", "net", "edu", "mil", "gov", "uk", "af", "al", "dz",
  176. "as", "ad", "ao", "ai", "aq", "ag", "ar", "am", "aw", "ac","au",
  177. "at", "az", "bs", "bh", "bd", "bb", "by", "be", "bz", "bj", "bm",
  178. "bt", "bo", "ba", "bw", "bv", "br", "io", "bn", "bg", "bf", "bi",
  179. "kh", "cm", "ca", "cv", "ky", "cf", "td", "cl", "cn", "cx", "cc",
  180. "co", "km", "cd", "cg", "ck", "cr", "ci", "hr", "cu", "cy", "cz",
  181. "dk", "dj", "dm", "do", "tp", "ec", "eg", "sv", "gq", "er", "ee",
  182. "et", "fk", "fo", "fj", "fi", "fr", "gf", "pf", "tf", "ga", "gm",
  183. "ge", "de", "gh", "gi", "gr", "gl", "gd", "gp", "gu", "gt", "gg",
  184. "gn", "gw", "gy", "ht", "hm", "va", "hn", "hk", "hu", "is", "in",
  185. "id", "ir", "iq", "ie", "im", "il", "it", "jm", "jp", "je", "jo",
  186. "kz", "ke", "ki", "kp", "kr", "kw", "kg", "la", "lv", "lb", "ls",
  187. "lr", "ly", "li", "lt", "lu", "mo", "mk", "mg", "mw", "my", "mv",
  188. "ml", "mt", "mh", "mq", "mr", "mu", "yt", "mx", "fm", "md", "mc",
  189. "mn", "ms", "ma", "mz", "mm", "na", "nr", "np", "nl", "an", "nc",
  190. "nz", "ni", "ne", "ng", "nu", "nf", "mp", "no", "om", "pk", "pw",
  191. "pa", "pg", "py", "pe", "ph", "pn", "pl", "pt", "pr", "qa", "re",
  192. "ro", "ru", "rw", "kn", "lc", "vc", "ws", "sm", "st", "sa", "sn",
  193. "sc", "sl", "sg", "sk", "si", "sb", "so", "za", "gz", "es", "lk",
  194. "sh", "pm", "sd", "sr", "sj", "sz", "se", "ch", "sy", "tw", "tj",
  195. "tz", "th", "tg", "tk", "to", "tt", "tn", "tr", "tm", "tc", "tv",
  196. "ug", "ua", "ae", "gb", "us", "um", "uy", "uz", "vu", "ve", "vn",
  197. "vg", "vi", "wf", "eh", "ye", "yu", "za", "zr", "zm", "zw", "int",
  198. "gs", "info", "biz", "su", "name", "coop", "aero" ]
  199. print_status("Performing Top Level Domain expansion using #{tlds.size} TLDs")
  200. tlds.each do |tld|
  201. query1 = @res.search("#{target}.#{tld}")
  202. if (query1)
  203. query1.answer.each do |rr|
  204. print_status("Domain: #{target}.#{tld} Name: #{rr.name} IP address: #{rr.address} Record: A ") if rr.class == Net::DNS::RR::A
  205. report_note(:host => @nsinuse.to_s,
  206. :proto => 'udp',
  207. :sname => 'dns',
  208. :port => 53,
  209. :type => 'dns.enum',
  210. :update => :unique_data,
  211. :data => "#{rr.address.to_s},#{target}.#{tld},A") if rr.class == Net::DNS::RR::A
  212. end
  213. end
  214. end
  215. end
  216. #-------------------------------------------------------------------------------
  217. def dnsbrute(target, wordlist, nssrv)
  218. print_status("Running bruteforce against domain #{target}")
  219. arr = []
  220. i, a = 0, []
  221. ::File.open(wordlist, "rb").each_line do |line|
  222. if not nssrv.nil?
  223. @res.nameserver=(nssrv)
  224. @nsinuse = nssrv
  225. end
  226. query1 = @res.search("#{line.chomp}.#{target}")
  227. if (query1)
  228. query1.answer.each do |rr|
  229. if rr.class == Net::DNS::RR::A
  230. print_status("Hostname: #{line.chomp}.#{target} IP address: #{rr.address.to_s}")
  231. report_note(:host => @nsinuse.to_s,
  232. :proto => 'udp',
  233. :sname => 'dns',
  234. :port => 53 ,
  235. :type => 'dns.enum',
  236. :update => :unique_data,
  237. :data => "#{rr.address.to_s},#{line.chomp}.#{target},A")
  238. next unless rr.class == Net::DNS::RR::CNAME
  239. end
  240. end
  241. end
  242. end
  243. end
  244. #-------------------------------------------------------------------------------
  245. def bruteipv6(target, wordlist, nssrv)
  246. print_status("Bruteforcing IPv6 addresses against domain #{target}")
  247. arr = []
  248. i, a = 0, []
  249. arr = IO.readlines(wordlist)
  250. if not nssrv.nil?
  251. @res.nameserver=(nssrv)
  252. @nsinuse = nssrv
  253. end
  254. arr.each do |line|
  255. query1 = @res.search("#{line.chomp}.#{target}", "AAAA")
  256. if (query1)
  257. query1.answer.each do |rr|
  258. if rr.class == Net::DNS::RR::AAAA
  259. print_status("Hostname: #{line.chomp}.#{target} IPv6 Address: #{rr.address.to_s}")
  260. report_note(:host => @nsinuse.to_s,
  261. :proto => 'udp',
  262. :sname => 'dns',
  263. :port => 53 ,
  264. :type => 'dns.enum',
  265. :update => :unique_data,
  266. :data => "#{rr.address.to_s},#{line.chomp}.#{target},AAAA")
  267. next unless rr.class == Net::DNS::RR::CNAME
  268. end
  269. end
  270. end
  271. end
  272. end
  273. #-------------------------------------------------------------------------------
  274. def reverselkp(iprange,nssrv)
  275. print_status("Running reverse lookup against IP range #{iprange}")
  276. if not nssrv.nil?
  277. @res.nameserver = (nssrv)
  278. @nsinuse = nssrv
  279. end
  280. ar = Rex::Socket::RangeWalker.new(iprange)
  281. tl = []
  282. while (true)
  283. # Spawn threads for each host
  284. while (tl.length < @threadnum)
  285. ip = ar.next_ip
  286. break if not ip
  287. tl << framework.threads.spawn("Module(#{self.refname})-#{ip}", false, ip.dup) do |tip|
  288. begin
  289. query = @res.query(tip)
  290. query.each_ptr do |addresstp|
  291. print_status("Hostname: #{addresstp} IP address: #{tip.to_s}")
  292. report_note(:host => @nsinuse.to_s,
  293. :proto => 'udp',
  294. :sname => 'dns',
  295. :port => 53 ,
  296. :type => 'dns.enum',
  297. :update => :unique_data,
  298. :data => "#{addresstp},#{tip},A")
  299. end
  300. rescue ::Interrupt
  301. raise $!
  302. rescue ::Rex::ConnectionError
  303. rescue ::Exception => e
  304. print_error("Error: #{tip}: #{e.message}")
  305. elog("Error running against host #{tip}: #{e.message}\n#{e.backtrace.join("\n")}")
  306. end
  307. end
  308. end
  309. # Exit once we run out of hosts
  310. if(tl.length == 0)
  311. break
  312. end
  313. tl.first.join
  314. tl.delete_if { |t| not t.alive? }
  315. end
  316. end
  317. #-------------------------------------------------------------------------------
  318. #SRV Record Enumeration
  319. def srvqry(dom,nssrv)
  320. print_status("Enumerating SRV records for #{dom}")
  321. i, a = 0, []
  322. #Most common SRV Records
  323. srvrcd = [
  324. "_gc._tcp.","_kerberos._tcp.", "_kerberos._udp.","_ldap._tcp","_test._tcp.",
  325. "_sips._tcp.","_sip._udp.","_sip._tcp.","_aix._tcp.","_aix._tcp.","_finger._tcp.",
  326. "_ftp._tcp.","_http._tcp.","_nntp._tcp.","_telnet._tcp.","_whois._tcp.","_h323cs._tcp.",
  327. "_h323cs._udp.","_h323be._tcp.","_h323be._udp.","_h323ls._tcp.","_h323ls._udp.",
  328. "_sipinternal._tcp.","_sipinternaltls._tcp.","_sip._tls.","_sipfederationtls._tcp.",
  329. "_jabber._tcp.","_xmpp-server._tcp.","_xmpp-client._tcp.","_imap._tcp.","_certificates._tcp.",
  330. "_crls._tcp.","_pgpkeys._tcp.","_pgprevokations._tcp.","_cmp._tcp.","_svcp._tcp.","_crl._tcp.",
  331. "_ocsp._tcp.","_PKIXREP._tcp.","_smtp._tcp.","_hkp._tcp.","_hkps._tcp.","_jabber._udp.",
  332. "_xmpp-server._udp.","_xmpp-client._udp.","_jabber-client._tcp.","_jabber-client._udp."]
  333. srvrcd.each do |srvt|
  334. trg = "#{srvt}#{dom}"
  335. query = @res.query(trg , Net::DNS::SRV)
  336. if query
  337. query.answer.each do |srv|
  338. print_status("SRV Record: #{trg} Host: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}") if srv.type != "CNAME"
  339. end
  340. end
  341. end
  342. end
  343. #-------------------------------------------------------------------------------
  344. #For Performing Zone Transfers
  345. def axfr(target, nssrv)
  346. print_status("Performing zone transfer against all nameservers in #{target}")
  347. if not nssrv.nil?
  348. @res.nameserver=(nssrv)
  349. @nsinuse = nssrv
  350. end
  351. @res.tcp_timeout=15
  352. query = @res.query(target, "NS")
  353. if (query.answer.length != 0)
  354. (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |nsrcd|
  355. print_status("Testing nameserver: #{nsrcd.nsdname}")
  356. nssrvquery = @res.query(nsrcd.nsdname, "A")
  357. if nssrvquery.answer.length == 0
  358. nssrvip = Rex::Socket.gethostbyname(nsrcd.nsdname)[3].bytes.reduce {|a,b| [a,b].join(".")}
  359. else
  360. nssrvip = nssrvquery.answer[0].address.to_s
  361. end
  362. begin
  363. @res.nameserver=(nssrvip)
  364. @nsinuse = nssrvip
  365. zone = []
  366. zone = @res.axfr(target)
  367. if zone.length != 0
  368. print_status("Zone transfer successful")
  369. report_note(:host => nssrvip,
  370. :proto => 'udp',
  371. :sname => 'dns',
  372. :port => 53 ,
  373. :type => 'dns.enum',
  374. :update => :unique_data,
  375. :data => "Zone transfer successful")
  376. #Prints each record according to its type
  377. zone.each do |response|
  378. response.answer.each do |rr|
  379. begin
  380. case rr.type
  381. when "A"
  382. print_status("Name: #{rr.name} IP address: #{rr.address} Record: A ")
  383. report_note(:host => nssrvip,
  384. :proto => 'udp',
  385. :sname => 'dns',
  386. :port => 53 ,
  387. :type => 'dns.enum',
  388. :update => :unique_data,
  389. :data => "#{rr.address.to_s},#{rr.name},A")
  390. when "SOA"
  391. print_status("Name: #{rr.mname} Record: SOA")
  392. report_note(:host => nssrvip,
  393. :proto => 'udp',
  394. :sname => 'dns',
  395. :port => 53 ,
  396. :type => 'dns.enum',
  397. :update => :unique_data,
  398. :data => "#{rr.name},SOA")
  399. when "MX"
  400. print_status("Name: #{rr.exchange} Preference: #{rr.preference} Record: MX")
  401. report_note(:host => nssrvip,
  402. :proto => 'udp',
  403. :sname => 'dns',
  404. :port => 53 ,
  405. :type => 'dns.enum',
  406. :update => :unique_data,
  407. :data => "#{rr.exchange},MX")
  408. when "CNAME"
  409. print_status("Name: #{rr.cname} Record: CNAME")
  410. report_note(:host => nssrvip,
  411. :proto => 'udp',
  412. :sname => 'dns',
  413. :port => 53 ,
  414. :type => 'dns.enum',
  415. :update => :unique_data,
  416. :data => "#{rr.cname},CNAME")
  417. when "HINFO"
  418. print_status("CPU: #{rr.cpu} OS: #{rr.os} Record: HINFO")
  419. report_note(:host => nssrvip,
  420. :proto => 'udp',
  421. :sname => 'dns',
  422. :port => 53 ,
  423. :type => 'dns.enum',
  424. :update => :unique_data,
  425. :data => "CPU:#{rr.cpu},OS:#{rr.os},HINFO")
  426. when "AAAA"
  427. print_status("IPv6 Address: #{rr.address} Record: AAAA")
  428. report_note(:host => nssrvip,
  429. :proto => 'udp',
  430. :sname => 'dns',
  431. :port => 53 ,
  432. :type => 'dns.enum',
  433. :update => :unique_data,
  434. :data => "#{rr.address.to_s}, AAAA")
  435. when "NS"
  436. print_status("Name: #{rr.nsdname} Record: NS")
  437. report_note(:host => nssrvip,
  438. :proto => 'udp',
  439. :sname => 'dns',
  440. :port => 53 ,
  441. :type => 'dns.enum',
  442. :update => :unique_data,
  443. :data => "#{rr.nsdname},NS")
  444. when "TXT"
  445. print_status("Text: #{rr.inspect}")
  446. report_note(:host => nssrvip,
  447. :proto => 'udp',
  448. :sname => 'dns',
  449. :port => 53 ,
  450. :type => 'dns.enum',
  451. :update => :unique_data,
  452. :data => rr.inspect)
  453. when "SRV"
  454. print_status("Host: #{rr.host} Port: #{rr.port} Priority: #{rr.priority} Record: SRV")
  455. report_note(:host => nssrvip,
  456. :proto => 'udp',
  457. :sname => 'dns',
  458. :port => 53 ,
  459. :type => 'dns.enum',
  460. :update => :unique_data,
  461. :data => "#{rr.host},#{rr.port},#{rr.priority},SRV")
  462. end
  463. rescue ActiveRecord::RecordInvalid
  464. #Do nothing. Probably tried to store :host => 127.0.0.1
  465. end
  466. end
  467. end
  468. else
  469. print_error("Zone transfer failed (length was zero)")
  470. end
  471. rescue Exception => e
  472. print_error("Error executing zone transfer: #{e.message}")
  473. elog("Error executing zone transfer: #{e.message}\n#{e.backtrace.join("\n")}")
  474. end
  475. end
  476. else
  477. print_error("Could not resolve domain #{target}")
  478. end
  479. end
  480. def run
  481. @res = Net::DNS::Resolver.new()
  482. if datastore['TCP_DNS']
  483. vprint_status("Using DNS/TCP")
  484. @res.use_tcp = true
  485. end
  486. @res.retry = datastore['RETRY'].to_i
  487. @res.retry_interval = datastore['RETRY_INTERVAL'].to_i
  488. @threadnum = datastore['THREADS'].to_i
  489. wldcrd = wildcard(datastore['DOMAIN'])
  490. switchdns(datastore['DOMAIN'])
  491. if(datastore['ENUM_STD'])
  492. genrcd(datastore['DOMAIN'])
  493. end
  494. if(datastore['ENUM_TLD'])
  495. tldexpnd(datastore['DOMAIN'],datastore['NS'])
  496. end
  497. if(datastore['ENUM_BRT'])
  498. if wldcrd and datastore['STOP_WLDCRD']
  499. print_error("Wildcard record found!")
  500. else
  501. dnsbrute(datastore['DOMAIN'],datastore['WORDLIST'],datastore['NS'])
  502. end
  503. end
  504. if(datastore['ENUM_IP6'])
  505. if wldcrd and datastore['STOP_WLDCRD']
  506. print_status("Wildcard Record Found!")
  507. else
  508. bruteipv6(datastore['DOMAIN'],datastore['WORDLIST'],datastore['NS'])
  509. end
  510. end
  511. if(datastore['ENUM_AXFR'])
  512. axfr(datastore['DOMAIN'],datastore['NS'])
  513. end
  514. if(datastore['ENUM_SRV'])
  515. srvqry(datastore['DOMAIN'],datastore['NS'])
  516. end
  517. if(datastore['ENUM_RVL'] and datastore['IPRANGE'] and not datastore['IPRANGE'].empty?)
  518. reverselkp(datastore['IPRANGE'],datastore['NS'])
  519. end
  520. end
  521. end