Path: blob/master/modules/auxiliary/scanner/dns/dns_amp.rb
19851 views
# encoding: binary12##3# This module requires Metasploit: https://metasploit.com/download4# Current source: https://github.com/rapid7/metasploit-framework5##67class MetasploitModule < Msf::Auxiliary8include Msf::Auxiliary::Report9include Msf::Exploit::Capture10include Msf::Auxiliary::UDPScanner11include Msf::Auxiliary::DRDoS1213def initialize14super(15'Name' => 'DNS Amplification Scanner',16'Description' => %q{17This module can be used to discover DNS servers which expose recursive18name lookups which can be used in an amplification attack against a19third party.20},21'Author' => [ 'xistence <xistence[at]0x90.nl>'], # Original scanner module22'License' => MSF_LICENSE,23'References' => [24['CVE', '2006-0987'],25['CVE', '2006-0988'],26]27)2829register_options([30Opt::RPORT(53),31OptString.new('DOMAINNAME', [true, 'Domain to use for the DNS request', 'isc.org' ]),32OptString.new('QUERYTYPE', [true, 'Query type(A, NS, SOA, MX, TXT, AAAA, RRSIG, DNSKEY, ANY)', 'ANY' ]),33])34end3536def rport37datastore['RPORT']38end3940def setup41super4243# Check for DNS query types byte44case datastore['QUERYTYPE']45when 'A'46querypacket = "\x01"47when 'NS'48querypacket = "\x02"49when 'SOA'50querypacket = "\x06"51when 'MX'52querypacket = "\x0f"53when 'TXT'54querypacket = "\x10"55when 'AAAA'56querypacket = "\x1c"57when 'RRSIG'58querypacket = "\x2e"59when 'DNSKEY'60querypacket = "\x30"61when 'ANY'62querypacket = "\xff"63else64print_error("Invalid query type!")65return66end6768targdomainpacket = []69# Before every part of the domainname there should be the length of that part (instead of a ".")70# So isc.org divided is 3isc3org71datastore['DOMAINNAME'].split('.').each do |domainpart|72# The length of the domain part in hex73domainpartlength = "%02x" % domainpart.length74# Convert the name part to a hex string75domainpart = domainpart.each_byte.map { |b| b.to_s(16) }.join()76# Combine the length of the name part and the name part77targdomainpacket.push(domainpartlength + domainpart)78end79# Convert the targdomainpacket to a string80targdomainpacket = targdomainpacket.join.to_s81# Create a correct hex character string to be used in the packet82targdomainpacket = targdomainpacket.scan(/../).map { |x| x.hex.chr }.join83# DNS Packet including our target domain and query type84@msearch_probe = "\x09\x8d\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00" + targdomainpacket + "\x00\x00" + querypacket + "\x00\x01"85end8687def scanner_prescan(batch)88print_status("Sending DNS probes to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")89# Standard packet is 60 bytes. Add the domain size to this90sendpacketsize = 60 + datastore['DOMAINNAME'].length91print_status("Sending #{sendpacketsize} bytes to each host using the IN #{datastore['QUERYTYPE']} #{datastore['DOMAINNAME']} request")92@results = {}93end9495def scan_host(ip)96if spoofed?97datastore['ScannerRecvWindow'] = 098scanner_spoof_send(@msearch_probe, ip, datastore['RPORT'], datastore['SRCIP'], datastore['NUM_REQUESTS'])99else100scanner_send(@msearch_probe, ip, datastore['RPORT'])101end102end103104def scanner_process(data, shost, sport)105# Check the response data for \x09\x8d and the next 2 bytes, which contain our DNS flags106if data =~ /\x09\x8d(..)/107flags = $1108flags = flags.unpack('B*')[0].scan(/./)109# Query Response110qr = flags[0]111# Recursion Available112ra = flags[8]113# Response Code114rcode = flags[12] + flags[13] + flags[14] + flags[15]115116# If these flags are set, we get a valid response117# don't test recursion available if correct answer received118# at least the case with bind and "additional-from-cache no" or version < 9.5+119if qr == "1" and rcode == "0000"120sendlength = 60 + datastore['DOMAINNAME'].length121receivelength = 42 + data.length122amp = receivelength / sendlength.to_f123print_good("#{shost}:#{datastore['RPORT']} - Response is #{receivelength} bytes [#{amp.round(2)}x Amplification]")124report_service(:host => shost, :port => datastore['RPORT'], :proto => 'udp', :name => "dns")125report_vuln(126:host => shost,127:port => datastore['RPORT'],128:proto => 'udp', :name => "DNS",129:info => "DNS amplification - #{data.length} bytes [#{amp.round(2)}x Amplification]",130:refs => self.references131)132end133134# If these flags are set, we get a valid response but recursion is not available135if qr == "1" and ra == "0" and rcode == "0101"136print_status("#{shost}:#{datastore['RPORT']} - Recursion not allowed")137report_service(:host => shost, :port => datastore['RPORT'], :proto => 'udp', :name => "dns")138end139end140end141end142143144