sazzad1148/sazzadul-APRSR-Framework

GitHub: sazzad1148/sazzadul-APRSR-Framework

一款高性能的被动与递归子域名侦察框架,通过多数据源并行采集、DNS 验证、云资产指纹识别和置信度引擎,为安全评估提供全面的攻击面发现能力。

Stars: 0 | Forks: 0

# sazzad007 -- 被动 + 主动子域名侦察 通过 **19 个生产就绪的数据源**进行被动子域名发现,智能多解析器 通配符过滤,**多源递归枚举**(crt.sh SAN 链式查询 + Wayback + GitHub + 可选的主动 JS/CSP 抓取),深度排列(级别 2-8),包含 **TTL / 使用的解析器 / 响应时间 / DNSSEC** 的 DNS 验证,按 **ASN / 组织 / 云服务商** 分组的反向 DNS,云 资产指纹识别(AWS, Azure, GCP, Cloudflare, Fastly, Akamai, Vercel, Netlify, Heroku, GitHub Pages, ...),一个**可配置、可解释的置信度 引擎**,一个**数据源健康摘要**,一个可查询的 **SQLite 情报 数据库**,针对上一次运行的**差异对比模式**,以及整洁的 `txt/ + json/ + reports/` 输出布局 —— 包含恢复支持、缓存、分阶段指标 和自动发现的插件架构。 请参阅 `ARCHITECTURE.md` 了解 pipeline 图表、完整的 JSON schema、插件 SDK 契约和置信度引擎公式。请参阅 `CONTRIBUTING.md` 了解开发 配置以及如何添加新数据源。请参阅 `CHANGELOG.md` 了解版本历史。 请参阅 `examples/` 获取示例输出(所有格式)、示例配置文件 (JSON/YAML/TOML)以及示例批量域名列表。 ### 快速开始(安装) ``` git clone https://github.com/sazzad1148/sazzadul-APRSR-Framework.git cd sazzadul-APRSR-Framework # the folder containing run.py pip install -r requirements.txt --break-system-packages # (或者,以 pip 可安装的形式:pip install -e . —— 这也会为你提供 # `passive-enum` 命令,请参阅下文的第 2/17 节) cp .env.example .env # optional -- fill in any free API keys you have nano .env python3 run.py -d example.com --profile balanced ``` 完整详情(配置文件、密钥、CLI 工具数据源、故障排除)位于 下面的第 1 节。 ### v3.1 中的新功能(本轮) | 功能 | 状态 | |---|---| | 模块化插件系统 | 完成 | | 自动插件发现(放入一个 `.py` 文件即生效) | 完成 —— 本身已实现,已通过专门的测试验证 | | 数据源健康摘要(每个数据源的 ok/skipped/error + 主机数 + 重复项) | 完成 | | 置信度引擎(累加、可解释、可通过 `--config-file` 配置) | 完成 | | 数据源归因 | 完成 | | 丰富的 JSON schema(`confidence_breakdown`、发现路径、ASN、云、丰富信息) | 完成 | | TXT / CSV / HTML / Markdown 报告 | 完成 | | SQLite 情报数据库(`intel.sqlite3`:运行历史、主机历史、搜索、跨运行重复项) | 完成 | | 差异模式(`--diff ` 或 `--diff auto`) | 完成 | | 恢复(按阶段检查点 + 优雅的 Ctrl+C 提示信息) | 完成,阶段中恢复不在本次范围内(参见 ARCHITECTURE.md) | | 新增/修改模块上的类型提示 | 完成;全代码库严格的 `mypy` 仍在进行中,目前还不是强制的 CI 门禁 | | `black` / `ruff` / `mypy` / pre-commit | 已配置(`pyproject.toml`, `.pre-commit-config.yaml`) | | 测试 | 跨 5 个文件的 25 个测试,涵盖标准化、配置、置信度引擎、数据源健康、插件发现、情报数据库、差异模式、导出器;未声明覆盖率百分比,因为在此沙箱中未运行 `coverage.py`(无网络安装) | | CI/CD (lint -> 测试矩阵 3.11/3.12 -> 构建) | 完成 | | pip 打包(`pyproject.toml`, `passive-enum` 控制台脚本) | 完成 | | Async 引擎 | 未完成 —— 当前并发基于线程池(`ThreadPoolExecutor`),这对于 I/O 密集型的 HTTP/DNS 工作已足够;真正的异步重写是更大的架构变更,留待未来进行 | | 带有图表/时间线的 HTML 仪表板 | 部分完成 —— `report.html` 是一个可交互、可排序/可过滤的表格,带有摘要统计卡片,而不是图表式仪表板 | | 专属的 "Mr. Cool" 启动横幅(logo 艺术字 + 作者:Sazzadul / 版本 / 引擎 / 模式 / 状态面板) | 完成 | | `--minimal` 输出模式(仅保留 `txt/final_hosts.txt` + `reports/report.json`,删除其他所有内容) | 完成 | | 每次运行自动刷新输出(第二次运行绝不与第一次运行的残留混合;`--resume` 是唯一的退出选项) | 完成 | | 批量模式:`-dL/--domain-list example.txt` 可在一个命令中扫描 2 个或以上的域名,每个域名生成自己的输出子文件夹 | 完成 | ### 每个数据源的原始/标准化/拒绝/重复项明细 以前,数据源的日志行只显示最终计数(例如 `assetfinder: 58 normalized hosts`)—— 如果一个数据源返回了实际数据,但 全部在标准化/范围检查中被拒绝,这与该数据源 合法地一无所获是无法区分的。首先验证了 `normalize_hostname()` 本身没有错误(针对匹配实际真实域名的 subfinder 输出的 18 个 真实主机名模式进行了测试 —— 全部正确标准化),因此这并没有掩盖解析错误 —— 但*可见性*差距是真实存在的,现在已修复: ``` [+] subfinder: 428 normalized hosts (raw=558, rejected=6, dup=124) ``` 如果一个数据源确实返回了全部被拒绝的数据,现在将标记为 `WARNING`,而不是静默的 `INFO` 行,因此它不会混入正常的“一无所获”结果中: ``` [!] some-source: got 558 raw line(s) but 0 normalized -- likely a real parsing/scope issue, not "found nothing". Run with --debug for detail. ``` `raw`、`rejected` 和 `duplicate_in_source` 也存在于 `reports/report.json` 中 每个主机的 `provider_health` 条目中,并显示在控制台的 数据源健康摘要中。新增了 2 个回归测试,涵盖了正常的 明细和异常标记行为。 ### 第二个性能修复:被动数据源收集也是顺序执行的 递归阶段的修复(见下文)并不是唯一的顺序瓶颈。 **阶段 1** —— 查询所有被动数据源(此修复完成时有 21 个, 现在移除了 C99/CertDB 后是 19 个)—— 以完全相同的方式运行: 一次一个数据源,在一个普通的 `for` 循环中,每个阻塞调用(包括 像 crt.sh 这样缓慢/受限的免费 API,以及像 `findomain`/`sublist3r` 这样生成子进程的 CLI 工具)在下一个开始之前完全串行。针对 真实的数据源延迟配置,仅仅这一项在 DNS 验证、递归或排列开始之前 就需要花费几分钟 —— 几乎可以肯定 是导致数小时总运行时间的最大元凶。 采用与递归相同的方式修复:一个有界的并行工作线程池 (`source_threads` —— 快速/均衡/彻底模式下分别为 8/12/19,可通过 `--source-threads` 覆盖)。使用真实延迟配置(大多数 数据源 3-8 秒,几个慢的达到 20 秒)进行的模拟从 **148 秒的串行 变为 22 秒的并行 —— 仅此阶段就加速了 6.7 倍**;再加上 递归修复,这才是真正弥补“1-3 小时”差距的关键,而不是 添加更多的数据源或功能。新增了 3 个回归测试。 ### 第三个性能修复:“仍然卡住数小时”的根本原因 并行化上述两个阶段是必要的,但**并不充分** —— 一些实际运行之后仍然会停滞数小时。真正的 bug 是: 两个阶段都使用了 `with concurrent.futures.ThreadPoolExecutor(...) as ex:`。 退出该代码块会调用 `ex.shutdown(wait=True)`,这会阻塞直到 **每一个**提交的任务完成,无论有多少任务已经完成。 一个异常缓慢的响应 —— 例如 crt.sh 查询一个与数千个无关名称共享 通配符证书的主机,这是一种真实的常见情况 —— 可能会劫持整个一轮,即使该轮中的其他 100 多个调用在几秒钟内并行完成。 工作是真正并行的;*退出路径*会悄无声息地重新串行化到 最慢的落后者身上。 通过为每个阶段设置硬性的挂钟时间上限来修复: ``` python3 run.py -d example.com --recursion-round-timeout 120 # default: 60/180/400s by profile python3 run.py -d example.com --source-stage-timeout 120 # default: 60/180/400s by profile ``` 两个阶段现在都通过 `as_completed(futures, timeout=)` 等待 ,而不是无限期阻塞;超时时,保留已完成的内容, 按名称记录落后者,并且 `ex.shutdown(wait=False, cancel_futures=True)` 立即返回,而不是等待 已经运行的线程(Python 无法强制杀死一个线程 —— 它们 在后台完成,其结果被直接丢弃)。现在一轮运行 永远不会超过其配置的上限时间, 无论单个最慢的响应有多慢。由一个专门的回归测试覆盖,如果 这再次退化为阻塞,测试将会失败。 ### 可维护性/DX 优化阶段的补充内容 - **模块拆分**:将 `dns_utils.py`(445 行)拆分为 `dns_utils.py` (通配符 + 核心验证/PTR)和 `enrichment.py`(ASN 查询、云 指纹识别、完整 DNS 记录收集)。`pipeline.py` 的递归 扩展方法已移出至 `recursion_expanders.py`,作为普通的、 可独立测试的函数。参见 `ARCHITECTURE.md` 的新“模块 布局”表。(`pipeline.py` 仍然是最大的文件,约 630 行 —— 那是 11 阶段的编排器本身;进一步按阶段拆分 是可能的,但本轮未进行。) - **`summary.json`**:一个精简的摘要(计数、数据源健康状态、 重复项、ASN/云分组、置信度权重),与完整的 `report.json` 并存,适用于只需要数字的脚本/仪表板。 - **YAML/TOML 配置文件**:`--config-file` 现在接受 `.yaml`/`.yml` (需要 `pip install pyyaml`)和 `.toml`(标准库,无需额外安装), 除了 `.json` 之外。 - **真正的文件日志记录**:`output//logs/run_.log` 现在 被真正创建了(之前有文档说明但从未连接到代码) —— 无论控制台详细程度如何,始终捕获完整的 DEBUG 级别 详情。新增了 `--debug`(显示数据源失败的完整回溯,包括控制台和 日志中)和 `--quiet`(仅控制台显示 WARNING 级别, 完整详情仍会写入日志文件)标志。 - **进度显示**:DNS 验证、反向 DNS、云发现和 DNS 记录收集现在显示实时进度(如果安装了 `tqdm` 进度条,否则显示周期性 日志行 —— 无论哪种方式都有速率 + 预计剩余时间)。 每个 pipeline 阶段还会记录一个 `[stage N/11] ` 标记。 ### 最新全代码审查阶段的修复 - **让静默失败变得可见(“subfinder: 0 hosts 但手动运行正常” 的 bug):** 每个数据源 —— 基于 CLI 工具的(`subfinder`, `findomain`, `assetfinder`, `sublist3r`)和基于 HTTP 的(`crt.sh` 及其他 13 个) —— 以前都会吞掉真实的错误(超时、非零退出码、连接 被拒绝、非 2xx HTTP 响应、解析崩溃),将其变成裸露的 `except Exception: return []`。这使得“工具实际上失败”完全无法 与“它运行良好并合法地找到了零个 子域名”区分开来 —— 这正是当 `subfinder` 通过 pipeline 报告 0,而手动运行相同的 `subfinder -d ...` 命令却发现了 558 个时发生的情况。已修复:真实结果为零的干净运行(exit 0 / HTTP 2xx,输出为空)仍然正确地返回一个空列表 —— 这是一个 真实的答案。现在其他所有情况都会抛出异常(`CLISourceError` / `HTTPSourceError`),`stage_passive_sources` 中现有的针对每个数据源的 try/except 已经捕获了这些异常,并将其作为正确的 `error` 条目报告(包含 真实原因 —— 退出码、stderr 片段、HTTP 状态、连接 失败)在数据源健康摘要中,而不是令人误解的 `✓ 0 hosts`。新增了 15 个测试,涵盖辅助函数和真实数据源集成。 - **严重性能 bug:** 递归枚举完全串行运行 —— 425 个主机 x 3 个数据源(一个真实的案例,`crypto.com`)意味着 1275+ 次阻塞 HTTP 调用,一次一个地针对像 crt.sh 这样受限的 API, 这可能会在单轮中卡住一个小时或更长时间。已修复,使用了一个 有界的并行工作线程池(`recursion_threads`,每个配置文件 新增的可调参数)以及一个可选的每轮前沿上限 (`max_recursion_frontier_per_round`),适用于非常大的域名。请参阅 第 7 节了解修改前对比以及如何调整或禁用它们。新增了 3 个 回归测试,包括一个如果代码再次变为串行就会失败的测试。 从头到尾检查了整个代码库并修复了所有发现的问题: - **Bug:** 同时使用 `--diff --minimal` 会静默删除 `reports/diff.json` / `reports/diff.md` —— `--minimal` 的清理只 保留了 `report.json`,因此 `--diff` 被要求生成的内容被 丢弃了。已修复:`cleanup_to_minimal()` 现在也会在存在时保留 `diff.json`/`diff.md`。新增了回归测试 (`test_cleanup_to_minimal_keeps_final_report_and_diff_output`)和一个 端到端复现,以确保这不会静默退化。 - **Bug:** 数据源健康格式化程序中的无效三元运算符 (`"✓" if hosts > 0 else "✓"` —— 两个分支相同,显然是 遗留错误)。简化为只保留一个对勾。 - **清理:** 移除了 `cli.py` 中未使用的 `import sys`。 - **强化:** 将排列主机映射回其父级(用于 `discovery_path`)时使用的递归深度防护现在完全匹配 `wordgen.generate_deep_permutations` 的边界检查(`depth < 0 or depth >= max_depth`,而不仅仅是上限) —— 这是防御性的,因为 实际上到达该代码的每个基础主机都已经在范围内。 - 全代码审查还检查了:API 密钥是否在任何地方被记录/打印 (没有 —— 仅作为不透明的字典值传递)、每个模块中未使用的导入 (启发式 + 手动检查 —— 干净)、裸露的 `except:` 子句(无 —— 每个捕获都是 `except Exception:`,因此 `KeyboardInterrupt`/`SystemExit` 仍然正确传播)。 ### 安装(pip,可选) ``` pip install -e . # editable install from this repo, or `pip install .` passive-enum -d example.com --profile balanced ``` `python3 run.py -d example.com` 仍将像以前一样完全正常工作 —— pip 控制台脚本是一个额外的入口点,而不是替代品。 **范围:** 仅对你拥有或明确 授权测试的域名运行此工具。它只查询公共/被动数据源并执行 标准 DNS 解析 —— 无漏洞利用,无凭据攻击。可选的 `--active-recursion` 标志会抓取发现的主机上的公共页面 (以挖掘 JS/CSP 获取更多主机名) —— 仍然没有漏洞利用,但它是 向目标自身服务器发出的直接 HTTP 请求,因此它是可选的且默认关闭。 **项目范围(刻意为之):** 这是一个*子域名侦察*工具 —— 寻找最大数量的有效子域名并丰富其信息(数据源、DNS 记录、ASN、云、置信度)。它有意不进行端口 扫描、漏洞扫描(nuclei)、屏幕截图、JS 密钥扫描、 目录暴力破解或漏洞利用 —— 那些是不同工具的 工作,强行加上它们会把一个快速、专注的侦察工具变成一个缓慢、 臃肿的工具。如果你需要这些功能,请将此工具的 `txt/final_hosts.txt` 通过管道传递给 `httpx`、`nuclei`、`gowitness` 等。 ## 1. 安装 ``` # 从项目根目录(包含 run.py 的文件夹) pip install -r requirements.txt --break-system-packages # 可选的外部 CLI 工具(自动检测,如果缺失则跳过): # subfinder https://github.com/projectdiscovery/subfinder # assetfinder https://github.com/tomnomnom/assetfinder # findomain https://github.com/findomain/findomain # sublist3r https://github.com/aboul3la/Sublist3r ``` 检查你的系统上有哪些可用工具: ``` python3 run.py --list-plugins name confidence available ----------------------------------------------- alienvault_otx Medium yes anubisdb Medium yes assetfinder Medium no (missing key/binary) bufferover Medium yes censys High no (missing key/binary) certspotter High yes chaos High no (missing key/binary) crt.sh High yes findomain Medium no (missing key/binary) fullhunt Medium no (missing key/binary) github Medium no (missing key/binary) hackertarget Medium yes rapiddns Medium yes subfinder Medium no (missing key/binary) sublist3r Medium no (missing key/binary) threatminer Medium yes urlscan Medium yes virustotal Medium no (missing key/binary) wayback Medium yes ``` 开箱即用的免密钥数据源(9 个):`crt.sh`, `bufferover`, `alienvault_otx`, `rapiddns`, `wayback`, `urlscan`(数量少), `certspotter`(速率限制 低), `hackertarget`(免费层级限制严格), `anubisdb`, `threatminer`。 CLI 工具数据源(单独安装,在 `PATH` 中自动检测):`subfinder`, `assetfinder`, `findomain`, `sublist3r`。 可选 API 密钥数据源(5 个) —— 全部免费注册,无需付款。对于 其中每一个,行为都是相同的:**存在密钥 -> 运行该数据源;缺少密钥 -> 自动跳过,并在数据源健康摘要中给出明确原因, pipeline 的其余部分正常继续。** 没有例外,没有崩溃,其他任何东西都不受影响 —— 由 `test_passive_sources_skipped_when_unavailable` 和 `stage_passive_sources` 中的“已跳过”状态路径(`Pipeline.provider_health`)确认。 | 数据源 | 免费注册地址 | CLI 标志 | |---|---|---| | GitHub | github.com(个人访问令牌) | `--github-token` | | Censys | search.censys.io(社区层级) | `--censys-id` + `--censys-secret`(均需提供) | | VirusTotal | virustotal.com | `--virustotal-key` | | FullHunt | fullhunt.io | `--fullhunt-key` | | Chaos | chaos.projectdiscovery.io(免费,基于资格) | `--chaos-key` | `urlscan.io` 和 `CertSpotter` 也接受可选的密钥 (`--urlscan-key` / `--certspotter-key`)以提高其速率限制,但 它们支持免密钥使用(如上所列),而不仅仅是可选使用。 **已从此项目中移除:** C99(曾是一个**付费** API —— 不应该 放在免费/ freemium 数据源旁边)和 CertDB(曾是一个没有真实 接口的存根 —— 没有单一的标准化公共“CertDB”服务,因此它 从未真正起作用)。计算它们中的任何一个都会使数据源计数 不准确;19 是真正针对真实 数据运行的数据源数量。如果你有一个想要接入的真实付费 API 密钥(C99 或其他 任何内容),第 11 节中的插件模式使其成为一个即插即用的文件,无需更改 核心代码。 刻意未包含(仅限付费,无可用免费层级):Shodan, BinaryEdge。刻意未包含的数据源及其原因(已停止维护、 违反服务条款的抓取,或已通过其他方式覆盖的独立工具)与 上一个 README 部分相比未做更改,并且仍然适用。 ### 存储 API 密钥 ``` cp .env.example .env # 然后编辑 .env 并填入你拥有的任何 key ``` `.env` 已包含在 `.gitignore` 中。如果一个密钥在多个 地方设置,优先级为:`--flag-on-cli` > shell 环境变量 > `.env` 文件。 ## 2. 基本用法 ``` python3 run.py -d example.com --profile balanced ``` ### 自动刷新输出(默认行为) 每次运行都会为该域名重置状态 —— 除非你传递 `--resume`,否则该域名的输出目录会在 pipeline 启动前自动清除。对同一个域名进行第二次运行永远不会与 第一次运行的遗留文件混合;你不需要记住使用 `--fresh`(为了 向后兼容保留为一个空操作标志,但只要 你不进行恢复,现在清除就是默认行为)。 ``` python3 run.py -d example.com --profile fast # run 1 -> output/... python3 run.py -d example.com --profile fast # run 2 -> output/ auto-wiped first, clean result python3 run.py -d example.com --profile fast --resume # only this one preserves the prior output ``` ### 一次扫描多个域名(`-dL` / `--domain-list`) ``` # example.txt —— 每行一个域名,空行和 #注释 会被跳过 example.com another-domain.com # this-one-is-commented-out.com third-domain.com ``` ``` python3 run.py -dL example.txt --profile balanced ``` 针对文件中的每个域名运行完整的 pipeline(重复项 不区分大小写地进行去重)。你也可以将 `-d` 与 `-dL` 结合使用 —— 两者 都会被扫描。每个域名都有其**独立的隔离输出子文件夹**: ``` output/ example.com/ txt/ json/ reports/ ... another-domain.com/ txt/ json/ reports/ ... third-domain.com/ txt/ json/ reports/ ... ``` (如果只有单个 `-d` 而没有 `-dL`,输出将完全像以前一样保持在 `output/...` 的扁平结构 —— 按域名划分的子文件夹仅在批量 模式下启用,因此现有的单域名脚本/工作流不受影响。)自动刷新 适用于每个域名,并且 Ctrl+C 会停止整个批次(已完成的 域名保留其结果;被中断的域名可以使用 `--resume -d ` 单独恢复)。批量摘要 (每个域名的 OK/INTERRUPTED/FAILED)将在最后打印。 **只想要最终结果,不想要其他内容?** 使用 `--minimal` —— 运行 后,除了两个最终报告文件之外的所有内容都会被自动删除: ``` python3 run.py -d example.com --profile fast --minimal ``` 只保留: ``` output/ txt/final_hosts.txt # hostnames only, one per line reports/report.json # full structured report (IPs, sources, confidence, cloud, ...) ``` 其他一切 —— 每个阶段的 `json/`,其他的 `txt/*.txt` 文件, `report.csv`/`.html`/`.md`, `cache.sqlite3`, `intel.sqlite3`, `metadata.json`, `checkpoints/`, `logs/` —— 都会被移除。(如果不使用 `--minimal`,默认行为保持不变:仅 `checkpoints/` 会 被自动删除,其他一切保留 —— 见第 3 节和第 18 节。) ## 3. 输出结构 ``` output/ txt/ passive_hosts.txt # stage 01 -- raw candidates, pre-DNS-validation validated_hosts.txt # stage 03 -- initial DNS-validated hosts recursive_hosts.txt # stage 04 -- hosts after recursive expansion permutation_hosts.txt # stage 06 -- hosts found via permutation final_hosts.txt # FINAL validated hostnames -- ONLY hostnames, one per line json/ 01_passive_sources.json 02_wildcard_detection.json 03_initial_dns_validation.json 04_recursive_enumeration.json 05_word_extraction.json 06_permutation_validation.json 07_reverse_dns.json # PTR + ASN, per IP 08_cloud_discovery.json 09_dns_records.json 10_final_filter_validation.json # final hosts + TTL/resolver/RTT/DNSSEC reports/ report.json # full structured report: hostname -> IPs + everything else summary.json # lean summary only: counts, provider health, duplicates, # ASN/cloud groupings, confidence weights -- no per-host array report.csv report.html # dark-themed, sortable, filterable report.md metadata.json # first_seen/last_seen/sources/discovery_path per host intel.sqlite3 # run history (see section 15) -- separate from cache.sqlite3 cache.sqlite3 # API + DNS cache (persists across runs) logs/ run_.log # full DEBUG-level log for this run, regardless of # console verbosity (--quiet still gets a complete file) checkpoints/ # per-stage checkpoint files, auto-deleted after a # successful run (see "Auto-cleanup" below) ``` **`txt/final_hosts.txt` 仅包含已验证的主机名** —— 没有 IP,没有 元数据 —— 恰好是“仅主机名”列表。你要求追踪的其他每一个字段 (数据源、provider_count、置信度、记录、云、通配符、 recursive_depth、discovery_path、标签、元数据)都存在于 `reports/report.json` 中, 针对每个主机,例如: ``` { "host": "login.example.com", "validated": true, "sources": ["crt.sh", "recursive-wayback"], "provider_count": 2, "confidence": 0.98, "confidence_label": "High", "records": { "ips": ["1.2.3.4"], "ttl": 300, "resolver_used": "8.8.8.8", "response_time_ms": 14.2, "dnssec": false, "dns_records": {"A": {"values": ["1.2.3.4"], "ttl": 300}, "MX": {...}} }, "cloud": {"provider": "AWS", "service": "CloudFront", "evidence": "d123.cloudfront.net"}, "wildcard": false, "recursive_depth": 1, "discovery_path": ["example.com"], "tags": ["recursive"], "metadata": { "first_seen": 1753350000.0, "last_seen": 1753350100.0, "validation_time": 1753350100.0, "ptr": {"1.2.3.4": "ec2-1-2-3-4.compute-1.amazonaws.com"}, "asn": {"1.2.3.4": {"asn": "16509", "prefix": "1.2.3.0/24", "country": "US", "registry": "arin", "org": "AMAZON-02"}} } } ``` ### 自动清理 在运行成功完成后,`output/checkpoints/` 将被自动删除 (一旦每个阶段完成,就没有什么可恢复的了) —— `txt/`, `json/`, `reports/`, `metadata.json`, `cache.sqlite3` 和 `logs/` 将 被保留;这些才是真正的交付物。如果你想检查它们或稍后恢复分析某次运行,请传递 `--keep-checkpoints`。 ## 4. 配置文件 配置文件 | 线程数 | 最大深度 | 每级排列数 | 缓存 TTL | 检查的 DNS 解析器 ---|---|---|---|---|--- fast | 30 | 2 | 500 | 1h | 系统默认 balanced | 60 | 5 | 3,000 | 6h | 8.8.8.8, 1.1.1.1 thorough | 100 | 8 | 20,000 | 24h | 8.8.8.8, 1.1.1.1, 9.9.9.9 ``` python3 run.py -d example.com --profile thorough --max-depth 8 python3 run.py -d example.com --profile balanced --threads 120 --perm-limit 8000 python3 run.py -d example.com --profile balanced --config-file myconfig.json ``` `--config-file` 接受三种格式,通过扩展名选择: ``` python3 run.py -d example.com --config-file myconfig.json # stdlib, always available python3 run.py -d example.com --config-file myconfig.toml # stdlib (tomllib, Python 3.11+), no extra install python3 run.py -d example.com --config-file myconfig.yaml # needs: pip install pyyaml --break-system-packages ``` 相同的键,任何格式 —— 例如 `myconfig.yaml`: ``` threads: 80 max_depth: 6 cache_ttl_seconds: 3600 confidence_weights: cloud: 20 permutation_penalty: -25 ``` `--config-file` 根据扩展名选择解析器 —— `.json`(始终 可用),`.toml`(标准库 `tomllib`,Python 3.11+,无需额外安装),或 `.yaml`/`.yml`(需要 `pip install pyyaml`,如果缺少则会引发明确的错误 提示你安装,而不是令人困惑的回溯): ``` // myconfig.json { "threads": 80, "max_depth": 6, "cache_ttl_seconds": 3600 } ``` ``` # myconfig.yaml threads: 80 max_depth: 6 cache_ttl_seconds: 3600 confidence_weights: cloud: 20 permutation_penalty: -25 ``` ``` # myconfig.toml threads = 80 max_depth = 6 cache_ttl_seconds = 3600 ``` 这三种方式都是等效的 —— 选择你已经在 工具链中使用的格式即可。 ## 5. 更智能的通配符检测 简单的单次探测通配符检查存在两个问题: 一个 解析器的陈旧缓存或瞬态应答可能会产生误报, 子域名可以有其**独立于**根域的**自身**的通配符条目 (`*.dev.example.com` 捕获所有内容,即使 `*.example.com` 并 没有)。 此版本修复了这两个问题: - **多探测、多解析器多数投票。** 在活动配置文件中的 每个解析器(`balanced`/`thorough` 模式下的 Google/Cloudflare/Quad9)上探测 4 个随机的、基本上 保证未注册的标签。一个 IP 只有在它出现在 **大多数**探测/解析器组合中时,才会被计为通配符签名的一部分 —— 单个偶然的异常应答不能 单独产生(或隐藏)通配符信号。这就是修复 “通配符检测总是返回 0”问题的方法:旧版本使用 单次静态检查,太容易遗漏瞬态通配符 响应,或者过于轻率地将一个 stray IP 称为通配符。 - **按级别检测**,精神上与以前相同:在 排列阶段在已验证的主机下进行更深层的扩展之前,它会 单独探测 `*.` 以获取其自身的通配符签名。发现 具有通配符的主机将保留在结果中(报告中为 `"wildcard": true`),但不会用作进一步排列的基础。 ## 6. DNS 验证信息丰富 `reports/report.json` / `json/10_final_filter_validation.json` 中 每个最终主机的记录现在除了包含解析出的 IP 外,还带有: - 解析记录的 **TTL** - **使用的解析器**(实际应答的配置解析器中的哪一个) - 以毫秒为单位的 **响应时间** - **DNSSEC** —— 尽力检查 DNSSEC 感知重新查询上的 Authenticated Data (AD) 标志 ## 7. 递归枚举 —— 多源扩展 旧版本仅针对每个新发现的主机重新查询 crt.sh。此 版本在每一轮中通过**每个主机多个独立的数据源**进行扩展: ``` developer.example.com | +--> crt.sh (certificate SAN chaining) +--> Wayback Machine (archived URLs under the host) +--> GitHub code search (only if --github-token is set) +--> [opt-in, --active-recursion] JS file links + CSP header hostnames ``` 每个新的主机都会在 `discovery_path` 中记录**它是 在哪个父主机下被发现的** —— 这样你就可以准确追踪 `vpn.internal.developer.example.com` 是如何被找到的(例如 `["example.com", "developer.example.com", "internal.developer.example.com"]`)。 ### 性能:并行化,带有前沿上限(修复长达数小时的卡顿) 此阶段的早期版本完全**顺序**扩展 `(host, source)` 对 —— 一次一个阻塞 HTTP 调用,每次都带有自己的 重试/退避等待。针对一个拥有数百个初始验证 主机的域名(例如拥有 425 个的 `crypto.com`),这意味着 1000+ 次连续调用 访问像 crt.sh 这样的受限免费 API,这确实可能会在单轮中 卡住一个小时甚至更长时间。 通过两种方式修复: 1. **并行扩展。** `(host, source)` 对现在通过有界 线程池(`recursion_threads` —— fast/balanced/thorough 模式下为 10/20/30) 运行,而不是一次一个。特意设置得低于常规的 `--threads` 计数,这样大型域名就不会过度猛烈地冲击免费层级的 API 以至于被封 IP,同时仍然重叠每次调用的 重试/退避等待,而不是逐个主机地支付时间。 2. **前沿上限。** `max_recursion_frontier_per_round`(fast/balanced/thorough 模式下为 100/250/600)限制了在超大域名上的单轮中要扩展多少主机 —— 其余的保持验证状态并留在你的 结果中,只是在本次运行中不会被递归。每次运行覆盖或 禁用: ``` python3 run.py -d crypto.com --profile balanced --recursion-threads 30 python3 run.py -d crypto.com --profile balanced --max-recursion-frontier 0 # disable the cap ``` 或通过 `--config-file`: ``` { "recursion_threads": 25, "max_recursion_frontier_per_round": null } ``` ## 8. 反向 DNS —— 按 ASN / 服务商 / 云分组 `reports/report.json["reverse_dns_groups"]`(以及 `report.md` / `summary` 输出的 “Reverse DNS” 部分)将每个最终主机按以下方式分组: - **ASN** —— 通过 Team Cymru 的基于 DNS 的 whois 服务进行免费、免密钥查询 (`origin.asn.cymru.com` / `asn.cymru.com`;无 API 密钥,无受限 付费依赖) - **云服务商** —— 见下文 每个主机的 PTR + ASN 详细信息也存在于完整报告中每个主机的 `metadata.ptr` / `metadata.asn` 下。 ## 9. 云/CDN 发现 每个验证主机的 CNAME 链(最多 8 跳)都会被追踪并与 已知的服务商指纹进行匹配: CloudFront/S3/ELB -> **AWS**  |  azurefd/azurewebsites/blob.core.windows.net -> **Azure**  |  appspot/run.app/cloudfunctions -> **GCP**  |  cloudflare.net -> **Cloudflare**  |  fastly.net -> **Fastly**  |  akamai*/edgekey -> **Akamai**  |  vercel.app -> **Vercel**  |  netlify.app -> **Netlify**  |  heroku* -> **Heroku**  |  github.io -> **GitHub Pages** 匹配结果按主机显示为 `"cloud": {"provider": "AWS", "service": "CloudFront", "evidence": "...", "cname_chain": [...]}` 并在 `reverse_dns_groups.by_cloud_provider` 中汇总。(它只能 报告 CNAME 链实际揭示的内容 —— 直接指向 裸 IP 且没有 CNAME 的主机将无法通过这种方式进行归因;这是 被动 CNAME 指纹识别的固有局限性,而不是 bug。) ## 10. 恢复与检查点 ``` python3 run.py -d example.com --profile thorough --resume python3 run.py -d example.com --profile thorough --fresh # force a clean re-run ``` pipeline 阶段,按顺序:`01_passive_sources`, `02_wildcard_detection`, `03_initial_dns_validation`, `04_recursive_enumeration`, `05_word_extraction`, `06_permutation_validation`, `07_reverse_dns`(+ ASN), `08_cloud_discovery`, `09_dns_records`, `10_enrichment`, `11_final_filter_validation`。 ## 11. 添加新数据源(插件架构) 无需更改核心 pipeline 代码。在 `subdomain_recon/sources/` 中创建一个新文件: ``` # subdomain_recon/sources/my_source.py from .base import Source, SourceContext class MySource(Source): name = "my_source" confidence = "Medium" def fetch(self, domain, ctx: SourceContext): return [f"host1.{domain}", f"host2.{domain}"] ``` 它会被自动拾取 —— 使用 `python3 run.py --list-plugins` 验证。 ## 12. 运行测试套件 ``` pip install pytest dnspython --break-system-packages pytest tests/ -v ``` 涵盖:主机名标准化、范围/深度检查、配置文件加载 和覆盖、置信度评分,以及完整的 `txt/ + json/ + reports/` 导出布局(包括“自动清理仅移除检查点” 行为)。 ## 13. 数据源健康摘要 每次运行都以每个数据源的明细结束 —— 打印到控制台并 嵌入在 `reports/report.md` 中: ``` Provider Summary alienvault_otx ✓ 114 hosts certspotter ✓ 98 hosts github ✗ Missing key (github) chaos ✗ Missing key (chaos) subfinder ✓ 31 hosts Unique Hosts : 421 Duplicates : 198 Errors : 2 ``` `✗` 区分了**已跳过**(不可用 —— 缺少密钥或 CLI 二进制文件, 已明确命名)和**错误**(真正的失败 —— 非 2xx HTTP 状态码、 连接失败、非零 CLI 退出码或超时 —— 并在消息中附带实际 原因;参见上面的“让静默失败变得可见”更新日志 条目)。一个确实发现零主机的干净运行仍然正确地 显示为 `ok, 0 hosts` —— 这种区别正是修复的核心点。 ### 日志标志 ``` python3 run.py -d example.com --quiet # console: warnings/errors + final summary only python3 run.py -d example.com --verbose # console: DEBUG level python3 run.py -d example.com --debug # console: DEBUG + full tracebacks for source failures ``` 无论控制台详细程度如何,完整的 DEBUG 级别日志始终会 写入 `output//logs/run_.log` —— `--quiet` 只 影响屏幕上滚动的信息,而不影响保留供以后调试的信息。 ## 14. 置信度引擎 完整的公式和 JSON `confidence_breakdown` 结构在 `ARCHITECTURE.md` 中。快速版本 —— 累加分数,可通过 `--config-file` 配置: ``` { "confidence_weights": { "cloud": 20, "permutation_penalty": -25 } } ``` 默认值:2+ 个数据源 +20,DNS 有效 +20,递归 +15,云 +10,GitHub +15,crt.sh +10,仅排列 -15。分数限制在 `[0, 100]`;高 ## 15. SQLite 情报数据库 + 差异模式 每次运行都存储在 `output/intel.sqlite3` 中(与 API/DNS `cache.sqlite3` 分开) —— 运行历史、跨运行的每个主机历史、跨运行 重复检测和主机名搜索都是针对它进行的普通 SQL 查询 (见 `subdomain_recon/intel_db.py`)。如果你不需要,使用 `--no-intel-db` 跳过此步骤。 ``` # 与特定的已保存报告进行 diff python3 run.py -d example.com --diff /path/to/old/reports/report.json # 与 intel.sqlite3 中该域名最近一次的先前运行进行 diff python3 run.py -d example.com --diff auto ``` 写入 `reports/diff.json` + `reports/diff.md` 并记录 NEW/REMOVED 摘要。 ## 16. 恢复 + Ctrl+C ``` python3 run.py -d example.com --profile thorough --resume # the ONLY way to skip the auto-wipe python3 run.py -d example.com --profile thorough # every other invocation auto-wipes first (see section 2) ``` `--fresh` 仍然会被解析(这样旧脚本就不会中断),但现在是一个空操作 —— 只要未传递 `--resume`,清除就是默认行为。 在运行过程中按下 Ctrl+C 不再只是静默退出 —— 它会准确记录 哪些阶段已完成/检查点,并打印精确的 `--resume` 命令以继续。恢复粒度是按阶段的(参见 `ARCHITECTURE.md` 了解为什么未实现阶段中的恢复)。在批量模式(`-dL`)下,Ctrl+C 会在当前域名之后停止整个批次;已完成的域名 保留其结果,被中断的域名可以单独恢复。 ## 17. 开发者工具 ``` pip install -r requirements-dev.txt # pytest, black, ruff, mypy, pre-commit pre-commit install # run lint+format+tests before every commit black . ruff check . mypy . pytest tests/ -v ``` CI(`.github/workflows/tests.yml`):lint(`ruff` + `black --check`)-> 测试 矩阵(Python 3.11, 3.12)-> 包构建,每一个都作为下一个的关卡。 ## 18. 故障排除 - **`pip install ... --break-system-packages` 提示 “no such option”** —— 你使用的是较旧版本的 pip;要么升级 pip,要么去掉该标志并使用 虚拟环境。 - **未安装 dnspython** —— 基本的 A 记录解析回退到 Python 内置的 `socket` 模块,但 AAAA/CNAME/MX/TXT/NS/PTR, TTL, DNSSEC 和 ASN 查询都需要它:`pip install dnspython --break-system-packages`。 - **`subfinder` / `assetfinder` / `findomain` / `sublist3r` 显示 “no (missing key/binary)”** —— 这些是可选的外部 CLI 工具;安装它们并 确保它们在 `PATH` 中,或者忽略它们。 - **某个数据源在这里显示的主机少于(或为 0)手动单独运行它** —— 首先检查数据源健康摘要和 `reports/report.json` 的 `provider_health` 部分:每当这确实是 实际发生的情况时,它现在会显示带有真实 原因的 `error`(超时、退出码 + stderr、HTTP 状态),而不是令人误解的 `ok, 0 hosts`(参见上面的修复 更新日志)。如果它确实显示没有错误的 `ok, 0 hosts`,那么 两次运行可能只是遇到了不同的上游条件(速率限制、 瞬态网络问题,或独立工具自身的单独数据源 配置/缓存) —— 重新运行并比较,或者在 此工具旁边单独运行该数据源以直接比较。 - **一次运行多个域名比预期慢/不稳定** —— 如果你同时从同一台机器启动多个单独的 `python3 run.py -d ...` 进程 (每个域名一个),它们都会 同时竞争相同的免费/受限 API 和相同的出站 连接池,这可能会全面触发速率限制或 超时。请改用 `-dL/--domain-list`(第 2 节) —— 它在单个进程内一次扫描一个域名,因此你 可以获得相同的结果,而不会造成自找的并发负载。 - **空的 `txt/final_hosts.txt`** —— 检查 `output/logs/run_*.log` 和 `reports/report.json["metrics"]` 内部的 `errors` 列表 —— 最常见的原因是没有 数据源可达(无网络 / 无密钥 / 无 CLI 工具),或者 该域名具有激进的通配符 DNS 过滤掉了每个候选者(检查 `report.json["wildcard_ips"]`)。 - **缓存似乎过时** —— 通过 `--config-file` 降低 `cache_ttl_seconds`,或 删除 `output/cache.sqlite3`。 ## LICENSE MIT —— 见 `LICENSE`。此工具仅供授权的安全测试 和研究使用。仅对你拥有或具有 明确书面测试许可的域名和系统使用它。作者对 滥用不承担任何责任。
标签:GitHub, Python, Python安全, 子域名枚举, 实时处理, 无后门, 无服务器架构, 系统安全, 资产测绘, 逆向工具