Summary
The canary-based false-positive detection in bbot/core/helpers/dns/brute.py is completely broken. When brute-forcing a wildcard domain, massdns returns results for every queried subdomain (including canary subdomains). The canary safety net is supposed to detect this and abort, but three bugs prevent it from ever working.
This causes wildcard domains to flood scans with thousands of false-positive DNS_NAME events and wildcard detection log entries.
Bug 1 -- Exhausted generator (brute.py:60-71)
canaries = self.gen_random_subdomains(self.num_canaries) # generator
canaries_list = list(canaries) # exhausts the generator
# ...
if sub in canaries: # always False -- generator is empty
After list(canaries) on line 61, the generator is fully consumed. The sub in canaries membership test on line 71 iterates an empty generator and always returns False. No canary is ever detected, so canaries_triggered is always empty and the abort at line 76 never fires.
Bug 2 -- Trailing dot in subdomain comparison (brute.py:70)
sub = hostname.split(domain)[0]
# hostname = "testcanary.example.com"
# domain = "example.com"
# sub = "testcanary." <-- trailing dot
Even if Bug 1 were fixed, hostname.split(domain)[0] produces a string with a trailing dot (e.g. "testcanary.") that will never match the canary string "testcanary".
Bug 3 -- Variable shadowing (brute.py:52)
wildcard_domains = await self.parent_helper.dns.is_wildcard_domain(domain, (type, "CNAME"))
wildcard_rdtypes = set()
for domain, rdtypes in wildcard_domains.items(): # shadows the `domain` parameter
wildcard_rdtypes.update(rdtypes)
if wildcard_domains:
self.log.hugewarning(
f"Aborting massdns on {domain} ..." # uses wrong value
)
The loop variable domain overwrites the function parameter. If wildcard_domains has multiple entries, the abort warning references the wrong domain name.
Impact
When scanning a domain that has wildcard DNS (e.g. *.example.com with a CNAME to a CDN), the following happens:
is_wildcard_domain() may detect the wildcard and modules with reject_wildcards = "strict" skip it correctly
- However, if the wildcard check passes (e.g. due to resolver differences between bbot and massdns), massdns brute-forces thousands of subdomains that all resolve
- The canary safety net that should catch this scenario is completely non-functional
- All results (including canary subdomains) are emitted as
DNS_NAME events
- Each event triggers individual wildcard zone detection, flooding logs with thousands of entries
Steps to Reproduce
# Demonstrate Bug 1: exhausted generator
def gen():
yield "a"
yield "b"
g = gen()
items = list(g) # exhausts g
print("a" in g) # False -- generator is empty
# Demonstrate Bug 2: trailing dot
hostname = "canary.example.com"
domain = "example.com"
sub = hostname.split(domain)[0]
print(repr(sub)) # 'canary.' -- has trailing dot
Suggested Fix
- Bug 1: Use
canaries_list or convert to a set for O(1) lookups instead of the exhausted generator
- Bug 2: Strip the trailing dot from
sub, or use a different extraction method
- Bug 3: Use a different loop variable name (e.g.
_domain or wildcard_domain)
Summary
The canary-based false-positive detection in
bbot/core/helpers/dns/brute.pyis completely broken. When brute-forcing a wildcard domain, massdns returns results for every queried subdomain (including canary subdomains). The canary safety net is supposed to detect this and abort, but three bugs prevent it from ever working.This causes wildcard domains to flood scans with thousands of false-positive
DNS_NAMEevents and wildcard detection log entries.Bug 1 -- Exhausted generator (
brute.py:60-71)After
list(canaries)on line 61, the generator is fully consumed. Thesub in canariesmembership test on line 71 iterates an empty generator and always returnsFalse. No canary is ever detected, socanaries_triggeredis always empty and the abort at line 76 never fires.Bug 2 -- Trailing dot in subdomain comparison (
brute.py:70)Even if Bug 1 were fixed,
hostname.split(domain)[0]produces a string with a trailing dot (e.g."testcanary.") that will never match the canary string"testcanary".Bug 3 -- Variable shadowing (
brute.py:52)The loop variable
domainoverwrites the function parameter. Ifwildcard_domainshas multiple entries, the abort warning references the wrong domain name.Impact
When scanning a domain that has wildcard DNS (e.g.
*.example.comwith a CNAME to a CDN), the following happens:is_wildcard_domain()may detect the wildcard and modules withreject_wildcards = "strict"skip it correctlyDNS_NAMEeventsSteps to Reproduce
Suggested Fix
canaries_listor convert to asetfor O(1) lookups instead of the exhausted generatorsub, or use a different extraction method_domainorwildcard_domain)