sazzadul007/mr-cool-subdomain-recon
GitHub: sazzadul007/mr-cool-subdomain-recon
一款被动与主动相结合的子域名侦察工具,通过多源 OSINT 数据聚合与递归枚举实现全面的资产发现与 DNS 情报收集。
Stars: 0 | Forks: 0
# sazzad007 -- 被动 + 主动子域名侦察
通过 **21 个免费/需密钥的来源**进行被动子域名发现,智能多解析器
通配符过滤,**多源递归枚举**(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/` 输出目录结构 —— 支持断点续传、缓存、各阶段指标
以及自动发现的插件架构。
有关 pipeline 图表、完整的 JSON schema、插件 SDK
契约和置信度引擎公式,请参阅 `ARCHITECTURE.md`。
### 快速开始(安装)
```
git clone
cd # 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
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 + 作者/版本/引擎/模式/状态面板) | 完成 |
| `--minimal` 输出模式(仅保留 `txt/final_hosts.txt` + `reports/report.json`,删除其他所有文件) | 完成 |
| 每次运行自动刷新输出(第二次运行绝不会与第一次运行的残留文件混杂;`--resume` 是唯一的退出选项) | 完成 |
| 批处理模式:`-dL/--domain-list example.txt` 可在一个命令中扫描 2 个及以上域名,每个域名输出到各自的子文件夹中 | 完成 |
### 最近一次全代码审查修复的问题
从头到尾检查了整个代码库,并修复了发现的所有问题:
- **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 密钥是否在任何地方被记录/打印
(并没有 —— 仅作为不透明的 dict 值传递),每个模块中未使用的导入
(启发式 + 手动检查 —— 已清理),裸露的
`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 请求,因此它是可选的且默认关闭。
## 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
c99 High no (missing key/binary)
censys High no (missing key/binary)
certdb Medium 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`。
需密钥来源(免费注册):
| 来源 | 免费注册地址 | CLI 标志 |
|---|---|---|
| GitHub | github.com(个人访问令牌) | `--github-token` |
| Censys | search.censys.io(社区层) | `--censys-id` + `--censys-secret`(两者均需提供) |
| VirusTotal | virustotal.com | `--virustotal-key` |
| urlscan.io | urlscan.io(可选,可提高速率限制) | `--urlscan-key` |
| CertSpotter | sslmate.com(可选,可提高速率限制) | `--certspotter-key` |
| FullHunt | fullhunt.io | `--fullhunt-key` |
| Chaos | chaos.projectdiscovery.io(免费,基于资格) | `--chaos-key` |
你要求的付费/标准不明确的来源,以相同的插件方式接入:
| 来源 | 说明 | CLI 标志 |
|---|---|---|
| C99 | **付费的** c99.nl 子域名查找器 API —— 需要你自己的付费密钥 | `--c99-key` |
| CertDB | 目前不存在单一标准化的公共 "CertDB" API —— 以需密钥的**存根**形式提供 (`subdomain_recon/sources/certdb.py`),指向占位符 URL;请修改 `BASE_URL` 和响应解析以匹配你所指的具体服务,或者如果不需要可以直接删除该文件 | `--certdb-key` |
特意未包含的来源(仅限付费,无适用的免费层):Shodan、
BinaryEdge。特意未包含的来源及其原因(已停止维护、
违反 ToS 的抓取,或已通过其他方式覆盖的独立工具)与之前的 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 —— 每行一个 domain,空行和 #注释会被跳过
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
report.csv
report.html # dark-themed, sortable, filterable
report.md
metadata.json # first_seen/last_seen/sources/discovery_path per host
cache.sqlite3 # API + DNS cache (persists across runs)
checkpoints/ # per-stage checkpoint files, auto-deleted after a
# successful run (see "Auto-cleanup" below)
logs/
```
**`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 | 1 | 系统默认
balanced | 60 | 5 | 3,000 | 6小时 | 8.8.8.8, 1.1.1.1
thorough | 100 | 8 | 20,000 | 24小时 | 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
```
## 5. 更智能的通配符检测
简单的单次探测通配符检查存在两个问题: 某个解析器的
缓存过期或瞬态应答可能会产生误报,并且 子域名可以有
**自己**独立的通配符条目,而不受根域的影响
(例如 `*.dev.example.com` 会匹配所有内容,尽管 `*.example.com` 并不会)。
此版本修复了这两个问题:
- **多探测、多解析器多数投票法。** 在活动配置文件中的
每个解析器上探测 4 个随机的、几乎可以保证未注册的标签(在 `balanced`/`thorough` 模式下使用 Google/Cloudflare/Quad9)。如果某个 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"]`)。
## 8. 反向 DNS —— 按 ASN / 提供商 / 云分组
`reports/report.json["reverse_dns_groups"]`(以及 `report.md` / `summary` 输出的“反向 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 二进制文件,
已明确指出)和**错误**(该来源的 `fetch()` 实际抛出了异常)。有关一个已知的限制,请参阅 `ARCHITECTURE.md`(受速率限制/认证失败的 HTTP 响应目前显示为“ok, 0 hosts”,而不是明确的错误,因为来源尚未将状态码报告回 pipeline)。
## 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 中该 domain 最近一次的先前运行结果进行 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` 中,或者直接忽略。
- **c99 / certdb 从未运行** —— 两者都需要你自行提供密钥(c99 是
付费 API;certdb 是一个存根 —— 见第 1 节)。
- **`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`。
## 许可证
MIT —— 见 `LICENSE`。本工具仅供授权的安全测试
和研究使用。仅对你拥有或获得明确书面测试许可的域名和系统使用此工具。作者不对
任何误用行为承担责任。
标签:ESC4, GitHub, OSINT, Python, 子域名枚举, 安全侦察, 实时处理, 无后门, 无服务器架构, 系统安全, 逆向工具