第6章 阶段5:DNS 解析与数据清洗
本篇定位:子域名挖掘流程的第五阶段。前四步——被动、主动、进阶——收集了一批"原始子域名列表"。这个列表里有假阳性、重复、过时数据。清洗阶段把这些原始数据变成可信的子域名 + IP 列表,给下一步 HTTP 探测用。
阅读建议:如果你做过批量 DNS 解析,可以跳到 6.2 通配符检测看过滤方法。如果是新手,按顺序读——6.1 到 6.4 是清洗的四道工序,缺一不可。
6.0 方法论框架
清洗阶段在全局流程里的位置:
阶段4:进阶发现(新增子域名) ──→ 【阶段5:DNS 清洗】 ──→ 阶段6:HTTP 探测与价值评估 │ ├── 多 DNS 轮询解析(避免单一来源偏差) ├── 通配符检测与过滤(去除假阳性) ├── CNAME 链跟踪(识别架构和风险) └── 输入输出校验(防止丢包)什么是清洗
清洗(Data Cleaning),指的是把前四步收集的"原始子域名列表"做验证和过滤,变成"可信的子域名 + IP 列表"。清洗不做新发现——它只验证已有数据。
为什么在 HTTP 前面
| 原因 | 说明 |
|---|---|
| 假阳性浪费配额 | 通配符 DNS 制造的假子域,做 HTTP 探测全返回 404——浪费请求 |
| 过时数据浪费时间 | 已下线的子域做 HTTP 探测会超时——浪费时间 |
| 重复数据冗余 | 同一子域从多个方法发现,不做去重会重复探测 |
| 不可达数据干扰 | 有些子域解析到内网 IP 或失效 IP——HTTP 探测打不通 |
原始数据的四类问题
| 问题类型 | 来源 | 后果 |
|---|---|---|
| 假阳性 | 通配符 DNS、搜索引擎误收录 | 不存在的子域被误判为存在 |
| 重复 | 多个方法发现同一子域 | 重复处理浪费时间 |
| 过时 | 历史数据、CT Logs 旧证书 | 子域已下线,解析到旧 IP 或 NXDOMAIN |
| 不可达 | 内网 IP、失效 IP | HTTP 探测打不通 |
四个环节概览
关键认知:清洗不是发现新子域,是把已有数据变可信。这一步的价值是"省成本"——过滤掉假阳性和过时数据,让下一步 HTTP 探测只处理真正存活的子域。跳过清洗直接做 HTTP 探测,会浪费大量请求配额在不存在或已下线的子域上。
6.1 多 DNS 轮询解析
前置知识
DNS 缓存机制回顾
基础知识02讲过 DNS 解析流程——查询从递归 DNS 服务器出发,逐级查询。这里补充缓存对批量查询的影响:DNS 服务器会把查询结果缓存一段时间(TTL)。缓存对单次查询是好事——下次查同一个域名直接返回缓存。但对批量查询是坏事——如果第一次查dev.example.com返回了 NXDOMAIN(因为那时网络抖动),这个 NXDOMAIN 会被缓存——后面再查还是 NXDOMAIN,即使域名已经恢复。
公共 DNS 的差异
基础知识02讲过本地 DNS 和公共 DNS。这里补充:不同公共 DNS 的解析结果可能不同。原因:缓存状态不同(A 服务器刚缓存了旧结果,B 服务器没有)、EDNS 子网支持不同(部分公共 DNS 会根据用户地理位置返回不同 IP)、权威 DNS 负载均衡(权威 DNS 服务器本身有多个,不同公共 DNS 可能查到不同的权威服务器)。所以只查一个公共 DNS,可能拿到偏差结果。
UDP vs TCP 回顾
基础知识02讲过 DNS 用 UDP 53 端口查询。这里补充批量查询时的场景:UDP 包有 512 字节限制——CNAME 链长或响应记录多时,UDP 装不下,DNS 服务器会截断响应并设置 TC(Truncation)标志位。客户端看到 TC 标志后,要用 TCP 53 重新查一次拿完整结果。批量解析时,大量 CNAME 链会导致 UDP 频繁截断——如果只查 UDP,会漏掉被截断的结果。
是什么
用多个公共 DNS 服务器轮询解析子域名列表,避免单一 DNS 服务器的缓存偏差、限速和单点故障。
为什么
| 问题 | 单一 DNS 的问题 | 多 DNS 轮询解决 |
|---|---|---|
| 缓存偏差 | 单一 DNS 缓存了旧结果 | 多个 DNS 缓存状态不同,交叉验证 |
| 限速 | 单一 DNS 限速阈值低 | 分散到多个 DNS,单个不被限 |
| 单点故障 | 单一 DNS 服务故障 | 多 DNS 容错 |
| 地理偏差 | 单一 DNS 的地理视角固定 | 多 DNS(不同厂商)视角交叉 |
怎么做
第一步:配置多个公共 DNS
| DNS 服务器 | IP | 特点 |
|---|---|---|
| Cloudflare | 1.1.1.1 | 速度快、支持 EDNS |
8.8.8.8 | 全球覆盖、稳定 | |
| Quad9 | 9.9.9.9 | 安全过滤恶意域名 |
| 阿里 DNS | 223.5.5.5 | 国内目标解析准 |
| 腾讯 DNS | 119.29.29.29 | 国内目标解析准 |
第二步:轮询查询
对每个子域名,轮询用不同 DNS 服务器查询:
| 查询次序 | DNS 服务器 | 子域名 |
|---|---|---|
| 第 1 次 | 1.1.1.1 | api.example.com |
| 第 2 次 | 8.8.8.8 | dev.example.com |
| 第 3 次 | 9.9.9.9 | staging.example.com |
| 第 4 次 | 223.5.5.5 | admin.example.com |
第三步:结果对比
对同一子域名,如果多个 DNS 返回不同结果,标注并重查:
| 情况 | 处理 |
|---|---|
| 多 DNS 都返回同一 IP | 可信,保留 |
| 多 DNS 返回不同 IP | 负载均衡或 CDN 调度,全部保留 |
| 部分 DNS 返回 NXDOMAIN | 可能是缓存偏差,换 DNS 重查 |
| 全部 DNS 返回 NXDOMAIN | 确认不存在,丢弃 |
第四步:超时降级
UDP 查询超时后,切 TCP 重新查:
| 情况 | 处理 |
|---|---|
| UDP 超时 | 切 TCP 重查 |
| TCP 也超时 | 标注异常,稍后重试 |
| 返回 TC 标志 | 切 TCP 拿完整结果 |
技巧
| 技巧 | 做法 | 价值 |
|---|---|---|
| DNS 服务器选择 | 国外目标用 Cloudflare+Google,国内目标加阿里+腾讯 | 地理视角更全 |
| 权重分配 | 速度快的 DNS 权重高,慢的权重低 | 提高整体速度 |
| 异常监控 | 实时统计每个 DNS 的成功率和延迟 | 发现哪个 DNS 被限速 |
| EDNS 支持 | 优先用支持 EDNS 的 DNS | 拿到更准确的解析结果 |
注意事项
| 事项 | 说明 |
|---|---|
| 公共 DNS 也有缓存 | TTL 内会返回缓存结果,不是实时 |
| EDNS 支持 | 部分公共 DNS 不支持 EDNS,地理解析不准 |
| 国内 DNS 解析国内域名更准 | 国内目标用阿里/腾讯 DNS,结果更全 |
| 不查目标权威 DNS | 查权威 DNS = 直接接触目标,有风险 |
6.2 通配符检测与过滤
前置知识
通配符 DNS 回顾
基础知识04讲过通配符 DNS(Wildcard DNS)——在 DNS 配置里加一条*.example.com的记录,让所有未明确配置的子域都解析到同一个 IP。这意味着你查randomstring123.example.com,即使这个子域从未配置,也会返回 IP——返回 NOERROR 而不是 NXDOMAIN。
随机子域验证概念
检测通配符的方法:构造一个不可能存在的随机子域名(如xqzwkpvn123.example.com——这串随机字符不可能被管理员配置过),查它的 DNS。如果这个随机子域也解析成功,说明目标启用了通配符 DNS——字典爆破返回的所有 NOERROR 结果都是假阳性。
关键认知:通配符 DNS 是主动探测最大的干扰因素。如果没有通配符,NOERROR = 子域存在,NXDOMAIN = 子域不存在,判断很简单。有了通配符,NOERROR 不代表子域真实存在——所有子域都返回 NOERROR。检测通配符是主动探测后必须做的第一件事。
是什么
检测目标是否启用了通配符 DNS,过滤掉因通配符产生的假阳性子域。
为什么
通配符 DNS 让所有子域返回 NOERROR——字典爆破和排列扫描的结果全是假阳性。如果不过滤,HTTP 探测阶段会对着一批不存在的子域发请求,全返回 404 或超时——浪费请求配额和时间。
怎么做
第一步:随机子域探测
构造多个不可能存在的随机子域名,查 DNS:
| 随机子域 | 查询 |
|---|---|
xqzwkpvn123.example.com | 查 A 记录 |
randomtest456789.example.com | 查 A 记录 |
aaaa9999test.example.com | 查 A 记录 |
第二步:判断通配符
| 结果 | 判断 |
|---|---|
| 随机子域返回 NXDOMAIN | 没有通配符,NOERROR = 子域真实存在 |
| 随机子域返回 NOERROR + IP | 启用了通配符,所有 NOERROR 都可能是假阳性 |
| 部分随机子域返回 IP | 可能有部分通配符(如只对某些路径通配) |
第三步:过滤策略
确认启用通配符后,过滤掉命中通配符 IP 的子域:
| 子域 | 解析 IP | 通配符 IP | 处理 |
|---|---|---|---|
api.example.com | 1.2.3.4 | 1.2.3.4 | 丢弃(命中通配符) |
dev.example.com | 1.2.3.4 | 1.2.3.4 | 丢弃(命中通配符) |
www.example.com | 5.6.7.8 | 1.2.3.4 | 保留(IP 不同) |
mail.example.com | 9.10.11.12 | 1.2.3.4 | 保留(IP 不同) |
第四步:例外保留
不是所有命中通配符 IP 的子域都是假阳性——有些子域碰巧和通配符 IP 一样,但是真实存在的(管理员手动配置了dev.example.com → 1.2.3.4,通配符也指向1.2.3.4)。要保留的例外:
| 例外类型 | 怎么识别 |
|---|---|
| CT Logs 里有证书的 | 申请了证书 = 管理员配置过 = 真实子域 |
| 搜索引擎收录的 | 被收录 = 有真实页面 |
| 多 DNS 返回不同 IP | 不同 DNS 返回不同 IP = 有明确配置 |
技巧
| 技巧 | 做法 | 价值 |
|---|---|---|
| 多随机子域交叉 | 用 3-5 个随机子域都试 | 避免单个随机子域碰巧有记录 |
| 通配符 IP 记录 | 记下通配符返回的 IP | 过滤时对比——命中通配符 IP 的丢弃 |
| 部分过滤 | 只过滤命中通配符 IP 的,不删除全部 NOERROR | 避免误删真实子域 |
| 分级保留 | 多源子域优先保留,单源子域可过滤 | 多源子域更可信 |
注意事项
| 事项 | 说明 |
|---|---|
| 通配符+真实子域共存 | 通配符覆盖所有子域,但管理员可能给某些子域单独配了记录 |
| 通配符只覆盖一层 | *.example.com不覆盖api.dev.example.com(两层) |
| 过滤过度 | 只因命中通配符 IP 就删除,可能漏掉真实子域——要用例外保留 |
| 通配符 IP 可能多个 | 通配符可能指向多个 IP(负载均衡)——要全部记录 |
6.3 CNAME 链跟踪
前置知识
CNAME 记录回顾
基础知识04讲过 CNAME(Canonical Name,规范名称)记录——把一个域名别名指向另一个域名。如blog.example.com的 CNAME 指向example.github.io,访问blog.example.com实际访问的是example.github.io。
CNAME 链概念
CNAME 链是指一个子域的 CNAME 指向另一个域名,那个域名可能又指向下一个——形成链条:blog.example.com→example.github.io→github.map.fastly.net→151.101.1.1。链条的终点是 A 记录(IP 地址)。
CNAME 与第三方服务
当 CNAME 指向第三方平台(如github.io、herokuapp.com、s3.amazonaws.com),意味着这个子域托管在第三方平台上。如果目标在第三方平台上的资源被删除(如 GitHub Pages 项目删除),但 DNS 的 CNAME 记录还在——这个子域就指向了一个不存在的第三方资源。这种"悬挂 DNS"(Dangling DNS)可能被攻击者接管——在第三方平台上重新注册这个资源,就能控制这个子域。
关键认知:CNAME 链不只暴露服务架构,还暴露接管风险。指向已失效第三方资源的 CNAME 是高危信号——意味着这个子域可能被接管。识别和标注这种风险是 CNAME 链跟踪的重要价值。
是什么
追踪子域名的 CNAME 链,识别 CDN、第三方服务、接管风险。
为什么
| 价值 | 说明 |
|---|---|
| 识别 CDN | CNAME 指向 CDN 域名(如*.cloudfront.net)→ 这个 IP 是 CDN 的,不是目标的 |
| 识别第三方托管 | CNAME 指向第三方平台(如github.io)→ 子域托管在第三方 |
| 识别接管风险 | CNAME 指向已失效的第三方资源 → 可能被接管 |
| 发现关联域名 | CNAME 链的中间节点可能是新根域名(进阶发现用) |
怎么做
第一步:查 CNAME 记录
对每个子域名查 CNAME 记录:
| 子域 | CNAME 指向 | 类型 |
|---|---|---|
blog.example.com | example.github.io | 第三方托管 |
cdn.example.com | d123.cloudfront.net | CDN |
api.example.com | 无 CNAME,直接 A 记录 | 自有服务器 |
old.example.com | deleted.herokuapp.com | 悬挂 DNS |
第二步:追踪链条
顺着 CNAME 链一直追到终点(A 记录):
blog.example.com → example.github.io(CNAME) → github.map.fastly.net(CNAME) → 151.101.1.1(A 记录,终点)第三步:识别终点类型
| 终点类型 | 识别方式 | 处理 |
|---|---|---|
| 自有 IP | IP 归属目标 ASN | 保留,做 HTTP 探测 |
| CDN IP | IP 归属 CDN ASN(Cloudflare、Akamai) | 标注 CDN,HTTP 探测时注意 |
| 第三方平台 | CNAME 指向第三方域名 | 标注托管平台 |
| 已失效 | CNAME 终点不存在(NXDOMAIN) | 标注悬挂 DNS + 接管风险 |
第四步:标注接管风险
指向已失效第三方资源的 CNAME,标注接管风险:
| 子域 | CNAME 指向 | 终点状态 | 风险 |
|---|---|---|---|
old.example.com | deleted.herokuapp.com | NXDOMAIN | 可接管——第三方平台允许重新注册 |
这里只讲"识别和标注风险",不展开接管利用方法——利用步骤留到后续漏洞章节。
技巧
| 技巧 | 做法 | 价值 |
|---|---|---|
| 多级 CNAME 追踪 | 顺着链条追到 A 记录,不只看第一跳 | CNAME 链可能有多级,只看第一跳会漏 |
| 第三方平台识别表 | 维护常见第三方平台域名列表 | 快速判断是否第三方托管 |
| 失效 CNAME 标注 | 终点返回 NXDOMAIN 的单独标注 | 接管风险高,要重点处理 |
| 关联域名提取 | 从 CNAME 链中间节点提取新根域名 | 喂给进阶发现做递归 |
注意事项
| 事项 | 说明 |
|---|---|
| CNAME 链可能循环 | A→B→A 的循环——要检测并中止 |
| CNAME 到 A 记录的最终解析 | CNAME 链终点才是真实 IP,中间节点不是 |
| 部分 DNS 不返回完整链 | 有些 DNS 服务器只返回第一跳,要换 DNS 重查 |
| 第三方平台可接管的判断 | 不是所有失效 CNAME 都能接管——只有允许重新注册的平台才行 |
6.4 输入输出校验
前置知识
管道数据丢失概念
批量处理数据时,数据从输入端经过处理流程流向输出端,这个中间通道叫"管道"(Pipeline)。管道可能丢数据——比如 DNS 解析时,输入了 1000 个子域,但因为网络超时、DNS 服务器限速、程序异常,输出端只收到 950 个结果。50 个子域在管道里丢了。如果不做校验,你以为处理完了 1000 个,实际只处理了 950 个——50 个子域漏掉了。
关键认知:丢包是批量处理的常见问题,不是 bug——网络超时、DNS 限速、并发冲突都会导致丢包。校验的价值是"发现丢了多少、补回来多少"。第8章踩坑录里有管道数据丢失的实战案例。
是什么
校验从输入(原始子域名列表)到输出(清洗后子域名列表)的数据完整性,发现和修复丢包。
为什么
批量解析时管道可能丢数据——输入 1000 个子域,输出 950 个,50 个在管道里丢了。如果不校验,这 50 个会被当作"不存在"——实际是超时丢的,不是真不存在。假阴性。
怎么做
第一步:输入计数
| 记录项 | 说明 |
|---|---|
| 原始子域总数 | 进入清洗的子域数量 |
| 按来源分类 | 被动发现多少 / 主动探测多少 / 进阶发现多少 |
| 按方法分类 | CT 多少 / 搜索引擎多少 / 字典爆破多少 |
第二步:输出计数
| 记录项 | 说明 |
|---|---|
| 解析成功数 | 返回 NOERROR + IP 的 |
| 解析失败数 | 返回 NXDOMAIN 的 |
| 超时数 | 查询超时的 |
| 异常数 | SERVFAIL、CNAME 循环等 |
第三步:差异比对
| 差异类型 | 原因 | 处理 |
|---|---|---|
| 输入 - 输出 = NXDOMAIN 数 | 正常丢弃——子域确实不存在 | 不处理 |
| 输入 - 输出 > NXDOMAIN 数 | 异常丢失——超时或丢包 | 重跑丢失的 |
| 超时数占比高 | DNS 限速或网络问题 | 降速重跑 |
第四步:异常处理
| 异常类型 | 处理 |
|---|---|
| 超时的 | 换 DNS 服务器重查,切 TCP |
| CNAME 循环的 | 标注异常,不丢弃 |
| 返回 SERVFAIL 的 | 换 DNS 重查 |
| 丢失的(输入有、输出没有) | 重跑,确认是丢弃还是不存在 |
技巧
| 技巧 | 做法 | 价值 |
|---|---|---|
| 分批处理 | 每批 500-1000 个,每批做完校验 | 及时发现丢包,不等到最后 |
| 每批校验 | 输入数 - 输出数 = 预期丢弃数? | 数值不对 = 有异常丢失 |
| 异常日志 | 记录每个异常子域和异常类型 | 事后排查和重跑 |
| 丢包率监控 | 统计丢包率,超过 5% 自动降速 | 早期发现 DNS 限速 |
注意事项
| 事项 | 说明 |
|---|---|
| 正常丢弃 vs 异常丢失 | NXDOMAIN 是正常丢弃,超时是异常丢失——要区分 |
| 丢包率监控 | 丢包率突然升高 = 可能被限速了 |
| 重跑策略 | 超时的换 DNS 重跑,不要用同一 DNS 重跑 |
| 全量校验 | 最终要全局校验,不能只校验单批 |
6.5 阶段输出
输出1:可信子域名列表
| 字段 | 说明 | 示例 |
|---|---|---|
| 子域名 | 清洗后的可信子域名 | api.example.com |
| A 记录 IP | 解析到的 IP | 1.2.3.4 |
| CNAME 链 | 完整 CNAME 链 | api.example.com → internal-lb.example.com → 1.2.3.4 |
| 终点类型 | 自有/CDN/第三方/悬挂 | 自有 |
| 通配符状态 | 是否命中通配符 | 否 |
| 发现来源 | 从哪些方法发现的 | CT, 字典爆破 |
| 清洗状态 | 是否通过清洗 | 通过 |
输出2:IP 地址列表
| 字段 | 说明 | 示例 |
|---|---|---|
| IP | 解析到的 IP | 1.2.3.4 |
| 归属 ASN | IP 所属 ASN | AS37963 |
| 归属组织 | ASN 归属组织 | 阿里巴巴 |
| 是否 CDN | 是 CDN IP 还是目标自有 | 否 |
| 关联子域 | 哪些子域解析到这个 IP | api.example.com,www.example.com |
输出3:通配符状态表
| 字段 | 说明 | 示例 |
|---|---|---|
| 根域名 | 哪个根域启用了通配符 | example.com |
| 通配符 IP | 通配符指向的 IP | 1.2.3.4 |
| 检测方法 | 怎么检测到的 | 随机子域验证 |
| 过滤策略 | 怎么过滤的 | 命中通配符 IP 的丢弃 |
| 过滤数量 | 过滤了多少假阳性 | 120 |
输出4:异常记录
| 字段 | 说明 | 示例 |
|---|---|---|
| 子域名 | 异常的子域名 | old.example.com |
| 异常类型 | 什么异常 | 悬挂 DNS / CNAME 循环 / 超时 |
| 异常详情 | 具体情况 | CNAME 指向已失效的 herokuapp.com |
| 处理状态 | 怎么处理的 | 标注接管风险,保留 |
| 重跑结果 | 重跑后的结果 | 仍然失效 |
6.6 与其他阶段的衔接
输出流向
可信子域名列表 ──→ 阶段6:HTTP 探测(对存活的做探测) IP 地址列表 ──→ 阶段6:HTTP 探测(IP 归属判断 CDN) 通配符状态表 ──→ 归档(后续复扫参考) 异常记录 ──→ 阶段8:踩坑录(接管风险单独处理)清洗过的数据为什么要做 HTTP 探测
清洗解决的是"DNS 层面是否存活"——解析成功 = 域名在 DNS 里有记录。但 DNS 存在不等于有价值:
| DNS 状态 | HTTP 探测可能的结果 |
|---|---|
| 解析成功 + 自有 IP | 可能是正常服务(200),也可能是空站(404) |
| 解析成功 + CDN IP | 可能是 CDN 缓存(200),也可能是 CDN 回源失败(502) |
| 解析成功 + 悬挂 DNS | HTTP 探测返回错误页或 404 |
| CNAME 指向第三方 | 可能是正常第三方页面,也可能第三方已删除 |
清洗没解决的问题:DNS 存在不等于有价值。一个子域名 DNS 解析成功,但 HTTP 探测可能返回 404、403、502——这些状态码的挖掘意义,留给阶段6 HTTP 探测判断。
递归时要重新清洗
进阶发现阶段(阶段4)发现新子域时,要回到这里重新清洗:
| 重新做的 | 为什么 |
|---|---|
| 重跑多 DNS 解析 | 新子域要验证 DNS 是否存活 |
| 重跑通配符检测 | 新根域名可能有自己的通配符配置 |
| 重跑 CNAME 链跟踪 | 新子域的 CNAME 链可能指向新第三方服务 |
| 重跑输入输出校验 | 新一批数据要校验完整性 |
关键认知:清洗是流程里最容易被忽视的阶段——它不发现新东西,只做验证和过滤。但跳过清洗直接做 HTTP 探测,会浪费大量请求配额在假阳性、过时、不可达的子域上。清洗的价值是"省成本"和"保质量"。
下一篇:第7章——HTTP 探测与价值评估,判断哪些子域"存活"且"有价值"。