Skip to content

deep-review: subdomain-enumerator — ERR: broad except conflates NXDOMAIN with resolver failure #5

Description

@5h4d0wn1k

Purpose

Per README.md, the tool's job is reliable DNS-based enumeration ("Deduplicated output — sorted unique FQDNs that resolved successfully"). This finding is a defect against that purpose: every failure mode — NXDOMAIN, resolver outage, timeout, unexpected error — is collapsed into "not found", so a DNS outage prints Found 0 subdomain(s) exactly like a clean domain. Results become unverifiable, not a tradeoff.

Location

subdomain_enum.py:35-39:

try:
    await asyncio.wait_for(loop.getaddrinfo(fqdn, None), timeout=timeout)
    return fqdn, True
except Exception:
    return fqdn, False

Repro (no network)

import asyncio, socket, sys
sys.path.insert(0, '/tmp/opencode/scratch/subdomain-enumerator')
import subdomain_enum as se
from unittest import mock
async def raise_gai(*a, **k): raise socket.gaierror(8, 'Name or service not known')
async def raise_boom(*a, **k): raise RuntimeError('simulated resolver outage')
async def main():
    sem = asyncio.Semaphore(5)
    with mock.patch.object(asyncio.BaseEventLoop, 'getaddrinfo', raise_gai):
        r1 = await se.resolve('www', 'example.com', sem, 2.0)
    with mock.patch.object(asyncio.BaseEventLoop, 'getaddrinfo', raise_boom):
        r2 = await se.resolve('www', 'example.com', sem, 2.0)
    print(r1, r2)
asyncio.run(main())

Observed

('www.example.com', False) ('www.example.com', False)

A name that does not exist and a total resolver failure are indistinguishable. A user mid-outage gets a confident-looking Found 0 subdomain(s) and may conclude the target has no attack surface.

Expected

Catch only expected lookup failures (socket.gaierror, asyncio.TimeoutError/TimeoutError) as not-found; let unexpected exceptions propagate (or count them as errors, report to stderr, and exit non-zero when the error rate is high).

Severity

Medium — silent conflation of "absent" with "unknown"; misleads the primary result.

Safe remediation

Narrow the except to (socket.gaierror, asyncio.TimeoutError, TimeoutError); add an error counter surfaced in the final summary. No change to the success path.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions