Monday, January 2, 2012

Python - TestZoneTransfer

Here's a python script to help find world-transferable DNS domains within your organization. Alternatively, you could search through your .conf files for ACL weaknesses/misconfigurations, but that can become quite cumbersome when dealing with large datasets.


* * * Note: The script below is out of date. Please use the script found here instead:


https://github.com/btaub/test-dns-xfer


This script queries NS records for a given domain and then attempts to transfer the supplied zone from each name server.

#!/usr/bin/env python
'''
Info:     Query a supplied dns zone for it's NS records
          and test if it's offering transfers out to the world.

          This script could be replaced by using a couple dig commands.

          e.g. dig -tns example.org
          dig @ns1.example.org example.org axfr
          dig @ns2.example.org example.org axfr
           ... etc.

          Or even nslookup

Required: DNS python, available here: http://www.dnspython.org
          or via easy_install, e.g.:
          `easy_install dnspython`
          
'''
import dns.query, dns.zone, dns.resolver, sys, socket

# Get NS records
def getNameservers(zonename):
    nameservers = dns.resolver.query(zonename, 'NS') 
    return nameservers

# Check for and get mandatory zone argument
def getArgs(zonename):
    if  len(sys.argv) != 2:
        print '\n     Usage: \n\n     {0}  fqdn\n'.format(sys.argv[0]) 
        print '\n     Purpose: \n\n     Test a domain for wide-open zone transfer\n'
              
        sys.exit(1)
    else:
        return sys.argv[1]

zonename = ''
zonename = getArgs(zonename)

# Get nameserver records
try:
    if len(getNameservers(zonename)):
        print "Number of NS records:", len(getNameservers(zonename))
except dns.resolver.NXDOMAIN:
    print "Invalid name" , zonename
    sys.exit(1)

# Attempt to transfer the zone from each nameserver, exit if 1 server gives up the zone 
for nameserver in getNameservers(zonename):
    try:

        print '\n   - Querying nameserver {0} for DNS zone {1}\n'.format(nameserver,zonename)

        tryxfer = dns.zone.from_xfr(dns.query.xfr(str(nameserver), zonename))
        names = tryxfer.nodes.keys()
        names.sort()

        for n in names:
             print tryxfer[n].to_text(n)

        sys.exit(0)

# Trap errors
    except dns.resolver.NoAnswer: 
        print "\nproblem getting NS record\n"

    except dns.exception.FormError:
        print "\nXfer refused, good work dns admin\n"

    except dns.resolver.NoAnswer:
        print "\nNo Answer\n"

    except EOFError:
        print "\nEOFError\n"

    except KeyboardInterrupt:
        print "\nUser cancelled\n"

    except socket.error:
        print "\nFailed: connection refused\n"

Post a Comment