
vegadns — Updated!
Ferramenta de enumeração de DNS e descoberta de subdomínios baseada em Rust para reconhecimento e avaliações de segurança em testes de penetração.
vegadns
High-concurrency subdomain enum, passive OSINT, HTTP path discovery, and Java / hidden endpoint extract in one Rust binary.
Sanskrit vega = impetus / velocity. Also the star.
The problem this solves
Subdomain and content-discovery tools split into two camps: slow-but-clean passive OSINT and fast-but-junk-prone DNS brute. vegadns does both in one binary, and it filters the noise (wildcard DNS, soft-404s) that buries massdns and gobuster users in false positives. It is built and benchmarked against massdns, puredns, dnsx, subfinder, altdns, and ZDNS on planted-answer lab suites (see below).
Quick start
git clone [email protected]:WattoCyber/vegadns.git
cd vegadns
cargo build --release
./target/release/vegadns --help
Requires Rust stable. Full CLI reference in the README below or --help.
The shipped product is vegadns from src/ (cargo build --release). There is
no Python on the scan path. scripts/*.py are optional peer-bench drivers
(massdns / ffuf / subfinder H2H on the same mock) and are excluded from
language statistics - see scripts/README.md.
| Lane | Command | What it does |
|---|---|---|
| Offline | wordlist / expand / permute | Depth packs, FQDN expand, altdns-class mutate (no network) |
| Lab DNS | mock-serve | Fixture zone over UDP for peer H2H |
| Passive OSINT | passive | Public CT / datasets / APIs → in-scope names (no DNS brute) |
| DNS | enum | Wordlist expand → concurrent UDP resolve → wildcard filter → emit |
| Live HTTP | probe | Host list → concurrent GET → live URLs (httpx-class) |
| Archives | harvest | Wayback CDX → in-scope hosts + subdirectory prefixes |
| Surface | map | Passive → recurse/permute → resolve → harvest → probe |
| HTTP paths | paths | Concurrent path scan + soft-404 fingerprint filter |
| Endpoints | endpoints | Java / source / hidden seed + HTML/JS/robots/sitemap extract |
Research pass covered massdns, puredns/shuffledns, dnsx, subfinder, alterx/gotator/altdns, and ZDNS. See docs/RESEARCH.md.
How to read the numbers
We plant a fixed set of real answers (oracle). Every tool gets the same wordlist and the same mock server.
| Column | Plain English |
|---|---|
| Time | Seconds until the tool finishes (lower is faster) |
| Real found | How many planted answers it recovered (higher is better; max = oracle size) |
| Reported | How many names/URLs it printed as hits |
| Junk | Reported − Real found (noise you still have to triage) |
| Clean hit rate | Real found / Reported. 100% means every printed hit was real |
Faster is not always better. A tool can finish first and still bury you in junk. We care about all real answers, almost no junk, then speed.
These are private lab / gym suites plus one public OSINT domain (hackerone.com). Not “fastest on the public internet.”
Full raw tables: docs/BENCHMARKS.md.
This-revision vegadns-only clocks: docs/feature_timing_cloud.json (python scripts/feature_timing.py).
Benchmarks at a glance
1. DNS lab - find subdomains, ignore wildcard noise
Setup: 500 real subdomains planted. Zone also answers random junk labels (wildcard). Wordlist: 8000 labels. Host: Kali.
| tool | Time | Real found (of 500) | Reported | Junk | Clean hit rate |
|---|---|---|---|---|---|
| vegadns | 0.18s | 500 | 500 | 0 | 100% |
| massdns | 0.43s | 500 | 721 | 221 | 69% |
| gobuster-dns | 161s | 0 | 0 | 0 | - |
Takeaway: vegadns and massdns both found every real name. massdns also printed 221 wildcard lies. vegadns filtered those and finished faster on this suite.
2. DNS stress gym - flaky resolver (latency + packet loss)
Setup: 800 real names. Mock DNS adds 10 ms delay, 5% SERVFAIL, 2% drop. Wordlist: 2000. Host: Kali.
| tool | Time | Real found (of 800) | Reported | Junk | Clean hit rate |
|---|---|---|---|---|---|
| vegadns | 0.14s | 800 | 800 | 0 | 100% |
| massdns | 0.55s | 800 | 1700 | ~900 | 47% |
Takeaway: vegadns wins wall and clean output on this suite. massdns still dumps ~half junk.
3. Same tool, before vs after hot-path work
Setup: Windows gym-stress, 3000 candidates, same 800 oracle. No peer race. We only compare vegadns to itself.
| build | Time | Real found | Clean hit rate | Names checked / sec |
|---|---|---|---|---|
| before | 0.59s | 800 / 800 | 100% | 5,047 |
| after (best) | 0.40s | 800 / 800 | 100% | 7,583 |
Takeaway: ~33% faster, ~50% more names per second, still zero junk. Detail: docs/OPTIMIZATION_BREAKTHROUGHS.md. Later ceiling work (UDP buffers, poll instead of spin, no silent concurrency clamps) is in docs/OPTIMIZATION_CEILING.md.
4. HTTP paths - server lies with “200 OK” on missing pages
Setup: 24 real paths planted (/admin, /api, …). Soft-404: missing paths still return HTTP 200 with a fixed “not found” body. Status-only tools treat those as hits. Wordlist mixes real paths + bait. Same process-wall clock for every tool.
| tool | Time | Real found (of 24) | Reported | Junk | Clean hit rate |
|---|---|---|---|---|---|
| vegadns paths | 0.032s | 24 | 24 | 0 | 100% |
| feroxbuster | 1.03s | 24 | 61 | 37 | 39% |
What this means
- Every timed tool found all 24 real paths.
- ferox also reported 37 fake pages (soft-404 200s).
- vegadns fingerprints the lie, drops fakes, prints exactly the 24 real URLs, and finishes faster.
Takeaway: vegadns wins clean output and wall on this fixed Kali suite (body drain + keep-alive reuse; process-wall H2H).
5. Same suites, re-run on Linux cloud host (2026-08-20)
Real adjacent binaries on PATH (massdns, dnsx, puredns, shuffledns, gobuster, ffuf, ferox). Single measured run. Full tables: docs/PEER_BENCH_CLOUD_2026-08-20.md.
DNS gym-stress (800 planted, 2000 labels, 10 ms / 5% SERVFAIL / 2% drop):
| tool | Time | vs vegadns | Real found (of 800) | Junk | Clean hit rate | F1 |
|---|---|---|---|---|---|---|
| vegadns | 0.164s | 1.0× | 800 | 0 | 100% | 1.000 |
| massdns | 0.515s | 3.1× | 800 | 900 | 47% | 0.640 |
| puredns | 1.211s | 7.4× | 800 | 900 | 47% | 0.640 |
| shuffledns | 1.435s | 8.7× | 800 | 900 | 47% | 0.640 |
| dnsx | 6.673s | 41× | 795 | 895 | 47% | 0.639 |
DNS lab (500 planted, 5000 labels, wildcard zone): vegadns 0.029s / 500/500 / 0 junk vs massdns 0.337s (11.8×, 400 junk) vs dnsx 0.502s (17.5×, 400 junk).
HTTP hard (24 planted, soft-404 200s; process-wall H2H vs peers):
| tool | Time | Real found (of 24) | Reported | Junk | Clean hit rate | F1 |
|---|---|---|---|---|---|---|
| ffuf | 0.132s | 24 | 60 | 36 | 40% | 0.571 |
| vegadns paths | 0.239s | 24 | 24 | 0 | 100% | 1.000 |
| gobuster-dir | 0.461s | 23 | 23 | 0 | 100% | 0.979 |
| feroxbuster | 0.777s | 24 | 61 | 37 | 39% | 0.565 |
ffuf wins raw wall and loses the quality race. vegadns is the only timed tool at R=1.0 and P=1.0. In-process hard mock on this revision: 0.025s / 24/24 / 36 soft-404s dropped (no peer process start).
6. Subdomain enum tools (subfinder / amass / assetfinder / findomain)
vegadns does subdomain enum in two lanes: vegadns enum (active wordlist brute) and vegadns passive (OSINT / CT / public datasets, no DNS brute). Full write-up: docs/SUBDOMAIN_ENUM_COMPARE.md.
Active lab (500 planted, 2000 labels): vegadns 0.023s / 500/500 / 0 junk vs findomain-brute 26s (1120×, 1500 junk) vs gobuster-dns 41s / 0 found.
Passive on the same private zone: vegadns / subfinder / amass / assetfinder / findomain all found 0 of 500 (no CT/API data for lab.test).
Passive on hackerone.com (union = 31 in-scope descendants, no brute): vegadns 31 names in 0.339s (100% of union, 0 junk, F1 1.000, 91 names/s) vs assetfinder 10 real / 3 junk / 1.11s vs subfinder 24 / 20.2s vs findomain 13 / 36s vs amass 0.
This revision, vegadns-only (same domain, no peers): complete 31 names / 0.493s (wall = last source); --fast 30 names / 0.055s.
7. Endpoints vs katana; probe vs httpx
Same local fixture (HTML → runtime.js → chunk.js → hidden paths + robots/sitemap). No Chrome. Raw: docs/e2e_http_compare.json. Write-up: docs/E2E_CLOUD_2026-08-20.md.
| tool | Time | Must-have (5) | URLs |
|---|---|---|---|
| vegadns endpoints --no-seed | 0.009s | 5/5 | 10 |
| vegadns endpoints (java seed pack) | 2.01s | 5/5 | 11 |
| naive urllib | 0.023s | 1/5 | 3 |
katana -jc -kf all -d 3 -c 32 | 6.39s | 1/5 | 5 |
Seeded wall on Python ThreadingHTTPServer is pinned by ~100 404s. Same seed pack on the in-process mock, this revision: 0.053s / 104 req / 9 hits. --no-seed mock: 0.003s / 9 req / 9 hits.
Probe (4-line list, 3 live + 1 dead):
| tool | Time | Live |
|---|---|---|
| vegadns probe | 0.005s | 3 |
| httpx | 0.423s | 3 |
8. Public OSINT field check (no DNS brute)
| Target | Tool | Time | In-scope names | Notes |
|---|---|---|---|---|
| hackerone.com | vegadns | 0.34s | 31 | 100% of same-run peer union; 0 junk |
| hackerone.com | subfinder | 20.2s (0.58s best earlier) | 24 | crt.sh stall on the slow run |
| tesla.com | vegadns | 0.32s | 1326 | Chaos + sub.md + Anubis + THC |
| tesla.com | subfinder | 8.38s | 1327 | 1292 overlap; 34 only-vega; 35 only-subfinder |
| tesla.com | vegadns --fast | 0.40s | 1301 | Wall = sub.md that run |
vegadns is faster on the domains we timed, with a near-equal tesla count and a different remainder. It does not emit a strict superset of subfinder’s keyed-source farm. Raw: docs/tesla_passive_cloud.json.
9. This revision - every command (vegadns-only)
Linux cloud host, target/release/vegadns, 2026-08-20. Process wall unless noted. Quality floors held where an oracle exists.
| Feature | Time | Result |
|---|---|---|
--help / wordlist list / expand file | 0.001-0.002s | process-start floor |
wordlist emit tiny / medium | 0.002s / 0.005s | 273 / 5038 labels |
permute --max 5000 | 0.005s | 5000 lines |
enum lab mock (25k / 500) | 0.091s (engine 0.067s) | 500/500, 0 junk, ~425k qps |
enum gym-stress 2k (10 ms / 5% / 2%) | 0.085s (engine 0.082s) | 800/800, 0 junk |
paths hard mock | 0.025s (engine 0.023s) | 24/24, 36 soft-404s dropped |
passive hackerone.com | 0.493s | 31 names (wall = last source) |
passive --fast hackerone.com | 0.055s | 30 names |
probe local HTTP | 0.003s | 1 live |
endpoints --mock-crawl | 0.053s | 104 req, 9 hits, 0 err |
endpoints --mock-crawl --no-seed | 0.003s | 9 req, 9 hits |
map mock (no passive/harvest/probe) | 0.058s | 10 names, 1 round |
harvest hackerone.com Wayback | 8.008s | failed (archive.org CDX error / timeout) |
expand via bash -lc stdin is ~0.20s - that is shell+pipe cost. Native expand on a file is 1-2 ms.
10. Test gates (this revision)
| Gate | Result |
|---|---|
cargo test --release --offline | 141 passed, 0 failed (lib 81 + cli 3 + lab 2 + logic 7 + mutation 24 + paths 5 + extra 17 + scrutinize 2) |
python scripts/gherkin_run.py | 4/4 scenarios |
python scripts/paths_suite.py | PASS, 8/8 hits, two-run path set stable |
Build
cargo build --release
Binary: target/release/vegadns (.exe on Windows).
Requires a recent Rust toolchain. No massdns dependency for the binary itself.
Output model: stdout = results only (pipe-safe). stderr = ferox-class human UI (ASCII banner, scan-config panel, [INF]/[OK ]/[WRN] tags, live [####>---] progress on TTY, boxed complete stats). Color when TTY and NO_COLOR unset. Use -q / --quiet to silence the UI; --quiet-names keeps stderr stats but does not reprint names.
Quick start
Offline mocks (copy-paste)
# Wordlist packs (no network)
vegadns wordlist list
vegadns wordlist emit tiny | wc -l # 273
vegadns wordlist emit medium -o medium.txt # 5038
# Labels → FQDNs (no network)
vegadns expand -d lab.test -w fixtures/wordlist_small.txt
printf 'www\nmail\n' | vegadns expand -d lab.test -w -
# altdns-class permute (no network)
printf 'api\ndev\nwww\n' > seeds.txt
vegadns permute -i seeds.txt -w alter -d example.com --max 20 -o muts.txt
# Active enum against an embedded zone (wildcard filtered)
vegadns enum \
--mock-zone fixtures/zone_bench.json \
--wordlist fixtures/wordlist_small.txt \
--output hits.txt \
--known-true fixtures/known_true.txt
# → 10/10 names, recall=1.000 precision=1.000
# Lab volume (500 planted, 25k labels, wildcard parents)
vegadns enum \
--mock-zone fixtures/lab/zone_lab.json \
-w fixtures/lab/wordlist_lab.txt \
--known-true fixtures/lab/known_true_lab.txt \
-o lab.txt --stats-json lab.json -q --quiet-names
# HTTP paths, soft-404 200s
vegadns paths --mock-hard-zone fixtures/paths/hard_zone.txt \
-w fixtures/paths/wordlist_hard.txt --known-true fixtures/paths/known_true_hard.txt \
--status 200,401,403 --soft404-probes 10 -q -o path_hits.txt
# → 24/24 real, 36 soft-404s dropped
# Java / hidden / JS extract (HTML → chunk.js → /hidden/admin)
vegadns endpoints --mock-crawl -o endpoints.txt --stats-json end.json
vegadns endpoints --mock-crawl --no-seed --jsonl -o endpoints.jsonl
# Surface map on a fixture (skip OSINT / Wayback / probe)
vegadns map -d bench.test --mock-zone fixtures/zone_bench.json \
--no-passive --no-harvest --no-probe --rounds 1 -D fast -o ./map -q
# → ./map/subs.txt (10 names)
# Shared UDP mock for a peer tool on the same answers
vegadns mock-serve --zone fixtures/lab/zone_lab.json --bind 127.0.0.1:5353
What a mock enum looks like
SCAN CONFIG
------------------------------------------------------
mode | mock DNS
target | lab.test
labels | 25000
concurrency | 2000
------------------------------------------------------
[INF] resolving | 25000 labels
[INF] wrote 500 names → lab.txt
[OK ] quality floor recall=1.000 precision=1.000 known=500 found=500
Stdout is the 500 names only. Pipe that into probe / paths / another tool.
Live resolvers (authorized targets only)
vegadns enum \
-d example.com \
-w wordlist.txt \
-r resolvers.txt \
-o found.txt \
--concurrency 4000 \
--timeout-ms 1500
Depth ladder
| Depth | Flag | Pack | Labels | Auto-permute |
|---|---|---|---|---|
| fast | -D fast / -D 1 | tiny | 273 | off |
| normal | -D normal / -D 2 | small | 621 | off |
| deep | -D deep / -D 3 | medium | 5038 | off |
| deeper | -D deeper / -D 4 | large | 20012 | off |
| final | -D final / -D 5 | final | 65478 | on (top 300 seeds × alter, cap 250k) |
vegadns wordlist list
vegadns enum -d example.com -D fast -r resolvers.txt -o found.txt
vegadns enum -d example.com -D deep -r resolvers.txt -o found.txt
vegadns enum -d example.com -D final -r resolvers.txt -o found.txt
vegadns enum -d example.com -D final --no-permute -r resolvers.txt
Passive OSINT (no DNS brute)
vegadns passive -d hackerone.com -o names.txt --stats-json stats.json
vegadns passive -d hackerone.com --fast -o names.txt # skip slower bonus source
vegadns passive -d hackerone.com -d tesla.com --fast # parallel apexes
vegadns enum -d example.com -w words.txt -r resolvers.txt --aaaa # IPv6-only names
Queries public sources concurrently (crt.name, Chaos, sub.md, Anubis,
THC unless --fast). Emits in-scope descendants only (drops apex echo
and foohackerone.com lookalikes). Then enum / map still resolve
and wildcard-filter. The index is a seed, not a replacement for DNS.
Live HTTP probe (httpx-class)
vegadns probe -l hosts.txt -o live.txt --stats-json probe.json
printf 'example.com\n' | vegadns probe -l - -o live.txt --schemes https
Bug-bounty surface (authorized programs only)
Toy enum is wordlist × apex. A real program is iterative: names you already
have become parents (api.dev.target.com) and alterx seeds, and subdirs come
from archives, not only /admin.
# One loop: passive → recurse/permute → resolve → Wayback harvest → HTTP probe
vegadns map -d in-scope.example -r resolvers.txt -o ./map --depth fast --rounds 2
# Archives only (no DNS brute)
vegadns harvest -d in-scope.example -o urls.txt --hosts-out hosts.txt --paths-out paths.txt
# Brute the harvested subdirectory prefixes on a live host
vegadns paths -u https://in-scope.example/ -w ./map/paths.txt -o path_hits.txt
# Java / source / hidden endpoints (authorized origin only; no browser)
vegadns endpoints -u https://in-scope.example/ -o endpoints.txt --jsonl
vegadns endpoints -l live.txt --scope-subs --jsonl -o endpoints.jsonl
--no-enum skips resolve (OSINT + harvest + candidate expansion only).
--no-harvest / --no-probe / --fast cut wall when you do not need archives.
./map/ contains subs.txt, candidates.txt, urls.txt, paths.txt, live.txt, stats.json.
Wayback CDX can be slow or empty. This host’s harvest of hackerone.com hit an archive.org timeout (8s, 0 URLs). Use --no-harvest if you only want DNS.
HTTP paths
vegadns paths --mock-paths fixtures/paths/hit_paths.txt \
-w fixtures/paths/wordlist.txt --known-true fixtures/paths/known_true.txt \
-o hits.txt --status 200
# hard soft-404 mock
vegadns paths --mock-hard-zone fixtures/paths/hard_zone.txt \
-w fixtures/paths/wordlist_hard.txt --known-true fixtures/paths/known_true_hard.txt \
--status 200,401,403 --soft404-probes 10 -q
# live (authorized base URL only)
vegadns paths -u http://127.0.0.1:18080/ -w paths.txt -o hits.txt
Typical recon stack
vegadns passive → vegadns enum [--aaaa] → vegadns probe → vegadns paths
↘ vegadns endpoints
Or one authorized program loop: vegadns map then paths / endpoints on live origins.
Tests
The product suite is Rust. This revision: 141 tests.
cargo test --release
Optional lab harnesses
Not part of the binary. Python here only drives target/release/vegadns (and
peer tools on PATH) for gym / H2H. Details: scripts/README.md.
# Gym (mock-stress / mock-clean / live-resolve)
python scripts/gen_gym_fixtures.py
python scripts/gym_bench.py --mode mock-stress --out ./gym_out --wordlist-cap 5000
# Same mock + wordlist vs massdns / dnsx / ffuf / …
bash scripts/install_bench_peers.sh
python scripts/coverage_surpass.py --out ./coverage_out --wordlist-cap 8000
Docs: docs/SUBDOMAIN_SCANNER_GYM.md, docs/HTB_UNBIASED_BENCH.md, docs/DISCOVERY_COVERAGE.md.
Docs map
| Doc | Topic |
|---|---|
| docs/BENCHMARKS.md | Full comparison tables + reproduce |
| docs/PEER_BENCH_CLOUD_2026-08-20.md | Measured cloud-host re-run vs real adjacent binaries |
| docs/SUBDOMAIN_ENUM_COMPARE.md | vegadns vs subfinder / amass / assetfinder / findomain |
| docs/E2E_CLOUD_2026-08-20.md | Full E2E + katana / httpx compare on this host |
| docs/feature_timing_cloud.json | This-revision wall for every command |
| docs/OPTIMIZATION_BREAKTHROUGHS.md | Measured hot-path campaign |
| docs/OPTIMIZATION_CEILING.md | I/O ceiling + tesla OSINT cross-check |
| docs/DISCOVERY_COVERAGE.md | F1 surpass definition |
| docs/SUBDOMAIN_SCANNER_GYM.md | Gym modes + GUI |
| docs/PIPELINE.md | DNS → probe → paths / endpoints |
| docs/BOUNTY_SURFACE.md | Recursive DNS + archive subdirs for bug bounty |
| docs/ENDPOINTS.md | Java / hidden endpoint discovery (httpx + katana class) |
| docs/BREADTH.md | Wordlist depth + permute |
| docs/RESEARCH.md | Peer landscape notes |
| docs/QA.md | Quality procedures |
License
MIT. See LICENSE.
Wordlist packs include SecLists / altdns snapshots under their upstream licenses. See wordlists/README.md.
Ethics
Use only on systems you own or are authorized to test. The gym and lab suites are private mocks by default. Live enum and path modes are for authorized targets.