NC3-TestingPlatform/subdomainenum

GitHub: NC3-TestingPlatform/subdomainenum

一款 Python 编写的子域名枚举 CLI,编排多种被动与主动工具完成子域名发现、DNS 解析和虚拟主机模糊测试。

Stars: 0 | Forks: 0

# 子域名枚举 **subdomainenum** 通过被动工具(subfinder、findomain、assetfinder —— 这些工具在内部也会查询 crt.sh 和其他 CT 日志)发现子域名,可选择使用 gobuster 暴力破解 DNS,通过 ffuf 对虚拟主机进行模糊测试,解析每个结果,并打印带有颜色标识的摘要。 ``` $ subdomainenum check example.com ``` ![Python](https://img.shields.io/badge/python-%3E%3D3.11-blue) ![Tests](https://img.shields.io/badge/tests-338%20passing-brightgreen) ![Coverage](https://img.shields.io/badge/coverage-99%25-brightgreen) ![License](https://img.shields.io/badge/license-GPLv3-lightgrey) ## 目录 - [功能](#features) - [依赖要求](#requirements) - [安装说明](#installation) - [外部工具](#external-tools) - [CLI 用法](#cli-usage) - [Python API](#python-api) - [Docker](#docker) - [项目结构](#project-structure) - [运行测试](#running-tests) - [贡献指南](#contributing) ## 功能 | 来源 / 模式 | 类型 | 作用 | | ------------------ | ------- | ------------------------------------------------------------------------------------ | | **subfinder** | 被动 | 运行 `subfinder -d domain -silent -all` (查询所有来源) | | **findomain** | 被动 | 运行 `findomain --target domain --quiet` | | **assetfinder** | 被动 | 运行 `assetfinder --subs-only domain` | | **dnsrecon** | 被动 | 结合 Bing/Yandex/crt.sh (`-b -y -k`) 运行 `std,srv`,SPF 反向解析 (`-s`),AXFR 区域传输 (`-a`),以及 DNSSEC 区域遍历 (`-z`)。AXFR 和区域遍历针对的是域名的权威 nameserver(公共 DNS 基础设施),而不是目标应用程序——因此它们被归类为被动方式。当环境中存在 `SHODAN_API_KEY` 时,会添加 `--shodan --shodan-active`。 | | **gobuster dns** | 主动 | 使用字典暴力破解 DNS (`gobuster dns --domain domain -w wordlist`) | | **ffuf** | 主动 | 通过 `Host` 头模糊测试虚拟主机。目标 IP 会自动派生 —— `--url` 是可选的 (参见 [Vhost 模糊测试](#vhost-fuzzing))。 | | **DNS 解析** | — | 所有被发现的 FQDN 都会被解析 (每个 FQDN 并行解析 A + AAAA 记录) — `A`/`AAAA` 查询会在共享的 256 个工作线程池中并发执行,最终批次最多由 100 个并行 worker 进行解析。`StreamingResolver` 将 DNS 解析与枚举过程重叠:每个工具在解析出 FQDN 时立即将其推送到解析器中,因此当枚举完成时,大多数查询也已经完成。 | 被动和主动来源可以独立运行,也可以组合运行 (`--mode all`)。 在 `--mode all` 模式下,被动池(4 个 worker)和主动池(1 个 worker:gobuster)会并发运行。随后 `ffuf` 会为每个已解析的目标 IP 分配一个 worker (上限为 8 个)。在构建 `ffuf` URL 时查询到的 IP 会被缓存,因此不会对任何 FQDN 进行两次 DNS 解析。 ## 依赖要求 - Python ≥ 3.11 - [`dnspython`](https://www.dnspython.org/) ≥ 2.6 - [`rich`](https://github.com/Textualize/rich) ≥ 13.7 - [`typer`](https://typer.tiangolo.com/) ≥ 0.12 - [`psycopg2-binary`](https://pypi.org/project/psycopg2-binary/) ≥ 2.9 - [`cryptography`](https://cryptography.io/) ≥ 42 外部工具是可选的 —— 缺失的工具会被自动跳过。运行 `subdomainenum info` 以查看哪些工具可用。 ## 安装说明 **从源代码安装(推荐):** ``` git clone https://github.com/NC3-TestingPlatform/subdomainenum.git cd subdomainenum python -m venv .venv source .venv/bin/activate pip install -e ".[dev]" # installs the CLI + all dev/test dependencies ``` 随后即可在你的 shell 中使用 `subdomainenum` 命令。 ## 外部工具 运行 `subdomainenum info` 以检查在 `$PATH` 中检测到了哪些工具: | 工具 | 安装方法 | | ----------- | -------------------------------------------------------------------------- | | subfinder | `go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest` | | findomain | 从 https://github.com/Findomain/Findomain/releases 下载 | | assetfinder | `go install github.com/tomnomnom/assetfinder@latest` | | dnsrecon | `pip install git+https://github.com/darkoperator/dnsrecon.git@master` (在 Docker 镜像中从源代码安装) | | gobuster | `go install github.com/OJ/gobuster/v3@latest` | | ffuf | `go install github.com/ffuf/ffuf/v2@latest` | ## CLI 用法 ### 被动枚举(默认) ``` # 查询 subfinder, findomain, assetfinder, dnsrecon passive (通过 -k 使用 crt.sh) subdomainenum check example.com ``` ### 主动枚举(DNS 暴力破解 + vhost 模糊测试) ``` # 使用 wordlist 进行 DNS 暴力破解 subdomainenum check example.com \ --mode active \ --wordlist /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt # 暴力破解 + vhost 模糊测试 — ffuf 自动在所有已解析的 IP 上运行 subdomainenum check example.com \ --mode active \ --wordlist /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \ --wordlist /opt/SecLists/Discovery/Web-Content/raft-small-words.txt # 将 ffuf 固定到特定 IP(例如负载均衡器 VIP 或内部主机) subdomainenum check example.com \ --mode active \ --wordlist /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \ --url http://10.0.0.1 ``` ### 所有来源组合 ``` # 被动 + 主动,vhost 模糊测试自动定向到所有发现的 IP subdomainenum check example.com \ --mode all \ --wordlist /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt # 使用特定 URL 覆盖 ffuf 目标 subdomainenum check example.com \ --mode all \ --wordlist /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \ --url http://10.0.0.1 ``` ### Vhost 模糊测试 只要提供了字典,ffuf 就会自动启动 —— 无需 `--url` 参数。 **如何选择目标 IP:** 1. 解析基础域名 (`example.com`) (A + AAAA 记录)。 2. 在被动阶段发现的每个子域名会通过共享的 `StreamingResolver` 并行解析 —— 会直接复用枚举期间已缓存的结果,不产生额外的 DNS 开销。 3. 收集所有唯一的 IP 并进行去重。IPv6 地址会用方括号括起来 (`[::1]`)。 4. ffuf 会在每个 IP 上启动一次,最多 8 个 worker 并行执行,针对 `http://` 模糊测试 `Host` 头。 如果指定了 `--url`,则会直接使用该 URL,且不会进行自动解析。 **ffuf 实际在什么时候运行?** | 模式 | ffuf 运行吗? | 目标来源 | |------|-----------|---------------| | `passive` | 否 | — | | `active` | 是(如果提供了字典) | 基础域名 IP + 主动枚举子域名 IP | | `all` | 是(如果提供了字典) | 基础域名 IP + 被动子域名 IP | 结果会进行去重:在多个 IP 中发现的相同虚拟主机只会出现一次。 ### JSON 输出 ``` # 机器可读输出 (stdout) subdomainenum check example.com --json # 保存到文件 subdomainenum check example.com --json --output report.json ``` ### 调试日志 ``` # 将每个工具的原始输出保存到自动命名的日志文件中 subdomainenum check example.com --debug-log # 同样适用于 --json subdomainenum check example.com --json --debug-log ``` 当指定 `--debug-log` 时,每个工具输出的每一行都会被写入一个名为 `_YYYYMMDD_HHMMSS.log` 的文件中。如果挂载了 `/reports/` 卷 (Docker),文件将放置在该目录中,否则放在当前目录下。调试信息不会输出到 stderr —— 结束时会出现一句简短的 `Debug log → ` 确认提示。 ### DNS 超时 ``` # 调整每次查询的 DNS 解析超时时间(默认 5.0 s) subdomainenum check example.com --timeout 10 ``` ### 工具可用性 ``` subdomainenum info ``` ### 版本 ``` subdomainenum --version ``` ## Python API ### 完整评估 ``` from subdomainenum.assessor import assess from subdomainenum.models import EnumMode from subdomainenum.reporter import print_report report = assess( "example.com", mode=EnumMode.PASSIVE, # passive | active | all wordlist=None, # required for active/all url=None, # optional: pin ffuf to one URL; omit to auto-target all resolved IPs timeout=5.0, # DNS resolution timeout per query progress_cb=print, # optional: called with status strings ) print_report(report) ``` ### 处理结果 ``` from subdomainenum.assessor import assess report = assess("example.com") print(report.domain) # "example.com" print(report.mode.value) # "passive" # 子域名 for sub in report.subdomains: print(sub.fqdn, sub.status.value, sub.ip_addresses, sub.tools) # 虚拟主机 (ffuf,仅在带 --url 的主动/全部模式下可用) for vhost in report.vhosts: print(vhost.vhost, vhost.status_code, vhost.content_length) # 按工具划分的结果 for tool in report.tools: print(tool.name, len(tool.subdomains), tool.available, tool.error) ``` `Status` 值:`ALIVE`、`DEAD`、`TIMEOUT`、`ERROR`、`FOUND`、`NOT_FOUND`、`SKIPPED`。 ### JSON 序列化 ``` import json from subdomainenum.assessor import assess from subdomainenum.reporter import to_dict report = assess("example.com") print(json.dumps(to_dict(report), indent=2)) ``` 顶层 schema: | 键 | 类型 | 备注 | |---|---|---| | `domain` | string | 目标基础域名 | | `mode` | string | `"passive"`、`"active"` 或 `"all"` | | `subdomains[]` | array | `{fqdn, status, alive, ip_addresses, tools}` | | `vhosts[]` | array | `{vhost, status_code, content_length}` | | `tools[]` | array | `{name, count, available, error, timed_out, mode}` | 每个 `tools[]` 条目反映了单次工具运行的整个生命周期:`available=false` 表示缺少相应的二进制文件或 API;`timed_out=true` 表示该工具被总时长或空闲超时看门狗杀死(与 `error` 不同);当工具引发或报告错误时,`error` 是一个字符串,否则为 `null`。 ## Docker 通过附带的 `Dockerfile`,提供了一个预装所有工具并捆绑了 SecLists(DNS + Web-Content 目录)的 Docker 镜像。 ``` # 构建镜像 docker compose build # 被动检查 docker compose run subdomainenum check example.com # 使用捆绑的 SecLists wordlist 进行主动检查 docker compose run subdomainenum check example.com \ --mode active \ --wordlist /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt # 所有模式 + vhost 模糊测试,将报告保存到主机 ./reports/ docker compose run subdomainenum check example.com \ --mode all \ --wordlist /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \ --url http://10.0.0.1 \ --json \ --output /reports/example.json # 检查容器内的可用工具 docker compose run subdomainenum info ``` ## 项目结构 ``` subdomainenum/ ├── subdomainenum/ │ ├── __init__.py Package version │ ├── models.py Dataclasses: SubdomainResult, VhostResult, │ │ ToolResult, EnumReport + Status/EnumMode enums │ ├── dns_utils.py resolve_ips(), is_alive() — dnspython wrappers │ │ (A+AAAA queried in parallel on a shared pool) │ ├── streaming.py StreamingResolver — background DNS queue that │ │ overlaps resolution with enumeration │ ├── constants.py ACTIVE_TOOLS registry, detect_tools(), get_install_hint() │ ├── assessor.py assess() — orchestrates passive + active sources │ ├── reporter.py Rich terminal output + to_dict() + save_report() │ ├── verdict.py build_verdict() — factual count summary │ ├── cli.py Typer CLI: check, info sub-commands │ └── tools/ │ ├── tool_runner.py subprocess wrapper used by all active tools │ ├── subfinder.py subfinder wrapper │ ├── findomain.py findomain wrapper │ ├── assetfinder.py assetfinder wrapper │ ├── dnsrecon.py dnsrecon wrapper (std,srv + Bing/Yandex/crt.sh/SPF │ │ + AXFR + DNSSEC zone walk; always passive) │ ├── gobuster_dns.py gobuster dns wrapper (sole DNS brute-forcer) │ └── ffuf.py ffuf vhost fuzzing wrapper ├── tests/ │ ├── __init__.py │ ├── test_models.py │ ├── test_verdict.py │ ├── test_constants.py │ ├── test_dns_utils.py │ ├── test_assessor.py │ ├── test_reporter.py │ ├── test_cli.py │ └── tools/ │ ├── test_tool_runner.py │ └── test_wrappers.py ├── Dockerfile ├── docker-compose.yml ├── pyproject.toml ├── requirements.txt ├── requirements-dev.txt └── README.md ``` ## 运行测试 ``` source .venv/bin/activate # 带覆盖率运行所有测试(通过 pyproject.toml 自动配置) pytest # 快速运行(简短的 tracebacks) pytest --tb=short -q # 运行单个模块 pytest tests/test_assessor.py -v # 运行单个测试类 pytest tests/test_cli.py::TestCheckCommand -v ``` 测试套件包含 **338 个测试**,并在所有模块中达到了 **99% 的测试覆盖率**。 所有的 DNS I/O (`dns.resolver.Resolver.resolve`)、TLS sockets 以及 subprocess 调用都在边界处进行了 mock —— 没有任何测试会连接到真实服务器或互联网。 ## 贡献指南 1. Fork 该仓库并创建一个功能分支。 2. 添加或更新测试 —— 该项目的目标是达到 80% 以上的单元测试覆盖率。 3. 在提交 pull request 之前运行 `pytest` 并确认所有测试通过。 4. 遵循现有的 docstring 格式 (reStructuredText / docutils 字段列表)。 5. 使用 [约定式提交](https://www.conventionalcommits.org/): `fix:`、`feat:`、`refactor:`、`test:`、`docs:`、`chore:` ## 许可证 GPLv3 —— 详见 [LICENSE](LICENSE)。
标签:amass, assetfinder, Bug Bounty, CT日志查询, dnsrecon, DNS安全, DNS枚举, DNS爆破, DNS解析, ffuf, findomain, GitHub, gobuster, Python命令行工具, subfinder, 主动发现, 可自定义解析器, 域名侦察, 子域名扫描器, 子域名枚举, 安全工具库, 开源项目, 系统安全, 网络安全工具, 虚拟主机发现, 被动侦察, 请求拦截, 逆向工具