From a4987c644734ebfbfa5ec3258901520bfcad518c Mon Sep 17 00:00:00 2001 From: acidvegas Date: Sat, 28 Oct 2023 21:40:06 -0400 Subject: [PATCH] Finalized code more, README cleaned up --- README.md | 22 +++++++++----- axfr.py | 87 +++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 83 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index e782480..b02e4b2 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,25 @@ # Mass DNS AXFR (Zone Transfer) -# STILL FINISHING THIS - JUST UPLOADING PROGRESS +###### This script will attempt a [Zone Transfer](https://en.wikipedia.org/wiki/DNS_zone_transfer) on all of the [Root Nameservers](https://en.wikipedia.org/wiki/Root_name_server) and [Top-level Domains](https://en.wikipedia.org/wiki/Top-level_domain) *(TLDs)*. + +## Expectations & Legalities +Please set realistic expectations when using this tool. In contemporary network configurations, AXFR requests are typically restricted, reflecting best practices in DNS security. While many nameservers now disallow AXFR requests, there may still be occasional instances where configurations permit them. Always exercise due diligence and ensure ethical use. ## Requirements -- [dnspython](https://pypi.org/project/dnspython/) +- [dnspython](https://pypi.org/project/dnspython/) *(`pip install dnspython`)* + +## Usage +| Argument | Description | +| ---------------- | ---------------------------------------------------- | +| `-r`, `--root` | Perform zone transfer on root nameservers. | +| `-t`, `--tld` | Perform zone transfer on a specific TLD. | +| `-ts`, `--tlds` | Perform zone transfer on all TLDs. | +| `-o`, `--output` | Specify the output directory *(default is axfrout)*. | ## Information -This script will attempt a [Zone Transfer](https://en.wikipedia.org/wiki/DNS_zone_transfer) on all of the [Root Nameservers](https://en.wikipedia.org/wiki/Root_name_server) and [Top-level Domains](https://en.wikipedia.org/wiki/Top-level_domain) *(TLDs)*. +I only wrote this to shit on **[this bozo](https://github.com/flotwig/TLDR-2/tree/main)** who took a dead project & brought it back to life by making it even worse. Rather than making a pull request to give this bloke more credit in his "tenure" as a developer, I decided to just rewrite it all from scratch so people can fork off of *clean* code instead. -Really, I only wrote this to shit on **[this idiot](https://github.com/flotwig/TLDR-2/tree/main)** who took a dead project & brought it back to life by making it even worse. Rather than making a pull request to give this bloke more credit in his "tenure" as a developer, I decided to just rewrite it all from scratch so people can fork off of *clean* code instead. - -## Notice -Do not expect insane results. For the most part, AXFR's are not very commonly allowed on nameservers anymore, by you will always catch a few that are not configured to block AXFR requests... +As a little added bonus, I have began working on a pure POSIX version of this script for protability, which is included in this repository. ___ diff --git a/axfr.py b/axfr.py index 5563fa8..01f3a5c 100644 --- a/axfr.py +++ b/axfr.py @@ -1,7 +1,9 @@ #!/usr/bin/env python # Mass DNS AXFR - developed by acidvegas in python (https://git.acid.vegas/mdaxfr) +import os import urllib.request +import logging try: import dns.rdatatype @@ -11,32 +13,48 @@ try: except ImportError: raise SystemExit('missing required \'dnspython\' module (pip install dnspython)') -def tld_axfr(tld: str, nameserver: str): +def attempt_axfr(tld: str, nameserver: str, filename: str): ''' Perform a DNS zone transfer on a target domain. :param target: The target domain to perform the zone transfer on. :param nameserver: The nameserver to perform the zone transfer on. + :param filename: The filename to store the zone transfer results in. ''' - xfr = dns.query.xfr(nameserver, tld+'.', timeout=15) - for msg in xfr: - for rrset in msg.answer: - for rdata in rrset: - print(f'{rrset.name}.{tld} {rrset.ttl} {rdata}') + temp_file = filename + '.temp' + try: + nameserver = resolve_nameserver(nameserver) + except Exception as ex: + logging.error(f'Failed to resolve nameserver {nameserver}: {ex}') + else: + try: + with open(temp_file, 'w') as file: + xfr = dns.query.xfr(nameserver, tld+'.', timeout=15) + for msg in xfr: + for rrset in msg.answer: + for rdata in rrset: + file.write(f'{rrset.name}.{tld} {rrset.ttl} {rdata}') + os.rename(temp_file, filename) + except Exception as ex: + if os.path.exists(temp_file): + os.remove(temp_file) + logging.error(f'Failed to perform zone transfer from {nameserver} for {tld}: {ex}') -def get_root_nameservers() -> list: # https://www.internic.net/domain/named.root +def get_root_nameservers() -> list: '''Generate a list of the root nameservers.''' - return [f'{root}.rootservers.net' for root in ('abcdefghijklm')] + root_ns_records = dns.resolver.resolve('.', 'NS') + root_servers = [str(rr.target)[:-1] for rr in root_ns_records] + return root_servers def get_root_tlds() -> list: '''Get the root TLDs from IANA.''' return urllib.request.urlopen('https://data.iana.org/TLD/tlds-alpha-by-domain.txt').read().decode('utf-8').lower().split('\n')[1:] -def get_tld_nameservers(tld: str) -> list: # https://www.internic.net/domain/root.zone +def get_tld_nameservers(tld: str) -> list: '''Get the nameservers for a TLD.''' return [nameserver for nameserver in dns.resolver.query(tld+'.', 'NS' )] -def resolve_nameserver(nameserver: str): +def resolve_nameserver(nameserver: str) -> str: ''' Resolve a nameserver to its IP address. @@ -51,16 +69,47 @@ def resolve_nameserver(nameserver: str): if __name__ == '__main__': + import argparse - for root in get_root_nameservers(): - try: - xfr = tld_axfr('', root+'.root-servers.net') # Need to store to file in chunks - except Exception as e: - print(f"Failed to perform zone transfer from the {root} root server: {e}") + parser = argparse.ArgumentParser(description='Mass DNS AXFR') + parser.add_argument('-r', '--root', action='store_true', help='perform zone transfer on root nameservers') + parser.add_argument('-t', '--tld', help='perform zone transfer on a specific TLD') + parser.add_argument('-ts', '--tlds', help='perform zone transfer on all TLDs') + parser.add_argument('-o', '--output', default='axfrout', help='output directory') + args = parser.parse_args() - for tld in get_root_tlds(): + os.makedirs(args.output, exist_ok=True) # Create output directory if it doesn't exist + + if args.root: try: - for ns in get_tld_nameservers(tld): - xfr = tld_axfr(tld, resolve_nameserver(str(ns))) # Need to store to file in chunks + for root in get_root_nameservers(): + try: + attempt_axfr('', root+'.root-servers.net', os.path.join(args.output, root+'-root.txt')) + except Exception as e: + logging.error(f'Failed to perform zone transfer from the {root} root server: {e}') except Exception as e: - print(f"Failed to resolve {tld}: {e}") \ No newline at end of file + logging.error(f'Failed to get root nameservers: {e}') + + if args.tlds: + try: + for tld in get_root_tlds(): + try: + for ns in get_tld_nameservers(tld): + try: + attempt_axfr(tld, ns, os.path.join(args.output, tld+'.txt')) + except Exception as e: + logging.error(f'Failed to perform zone transfer from {ns} for {tld}: {e}') + except Exception as e: + logging.error(f'Failed to get nameservers for {tld}: {e}') + except Exception as e: + logging.error(f'Failed to get root TLDs: {e}') + + elif args.tld: + try: + for ns in get_tld_nameservers(args.tld): + try: + attempt_axfr(args.tld, ns, os.path.join(args.output, args.tld+'.txt')) + except Exception as e: + logging.error(f'Failed to perform zone transfer from {ns} for {args.tld}: {e}') + except Exception as e: + logging.error(f'Failed to get nameservers for {args.tld}: {e}') \ No newline at end of file