From bde4059f83d61eb2cf753060538b5f8e64683009 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 12 Jan 2024 13:53:10 -0500 Subject: [PATCH 1/2] adding zone transfer module --- baddns/lib/findings.py | 4 ++ baddns/modules/zonetransfer.py | 79 ++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 baddns/modules/zonetransfer.py diff --git a/baddns/lib/findings.py b/baddns/lib/findings.py index 36a9c686..44924068 100644 --- a/baddns/lib/findings.py +++ b/baddns/lib/findings.py @@ -53,6 +53,10 @@ def __init__(self, finding_dict): raise BadDNSFindingException("Module was not a valid baddns module") self.finding_dict["module"] = module.name + data = finding_dict.get("data", None) + if data: + self.finding_dict["data"] = data + def to_dict(self): return self.finding_dict diff --git a/baddns/modules/zonetransfer.py b/baddns/modules/zonetransfer.py new file mode 100644 index 00000000..04106d2e --- /dev/null +++ b/baddns/modules/zonetransfer.py @@ -0,0 +1,79 @@ +from baddns.base import BadDNS_base +from baddns.lib.findings import Finding +from baddns.lib.dnsmanager import DNSManager + +import logging +import dns.zone +import dns.query + +log = logging.getLogger(__name__) + +class BadDNS_zonetransfer(BadDNS_base): + name = "zonetransfer" + description = "Attempt a DNS zone transfer" + zone_records = [] + zone_nameservers = [] + + def __init__(self, target, **kwargs): + super().__init__(target, **kwargs) + + self.target_dnsmanager = DNSManager(target, dns_client=self.dns_client) + + def parse_zone(self,zone): + for name, node in zone.nodes.items(): + for rdataset in node.rdatasets: + record_type = dns.rdatatype.to_text(rdataset.rdtype) + for rdata in rdataset: + raw_name = name.to_text() + if str(raw_name) == "@": + processed_name = self.target_dnsmanager.target + else: + processed_name = f"{raw_name}.{self.target_dnsmanager.target}" + record = (processed_name, record_type, rdata.to_text()) + if record not in self.zone_records: + self.zone_records.append(record) + + async def zone_transfer(self, nameserver, domain): + ns_ips = await self.target_dnsmanager.do_resolve(nameserver, "A") + ns_ip = ns_ips[0] + try: + zone = dns.zone.from_xfr(dns.query.xfr(ns_ip, domain, timeout=10)) + except TimeoutError: + log.warning("TimeoutError attempting zone transfer") + return False + except dns.xfr.TransferError as e: + log.debug(f"{nameserver} ({ns_ip}): {e}") + return False + self.zone_nameservers.append(nameserver) + self.parse_zone(zone) + return True + + async def dispatch(self): + await self.target_dnsmanager.dispatchDNS(omit_types=["A", "MX", "AAAA", "CNAME", "SOA", "TXT"]) + if self.target_dnsmanager.answers["NS"]: + + for ns in self.target_dnsmanager.answers["NS"]: + log.debug(f"Attempting Zone Transfer against NS [{ns}] for target [{self.target_dnsmanager.target}]") + r = await self.zone_transfer(ns,self.target_dnsmanager.target) + if r: + log.info(f"Successful Zone Transfer against NS [{ns}] for target [{self.target_dnsmanager.target}]") + return True + + def analyze(self): + findings = [] + if self.zone_records: + findings.append( + Finding( + { + "target": self.target_dnsmanager.target, + "description": "Successful Zone Transfer", + "confidence": "CONFIRMED", + "signature": "N/A", + "indicator": "Successful XFR Request", + "trigger": self.zone_nameservers, + "module": type(self), + "data": self.zone_records + } + ) + ) + return findings \ No newline at end of file From d9a38b6a611a26350cbebe36c73eaa0fdbba7140 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 12 Jan 2024 13:55:59 -0500 Subject: [PATCH 2/2] black --- baddns/modules/zonetransfer.py | 36 ++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/baddns/modules/zonetransfer.py b/baddns/modules/zonetransfer.py index 04106d2e..78af4593 100644 --- a/baddns/modules/zonetransfer.py +++ b/baddns/modules/zonetransfer.py @@ -8,6 +8,7 @@ log = logging.getLogger(__name__) + class BadDNS_zonetransfer(BadDNS_base): name = "zonetransfer" description = "Attempt a DNS zone transfer" @@ -19,7 +20,7 @@ def __init__(self, target, **kwargs): self.target_dnsmanager = DNSManager(target, dns_client=self.dns_client) - def parse_zone(self,zone): + def parse_zone(self, zone): for name, node in zone.nodes.items(): for rdataset in node.rdatasets: record_type = dns.rdatatype.to_text(rdataset.rdtype) @@ -51,29 +52,30 @@ async def zone_transfer(self, nameserver, domain): async def dispatch(self): await self.target_dnsmanager.dispatchDNS(omit_types=["A", "MX", "AAAA", "CNAME", "SOA", "TXT"]) if self.target_dnsmanager.answers["NS"]: - for ns in self.target_dnsmanager.answers["NS"]: log.debug(f"Attempting Zone Transfer against NS [{ns}] for target [{self.target_dnsmanager.target}]") - r = await self.zone_transfer(ns,self.target_dnsmanager.target) + r = await self.zone_transfer(ns, self.target_dnsmanager.target) if r: - log.info(f"Successful Zone Transfer against NS [{ns}] for target [{self.target_dnsmanager.target}]") + log.info( + f"Successful Zone Transfer against NS [{ns}] for target [{self.target_dnsmanager.target}]" + ) return True def analyze(self): findings = [] if self.zone_records: findings.append( - Finding( - { - "target": self.target_dnsmanager.target, - "description": "Successful Zone Transfer", - "confidence": "CONFIRMED", - "signature": "N/A", - "indicator": "Successful XFR Request", - "trigger": self.zone_nameservers, - "module": type(self), - "data": self.zone_records - } - ) + Finding( + { + "target": self.target_dnsmanager.target, + "description": "Successful Zone Transfer", + "confidence": "CONFIRMED", + "signature": "N/A", + "indicator": "Successful XFR Request", + "trigger": self.zone_nameservers, + "module": type(self), + "data": self.zone_records, + } ) - return findings \ No newline at end of file + ) + return findings