Skip to content

Latest commit

 

History

History
402 lines (291 loc) · 12.3 KB

File metadata and controls

402 lines (291 loc) · 12.3 KB
subenum

Build Release Go License: GPL v3 CodeQL Go Report Card PRs Welcome Platform


Fast concurrent subdomain enumeration, written in Go. Point it at a domain and a wordlist; it brute-forces DNS across a worker pool and prints the subdomains that resolve. Built for pentesters, bug-bounty hunters, and operators doing authorized reconnaissance of their own infrastructure.


subenum interactive TUI

Quick Start  |  Configuration  |  Usage  |  Architecture  |  Changelog



Important

Authorized use only. Only scan domains you own or have explicit written permission to test. Unauthorized scanning may violate applicable laws. Users are solely responsible for compliance with all applicable laws and regulations.



Quick Start

git clone https://github.com/TMHSDigital/subenum.git
cd subenum
go build -buildvcs=false -o subenum
./subenum -w examples/sample_wordlist.txt example.com

No network required to try it out. Simulation mode generates synthetic results with zero DNS queries:

./subenum -simulate -hit-rate 20 -w examples/sample_wordlist.txt example.com

Or launch the interactive terminal UI with no flags:

./subenum -tui



Feature Matrix

Module Description
Worker Pool Spawn N goroutines for parallel DNS resolution with a configurable concurrency ceiling
DNS Engine Resolve subdomains against any DNS server with per-query timeouts and retry backoff
Wildcard Detection Double-probe check before scanning; aborts early unless -force is set
Graceful Shutdown Trap SIGINT/SIGTERM, drain in-flight workers, flush partial results
Input Validation RFC-compliant domain syntax and strict ip:port format enforcement
Wordlist Dedup Deduplicate wordlist entries in a single pass before scanning begins
Simulation Mode Generate synthetic DNS results at a configurable hit rate, with zero network I/O
Output Pipeline Resolved domains to stdout (pipe-clean); progress and diagnostics to stderr
Output Formats Emit results as text, json (array of subdomain plus typed records), or csv via -format
Rate Limiting Cap total DNS queries per second across the worker pool with -rate (context-aware)
Record Types Look up and filter by A, AAAA, or CNAME records with -type
Recursive Enumeration Enumerate subdomains of discovered subdomains with -recursive and a -depth cap, with loop and duplicate protection
Interactive TUI Form-based config and live-scrolling results via -tui; session values persisted



System Architecture

flowchart LR
    subgraph Input
        A[Wordlist File] -->|"dedup + load"| B(Entry Slice)
        C[CLI Flags / TUI Form] --> D(Argument Parser)
    end

    subgraph PreScan
        D --> W{Wildcard\nDetection}
        W -->|"no wildcard / -force"| E
    end

    subgraph Engine
        B --> E{Worker Pool\nN Goroutines}
        E -->|subdomain.domain| F[DNS Resolver]
        F -->|retry + backoff| F
        G[Context] -->|cancel| E
        G -->|timeout| F
    end

    subgraph OutputLayer ["Output"]
        F -->|resolved| H["stdout (results)"]
        F -->|resolved| I[Output File]
        E -->|atomic counters| J["stderr (progress)"]
    end

    K[SIGINT / SIGTERM] -->|cancel| G
Loading



Installation

Prerequisites: Go 1.24.2+ · Git · Make (optional) · Docker (optional)

Build from source
git clone https://github.com/TMHSDigital/subenum.git
cd subenum
go build -buildvcs=false -o subenum
Pre-built binaries

Download the appropriate binary for your platform from the Releases page.

Platforms: Linux (amd64, arm64) · macOS (amd64, arm64) · Windows (amd64)

SHA-256 checksums are provided alongside each binary.

Docker
docker build -t subenum .
docker run --rm -v $(pwd)/data:/data subenum -w /data/wordlist.txt example.com

Or with Compose:

docker compose run subenum
Make targets
make build          # compile binary
make test           # run test suite with race detector
make lint           # run golangci-lint
make simulate       # safe run - no DNS queries
make tui            # launch interactive TUI
make docker-build   # build Docker image
make help           # list all targets



Configuration

CLI flags

Flag Default Description
-w <file> n/a Wordlist file, one prefix per line (required)
-t <n> 100 Concurrent worker goroutines
-timeout <ms> 1000 Per-query DNS timeout in milliseconds
-dns-server <ip:port> 8.8.8.8:53 DNS server address (validated on startup)
-attempts <n> 1 DNS resolution attempts per subdomain (1 = no retry)
-force false Continue scanning even if wildcard DNS is detected
-o <file> n/a Write results to file in addition to stdout
-format <fmt> text Output format: text, json, or csv
-rate <qps> 0 Max DNS queries per second across all workers (0 = unlimited)
-type <list> A,AAAA Comma-separated record types to look up: A, AAAA, CNAME
-recursive false Recursively enumerate subdomains of discovered subdomains
-depth <n> 1 Max recursion depth when -recursive is set (1 = no recursion)
-v false Verbose output: IPs, timings, per-query detail (stderr)
-progress true Live progress line on stderr
-simulate false Simulation mode: no real DNS queries
-hit-rate <n> 15 Simulated resolution rate, percent (1-100)
-tui false Launch the interactive Terminal UI
-version n/a Print version and exit
-retries <n> n/a Deprecated - alias for -attempts, prints a warning

Note

Wildcard DNS is detected automatically before scanning begins. If the target resolves wildcard records, the tool exits with a warning, since all subdomains would match, making results meaningless. Pass -force to override.

Caution

Simulation mode (-simulate) generates synthetic results and performs zero network I/O. Do not confuse simulated output with real DNS data.




Usage

CLI

subenum -w <wordlist> [flags] <domain>
Examples

Basic scan

./subenum -w wordlist.txt example.com

High-throughput with Cloudflare DNS, saving results

./subenum -w wordlist.txt -t 300 -timeout 500 -dns-server 1.1.1.1:53 -o results.txt example.com

Resilient scan for flaky networks

./subenum -w wordlist.txt -attempts 3 -timeout 2000 example.com

Pipe-friendly - only resolved subdomains on stdout

./subenum -w wordlist.txt example.com | cut -d' ' -f2 | your-takeover-scanner

Force scan on a wildcard domain

./subenum -w wordlist.txt -force example.com

Simulation - zero network I/O

./subenum -simulate -hit-rate 20 -w examples/sample_wordlist.txt example.com

Press Ctrl+C at any time to abort. In-flight queries drain and partial results are flushed before exit.


Interactive TUI

./subenum -tui

No flags required. Fill in the form and press ctrl+r to start scanning. Last-used values are saved to ~/.config/subenum/last.json and restored on next launch. The interface is shown at the top of this README.


TUI keyboard reference
Key Action
tab / shift+tab / Navigate fields
space Toggle Simulate / Force
ctrl+r Start scan
ctrl+c Abort scan (scan view) / quit (form)
r New scan - restores last-used values
q Quit after scan completes



Tech Stack

Layer Components
Core Engine Go 1.24.2 · net.Resolver · context · sync/atomic
Concurrency goroutines · channels · sync.WaitGroup · sync.Mutex
TUI Bubble Tea · Bubbles (textinput, viewport, progress) · Lip Gloss
Infrastructure Docker · Alpine · Make · docker-compose
CI/CD GitHub Actions · CodeQL · Dependabot · golangci-lint v2
Quality go test -race · gosec · govet · staticcheck



Project structure
subenum/
├── .github/
│   ├── workflows/
│   │   ├── go.yml              # CI: build, test, lint, release
│   │   ├── codeql.yml          # Weekly CodeQL security analysis
│   │   └── pages.yml           # GitHub Pages deployment
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── dependabot.yml
│   └── PULL_REQUEST_TEMPLATE.md
├── data/
│   └── wordlist.txt            # Default wordlist for Docker/Make
├── docs/
│   ├── assets/
│   │   └── tui-form.png        # TUI screenshot
│   ├── ARCHITECTURE.md
│   ├── CONTRIBUTING.md
│   ├── DEVELOPER_GUIDE.md
│   ├── docker.md
│   ├── _config.yml
│   └── index.md
├── examples/
│   ├── sample_wordlist.txt
│   ├── advanced_usage.md
│   ├── demo.sh
│   └── multi_domain_scan.sh
├── internal/
│   ├── dns/                    # ResolveDomain, CheckWildcard, SimulateResolution
│   ├── output/                 # Thread-safe Writer (stdout/stderr separation)
│   ├── scan/                   # Scan engine: Config, Event types, Run()
│   ├── tui/                    # Bubble Tea UI: form, scan view, session config
│   └── wordlist/               # LoadWordlist (dedup + sanitize)
├── tools/
│   └── wordlist-gen.go
├── main.go                     # CLI entry point
├── main_test.go
├── go.mod
├── Dockerfile
├── docker-compose.yml
├── Makefile
├── .golangci.yml               # golangci-lint v2 configuration
├── CHANGELOG.md
├── SECURITY.md
└── LICENSE                     # GNU General Public License v3.0



Development

See CONTRIBUTING.md for the pull request workflow and ethical guidelines. See DEVELOPER_GUIDE.md for build setup, testing, and project structure.