关于 find-hidden-subdomains
find-hidden-subdomains 是面向安全与资产调查的子域名发现技能,利用证书透明度日志等被动来源查找组织相关主机。它区分历史记录与当前可解析主机,并提醒排除共享证书和多租户环境带来的误报。
主要功能
- 01查询证书透明度日志
- 02按组织名称查找域名
- 03检查证书 SAN 与历史记录
- 04结合被动 DNS 和解析结果
- 05识别共享证书导致的误报
- 06按来源与状态记录主机
适用场景
- 01为已知域名发现历史子域名
- 02查找组织名下未列出的域名
- 03筛选仍可解析的候选主机
- 04评估通配符证书与共享托管影响
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ useosint/ skills --skill find-hidden-subdomains安装后在 Claude Code 中输入/find-hidden-subdomains确认已加载。
附带文件reference/name-pattern-triage.mdreference/subdomain-sources.md
详细介绍
查找隐藏子域名
组织遗忘的主机最值得查找,而其中大多数在有人申请 TLS 证书时就已留下记录。证书透明度(CT)将这些记录变成可搜索、永久且有历史记录的索引,而且免费、完全被动。初学者常犯的错误,是把 CT 查询结果当作在线主机:查出的多数主机无法解析,但这也是信息,并非噪声。
先查哪个来源
| 你掌握的信息 | 从这里开始 | 原因 |
|---|---|---|
| 一个顶级域名 | crt.sh 通配符查询 | 免费覆盖范围最广,包含早已失效的名称 |
| 一个使用通配符证书的域名 | 被动 DNS,然后查档案 | CT 只会显示 *.example.com |
| 对命名规则的猜测 | 先用 CT 了解规则,再用字典 | 先了解规律,再进行暴力枚举 |
| 组织名称,而非域名 | 按证书主题中的组织名称搜索 | 找出你不知道该组织拥有的域名 |
| 已有的证书 | 先查 SAN,再查序列号和颁发者 | SAN 可找到同组域名;序列号可在其他地方找到完全相同的证书 |
| 只需要当前在线的主机 | 解析候选列表 | CT 天生记录历史;DNS 才是判断在线状态的依据 |
CT 的实际工作原理
CA 会将其签发的每张证书提交到仅可追加、可通过密码学验证的公共日志中。日志会返回签名证书时间戳(SCT),而主流浏览器会拒绝信任不包含来自合格日志的 SCT 的公开信任证书。因此,参与并非自愿:如果证书能在浏览器中使用,它就会出现在日志中。
以下三点与你息息相关:
- 记录不会被删除。 日志仅可追加。五年前出现在证书中的主机名,即使对应的主机已不存在,仍会留在日志中。
- 你会看到预证书和正式证书。 CA 会先记录预证书,再记录最终证书,因此大多数名称至少会出现两次。请去重。
- 日志只涵盖公开信任的证书。 私有/内部 CA、自签名证书或 Cloudflare 源站证书都不会进入日志。CT 完全无法发现这些主机。
crt.sh
网页界面使用 ?q=,其中 % 是通配符;output=json 可返回机器可读的结果。
# every name ever seen in a cert covering example.com or a subdomain
curl -s 'https://crt.sh/?q=%25.example.com&output=json' \
| jq -r '.[].name_value' | sed 's/^\*\.//' | sort -u
# skip expired certs when you want a bias toward current infrastructure
curl -s 'https://crt.sh/?q=%25.example.com&output=json&exclude=expired' | jq -r '.[].name_value'
# an identity search on an organization string, which finds unknown domains
curl -s 'https://crt.sh/?q=Example+Corporation&output=json' | jq -r '.[].name_value'
q 参数用于身份搜索:它会匹配域名,也会匹配主题字段(例如组织名称),因此可以找到说明中未提及的域名。
有用的 JSON 字段:name_value(证书上的所有名称,以换行符分隔)、common_name、issuer_name、not_before/not_after、serial_number、entry_timestamp 和 id(打开 https://crt.sh/?id=<id> 阅读证书)。
crt.sh 还通过 Postgres 以只读方式提供数据库访问:主机为 crt.sh,端口为 5432,用户为 guest,数据库为 certwatch。你可以用它直接针对证书索引编写 SQL,而不必翻页查询 JSON。这是一项共享的免费服务:请限制查询范围;如果频繁发送大量查询,连接可能会被中断。
其他 CT 前端及其覆盖范围和访问方式,请参阅 reference/subdomain-sources.md。
SAN 字段才是关键
浏览器会忽略通用名称;真正列出所涵盖主机名的是 subjectAltName 扩展。把它看作一份声明,反映了同一个团队共同部署了哪些内容:
- 包含少量相关名称的证书是有意分组的——这些主机属于同一项服务,而且很可能由同一位管理员管理。
- 包含数十个互不相关名称的证书是托管服务提供商或 CDN 的捆绑证书。**这些名称属于其他客户,不是目标的资产。**这是基于 CT 的枚举中最大的误报来源。
- 一张证书上包含不同可注册域名中的名称,这是有价值的发现:这意味着同一运营方同时管理这些域名,可以揭示收购、品牌重塑和未公开的姊妹品牌。得出结论前请先核实——参见上面的捆绑陷阱。
- 内部名称经常在此泄露:
jira、owa、vpn、*.corp.example.com、带有机架或数据中心代码的主机名,以及从未公开发布的产品代号。
通配符会隐藏信息,而非揭示信息
*.example.com 涵盖所有子域名,但不会列出其中任何一个。组织改用通配符后(通常还会配合 DNS-01 ACME 自动化),从那时起实际上就从 CT 中消失了。看到通配符时:
- 挖掘通配符启用之前的 CT 数据,当时每台主机都有自己的证书。
- 转向被动 DNS,它记录的是解析结果,而不是证书。
- 检查存档和搜索索引中的主机名(
read-deleted-pages、google-like-a-spy)。 - 查找因技术原因必须继续使用独立证书的主机:通配符无法涵盖的更深层级标签(
a.b.example.com需要自己的证书),以及任何位于不同顶级域名下的主机。
组合数据源,然后解析
CT 提供历史记录。被动 DNS 提供观测到的实际情况。词表则提供无人公开发布的名称。三种来源都要用,并按来源标记结果,因为你能赋予名称的置信度取决于它的来源。
subfinder -d example.com -all -silent -o passive.txt # aggregates many passive sources
amass enum -passive -d example.com # different source mix, slower
dnsx -l passive.txt -a -resp -silent # resolve candidates to A records
解析会把候选名称分成三类:解析到 IP 地址、解析到 CNAME(查看目标——它会显示供应商名称,而悬空的 CNAME 是可报告的接管候选项),或者完全无法解析。失效名称仍然是发现项:它们能标示基础设施的年代、揭示命名惯例,有时还会在之后重新解析。
**在信任任何暴力枚举结果之前,先检测通配符 DNS。**解析一个不可能存在的随机名称,例如 zzq7x-nonexistent.example.com。如果它能得到响应,说明该区域会解析所有名称,你的整份暴力枚举列表都是误报。
明确划分界限:查询 CT、被动 DNS、搜索引擎和存档都不会接触目标。通过公共递归解析器解析候选名称基本不会被察觉,但确实会产生查询。使用词表进行暴力枚举会产生大量 DNS 流量,目标的 DNS 提供商可以看到这些流量,而且有时会对其限速或拦截。使用 httpx 之类的工具对结果进行 HTTP 探测则属于主动操作——你正在连接目标的服务器。在范围说明中标明暴力枚举和探测;如果本次任务仅限被动操作,则跳过这些步骤。
名称模式意味着什么
不要把所有发现的主机一视同仁。dev、staging、uat、vpn、legacy、old 和管理面板,与 www 相比,风险和后续处理方式都大不相同。分类表见
reference/name-pattern-triage.md。
容易出错的地方
- 捆绑证书和多租户证书。 共享主机和 CDN 证书会将互不相关的客户放在同一张证书上。采用证书上的其他名称之前,务必确认它们是否可能属于你的目标。
- CT 不是资产清单。 它记录的是证书申请。使用内部 CA、自签证书、源站证书或纯 HTTP 的主机不会出现在其中。绝不要把根据 CT 得出的列表报告为完整清单。
- 名称比主机存续更久。 大多数 CT 历史名称都已失效。一份包含 400 个子域名但未经解析验证的列表,只是 400 条未经核实的声明。
- 名称比所有权存续更久。 域名曾属于前任所有者期间为某个主机名签发的证书,仍会出现在当前所有者的查询结果中。请通过
who-owns-this-domain,结合域名注册和转让历史,核对not_before。 - 指向第三方的 CNAME 不属于目标的资产。 目标拥有的主机名指向 SaaS 租户,体现的是目标的关联关系,而非其基础设施。不要把供应商的暴露情况视为目标的暴露情况。
- 聚合器的结果各不相同,而且不会明确说明。 每个工具查询的来源集合都不同;免费版会截断结果,却不作提示。两个工具返回相同的 50 个名称,可能都读取自同一个来源。
- 蓄意投毒。 任何人都可以在看起来像目标的域名上,为自己控制的名称申请证书。错拼抢注域名会出现在 CT 搜索结果中,看起来像是目标自己的主机。请逐字符核对可注册域名。
置信度分级
- 已确认资产 — 名称可解析,且属于已验证注册信息的域名;其基础设施也与目标的其他主机一致(相同的 ASN、证书颁发者、命名惯例)。
- 可能的资产 — 位于已验证目标域名下、目前无法解析的 CT 名称,或解析到供应商共享平台的名称。名称确实存在,但当前状态尚未证实。
- 未确认 — 与无关客户捆绑在同一张证书上的名称、通配符 DNS 区域中的暴力枚举命中项、位于不同可注册域名且没有佐证关联的名称,或尚未查看底层证书或 DNS 答案的聚合器结果。
对每台主机记录:名称的来源、证书 id 或被动 DNS 来源、not_before 日期,以及带时间戳的解析结果。
示例
目标:example-health.test,范围仅限被动方式。
crt.sh 对 %25.example-health.test 的查询返回 61 个不重复名称。对预证书/证书对去重后,剩下 38 个。其中有三个立即值得关注:
vpn-uat.example-health.test、jira.internal.example-health.test 和
billing-legacy.example-health.test。
一张证书包含 44 个名称,涉及九家互不相关的公司——这是托管服务提供商的捆绑证书。剔除其中不属于目标的 43 个名称。若不这样做,就会误入死胡同,导致报告中的发现数量膨胀,远超实际发现。
解析这 38 个名称:其中 12 个有响应。jira.internal 无法通过公开 DNS 解析,但它出现在证书中,证实了内部命名惯例和一个 Jira 实例——值得记录,尽管没有可供检查的主机。vpn-uat 解析到某设备供应商的网段,应转交给 find-exposed-servers。
使用某张证书上的组织名称进行身份搜索,找到两张签发给 examplehealth-group.test 的证书。这是简介中无人提及的域名。通过 who-owns-this-domain 查询 WHOIS,发现注册机构相同。这一线索扩展了此次评估的范围。
分级:12 台可解析主机为已确认;jira.internal 为可能的资产(名称确实存在,但无法通过公开网络访问);兄弟域名为可能的资产,有待企业备案文件佐证。
跳转
| 新选择器 | 跳转至 |
|---|---|
| 实时主机名及其 IP | find-exposed-servers |
| 同级域名和收购的域名 | who-owns-this-domain、who-really-owns-it |
| 证书主题中的组织名称 | x-ray-a-company |
| 含有历史内容的失效主机名 | read-deleted-pages |
| 开发/暂存主机名、类似仓库的名称 | secrets-in-git-history |
| 新发现主机上已编入索引的文件 | google-like-a-spy |
| 需要梳理的大量主机/域名/IP 集合 | graph-the-network |
法律和服务条款说明
读取 CT 日志和被动 DNS 数据本质上是公开行为:这些数据本来就是供人读取的。但有两项实际限制。首先,crt.sh 这类免费服务属于共享基础设施——大量自动查询会导致你被封禁,也是不礼貌的行为;请限制查询范围并缓存结果。其次,DNS 暴力枚举和 HTTP 探测会向目标发送流量,根据流量大小和司法管辖区的不同,可能被认定为未经授权的活动;请将此类操作限制在书面授权范围内,详见 ../../ETHICS.md。发现悬空 CNAME 或暴露的暂存主机后,你有义务报告,而不是进行测试。