PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/auxiliary/gather/dns_enum.rb

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