反查域名这个动作说穿了就是手里攥着一串 IP想搞清楚它背后对应的是哪个站点、哪家服务、哪台机器。我做日志分析和资产梳理那几年几乎每周都要干一次——凌晨告警群里甩过来一个陌生 IP得在十分钟内判断它是自家某个边缘节点、外部扫描器还是合作方回调接口。这时候光看端口通不通毫无意义真正能救命的是把这个 IP 反查成域名再顺着域名摸清归属。下面这套路径从最基础的 PTR 反解析到被动 DNS 历史库、再到证书字段旁路都是我实际跑过很多遍的命令可以直接抄坑我替你踩过了。不管你是刚接触运维的新手还是做了几年安全的老兵都能从里面挑到顺手的那一把。1. 反查域名的底层逻辑与方案选型1.1 PTR 记录DNS 里那条独立的反向索引DNS 正查是域名 → IP反查是IP → 域名这两件事走的是完全独立的两棵子树。反查用的子树叫 in-addr.arpaIPv4和 ip6.arpaIPv6挂在 DNS 命名空间的最顶层。为什么要有这么个看起来很奇怪的后缀因为 DNS 的层级是从右往左读的越靠右越粗。要让 IP 也能按网段 → 主机的顺序逐级委派就必须把 IP 的字节顺序倒过来写。203.0.113.10 这个地址反查时写成 10.113.0.203.in-addr.arpa。最左边的 10 是主机位往右依次是 /24、/16、/8 的层级边界。这样 /24 的实际持有者只需要在自己的区里给自己的那一段授权不用关心整个 /8 怎么管。IPv6 更绕一点因为地址是十六进制并且有 32 个半字节所以要按 nibble半个字节逐个倒序展开。2001:db8::1 展开后是一长串以 ip6.arpa 结尾的名字看着吓人但规则非常机械用工具展开就行不用手算。理解了这套倒序逻辑你就能明白一件事反查不是查询某个 IP 的元数据而是去问一个特定的 DNS 区域要一条 PTR 记录。既然是 DNS 查询就必然受制于解析器缓存、超时、递归策略这些因素后面遇到的很多诡异现象都跟这个有关。1.2 为什么大部分 IP 的 PTR 是空的这是新手最容易崩心态的地方兴冲冲敲完 dig -x返回一堆 NXDOMAIN第一反应是命令写错了。其实没错。反向解析区不是你想设就能设的它由 IP 的实际持有方维护。家用宽带拨号拿到的动态地址运营商基本不会给你配 PTR云主机默认给你的 PTR 往往也是空的或者是一个形如某机房某机柜某号的通用名跟业务毫无关系对分析毫无帮助。真正有像样 PTR 的通常是几类自建机房的老牌企业、邮件服务商因为收信方会校验 PTR 和 HELO 域名是否一致不配就进垃圾箱、以及少数把反解析当成规范来做的团队。所以当你拿到一个干净的 PTR含金量其实不低。还有一个必须建立的认知PTR 是可以随便填的谁持有这个网段谁就能填。反查出来的域名只能当线索不能当证据。我见过把某个 IP 的 PTR 填成完全不相关域名的也见过填成一串随机字符专门恶心分析人员的。把它当成这条线索值得往下追的信号而不是结论心态就稳了。1.3 三条路线怎么选主动、被动、旁路只靠 DNS 反解析命中率在很多场景下不到三成。所以我平时用的是三条腿走路按成本和准确度排一下路线数据来源典型产出主要局限适用场景主动 DNS 反解析权威服务器上的 PTR一条或几条规范域名绝大多数 IP 没配配置方可以随意填邮件服务、自建机房、快速初筛被动 DNS 历史库递归解析器日志汇总该 IP 历史上解析过的全部域名及时间依赖平台覆盖度免费额度有限溯源、资产归属、挖历史绑定证书与内容旁路TLS 证书 SAN、HTTP 跳转、页面指纹该 IP 上正在服务的域名需直连有 SNI 干扰加密后失效确认当前到底跑着什么站这三条路的组合顺序很关键。我的习惯是先跑主动反解析拿第一手线索哪怕大概率是空的成本只有几十毫秒拿不到就立刻切被动 DNS看历史绑定历史也挖不出来最后才上证书和内容旁路因为这一步要直连目标动作最重、也最容易被对方的安全设备记录。选被动 DNS 而不是一上来就硬扫理由很实际扫描会留下痕迹而被动 DNS 只是查公开数据对方完全感知不到。做资产梳理和竞品分析时这个差别很大。至于证书旁路它的优势是所见即所得——你能确定这个 IP 此刻正在提供服务的域名是什么而不是历史上可能绑过什么。2. 命令行实操从单个 IP 到批量反查2.1 三个命令的最小可用形态绝大多数 Linux 发行版自带 dig、host、nslookup 三个工具装 bind-utils 或 dnsutils 就有。三者的差异很微妙dig 输出最全、可控性最好适合脚本化host 输出最干净适合人眼看nslookup 兼容性最好Windows 上也有但输出格式不统一不适合解析。# 最小可用直接反解 dig -x 203.0.113.10 short # 指定公共解析器绕开本地 DNS 缓存和劫持 dig -x 203.0.113.10 1.1.1.1 short # 只保留 ANSWER 段去掉 AUTHORITY 和统计噪音 dig -x 203.0.113.10 noall answer PTR # 查询反查区的 NS确认这个网段到底有没有被委派 dig 113.0.203.in-addr.arpa NS short最后那条命令值得单独说。很多人查不到 PTR 就开始怀疑人生其实只要先查一下这个网段的反查区有没有 NS 记录立刻就能判断没有 NS说明持有方压根没建反向区这条路上你查一辈子都是空有 NS说明区是存在的只是这个具体 IP 没配记录。这个区分对判断该不该继续在这条路上花时间特别有用。提示本地路由器的 DNS 转发经常对反查区做特殊处理甚至直接返回虚假结果。所有反查动作一律显式指定 解析器地址别用系统默认。host 和 nslookup 的写法顺手记一下遇到只有这两个工具的机器不至于抓瞎host 203.0.113.10 host 203.0.113.10 1.1.1.1 nslookup 203.0.113.10 1.1.1.12.2 一个 IP 的完整排查动作假设日志里冒出来一个 203.0.113.10我要在五分钟内给出结论。实际操作顺序是这样的第一步查 PTR同时把这个网段有没有反向区也查一遍两条命令并行跑。第二步查这个 IP 归属哪个网段、哪个组织。归属信息能直接告诉你它是云主机、IDC 托管还是家宽这决定了后续该往哪个方向想。第三步查历史解析。用被动 DNS 平台的 IP 查询入口看这个 IP 历史上挂过哪些域名重点看最近一次出现时间和记录类型。如果最近一周内有 A 记录指向它那基本可以认定这是当前活跃的绑定关系。第四步直连验证。用 curl 和一个伪造的 Host 头去看看或者直接看 TLS 证书。这一步是确认不是发现——你得带着假设去验证而不是漫无目的地扫。# 看 HTTP 响应头和跳转目标 curl -sSI --max-time 5 http://203.0.113.10/ | head -20 # 指定 Host 头试探虚拟主机绑定 curl -sS -o /dev/null -w %{http_code} %{redirect_url}\n \ -H Host: example.com http://203.0.113.10/ # 抓 TLS 证书里的域名列表 openssl s_client -connect 203.0.113.10:443 -servername example.com /dev/null 2/dev/null \ | openssl x509 -noout -subject -ext subjectAltName这几条命令的顺序别乱。先 curl 再 openssl因为 curl 更快、更不容易被 WAF 拦。带上 -m 5 这种超时限制是必须的我吃过太多次亏——某个 IP 不回包脚本就卡在那里直到天荒地老批量跑的时候简直是灾难。2.3 批量反查并发、超时、限速三件事单个 IP 好办几百上千个 IP 就得靠脚本。这里有个反直觉的点反查是 IO 密集型任务瓶颈在网络往返不在 CPU所以并发几十路是合理的但别无脑开到几百会把自己出口的 DNS 查询速率打爆运气不好还会被上游解析器限流。bash 版最快上手用 xargs 控制并发#!/usr/bin/env bash # ips.txt 一行一个 IP cat ips.txt | xargs -P 20 -I{} sh -c r$(dig short time2 tries1 -x {} 1.1.1.1 | head -1) echo -e {}\t${r:-NO_PTR} result.tsvtime2 tries1 这两个参数是精髓。默认 dig 会重试三次、每次等五秒一个不回包的 IP 就要耗掉十五秒一千个 IP 里只要有一百个不回包你的脚本就得多跑二十多分钟。把超时压到两秒、重试压到一次整体速度能快十倍以上代价是偶尔漏掉慢响应对批量初筛完全可以接受。要更细的控制就用 Python 配 dnspython好处是能拿到 RCODE区分不存在和超时这两种情况——这个区分在做统计时很有价值import concurrent.futures as cf import dns.resolver, dns.reversename, dns.exception def rev(ip, timeout2): try: name dns.reversename.from_address(ip) ans dns.resolver.resolve(name, PTR, lifetimetimeout) return ip, [r.to_text().rstrip(.) for r in ans] except dns.resolver.NXDOMAIN: return ip, [NXDOMAIN] except dns.exception.Timeout: return ip, [TIMEOUT] except Exception as e: return ip, [type(e).__name__] ips [l.strip() for l in open(ips.txt) if l.strip()] with cf.ThreadPoolExecutor(max_workers30) as pool: for ip, names in pool.map(rev, ips): print(ip, |.join(names))注意批量反查前先确认你有权限查这些 IP。给别人家的 IP 段做高频反查在对方的监控里就是一次低速扫描很容易被拉黑。控制并发、加随机间隔是最基本的礼貌。3. 被动 DNS 与历史解析PTR 为空时的主战场3.1 被动 DNS 到底记录了什么被动 DNSPassive DNS的原理不复杂一批递归解析器把自己看到的每一次域名 → IP的应答都记下来汇总成一张带时间戳的大表。你查到的不再是当前配置是什么而是过去某段时间里有人真的这样解析过。这个视角的转换非常关键它带来了三个主动查询做不到的能力。第一是历史性。一个域名昨天刚换了 IP主动查今天就看不到旧关系了被动 DNS 里还留着。做溯源时这条太重要了很多攻击基础设施的生命周期只有几天等你反应过来早换了只有历史库还留着痕迹。第二是全量性。一个 IP 上挂过几十个域名主动反查最多给你几条 PTR被动 DNS 能给你几十条甚至上百条。做虚拟主机识别、共享 IP 拆分时这是唯一靠谱的办法。第三是无感知。查被动 DNS 只是查别人的公开数据目标完全不知道你在查它。这一点在授权范围模糊的场景下比任何主动探测都安全。3.2 查询时要盯住哪几个字段不同平台字段名不一样但核心就那么几个看懂一个就都懂了。字段含义判读要点首次出现这条绑定最早被观测到的时间时间很早说明是长期绑定可信度高最后出现最近一次被观测到的时间一周内出现基本可认定当前仍活跃记录类型A / AAAA / CNAMECNAME 说明中间还有一层值得顺藤摸瓜解析来源分布观测到的解析器地域分布集中在某个区域可能是区域性服务关联域名数该 IP 上的域名总量几十上百条通常是共享主机或 CDN实战里我最看重最后出现时间和关联域名数这两个。前者决定这个线索是不是活的后者决定这个 IP 的性质。一个 IP 上关联了两百个域名基本都是 CDN 边缘节点或者虚拟主机你反查出来的任何一个域名都和这个 IP 没有排他关系别把它当成这个 IP 属于某个站的证据。3.3 自建一个轻量解析记录库商业平台有配额长期做资产跟踪的话自建一个小库更划算。思路很朴素定时任务去拉取公开的证书透明日志增量、对目标网段做低频反查、把结果按时间戳写进 SQLite然后按 IP 建索引。表结构不用复杂三张表够了一张存 IP 归属快照一张存IP-域名-时间的绑定事实一张存域名维度的补充信息。关键在于绑定事实表要有 observed_at 字段和来源标记这样同一对 IP-域名在不同时间被观测到多次就能形成一条时间线而不是一堆互相覆盖的脏数据。CREATE TABLE ip_domain ( ip TEXT NOT NULL, domain TEXT NOT NULL, source TEXT NOT NULL, -- ptr / passive / cert / http first_seen DATETIME NOT NULL, last_seen DATETIME NOT NULL, PRIMARY KEY (ip, domain, source) );这个设计的妙处是 source 字段。同一个 IP-域名关系如果 PTR 里出现过、被动 DNS 里出现过、证书里也出现过三条独立证据交叉可信度就完全不一样了。反过来如果只有某一条来源孤零零地存在那就要打个问号。我后来所有判断都是基于几个独立来源同时指向同一个结论而不是某一个平台给的漂亮结果。4. 证书与内容侧旁路把域名从 HTTPS 里抠出来4.1 TLS 证书的 SAN 字段是金矿只要目标开了 HTTPS握手时它必须把证书递给你而证书里的 Subject Alternative NameSAN字段会明明白白列出这张证书覆盖的所有域名。这是一条不需要任何权限、不需要登录、不需要 API Key 就能拿到的信息性价比极高。# 带上 SNI拿到对应虚拟主机的证书 openssl s_client -connect 203.0.113.10:443 -servername example.com /dev/null 2/dev/null \ | openssl x509 -noout -subject -ext subjectAltName # 不带 SNI拿到该 IP 的默认证书 openssl s_client -connect 203.0.113.10:443 /dev/null 2/dev/null \ | openssl x509 -noout -subject -ext subjectAltName这里有个必须讲的坑SNI。一台服务器上跑十个站点你不告诉它你要访问哪个域名它只能返回默认证书而这个默认证书对应的往往不是你想找的那个站。所以正确的打法是先不带 SNI 拿一次看看默认证书是什么再拿到的域名作为 -servername 参数打第二次才能看到真正的目标。很多人只跑一次就下结论结果拿到的域名八竿子打不着还以为查错了。还有一个免费的信息证书的有效期和签发时间。如果一张证书是三天前刚签发的说明这个站最近才部署或者刚续期往往对应着新上线的业务做资产变化监控时是个很好的抓手。4.2 跳转链与页面指纹HTTP 层面的信息量同样不小。哪怕不做任何路径爆破只看根路径的响应也能挖出不少东西。curl -sSI --max-time 5 http://203.0.113.10/重点看三样Location 头有没有把你跳到一个域名上Server 头暴露了什么中间件Set-Cookie 里的 Domain 字段是什么。第三个经常被忽略——很多站点在根路径直接下发一个带 Domain 的 Cookie那个 Domain 就是它真正服务的域名不用猜。如果对方是虚拟主机用 Host 头试探是最直接的办法。你已经从别处拿到了几个候选域名逐个塞进 Host 头看响应码和响应体长度有没有变化。状态码从 404 变成 200或者响应体长度从几百字节变成几万字节说明这个域名确实绑在这台机器上。for d in example.com example.net example.org; do printf %-20s $d curl -sS -o /dev/null -w %{http_code} %{size_download}\n \ -H Host: $d --max-time 5 http://203.0.113.10/ done这个方法的有效性取决于对方有没有配置默认站点。如果对方配了所有未知 Host 都返回同一个页面那长度就都一样这条线索就断了。断不断得试了才知道成本很低值得一试。4.3 证书透明日志的正确用法证书透明日志CT记录了所有公开 CA 签发的证书是个巨大的公开数据集。这里必须澄清一个常见误解CT 日志是按域名索引的不能直接按 IP 搜索。你没法在一个 CT 日志查询站点里输入一个 IP 然后指望它吐出域名来那是不存在的功能。CT 日志真正的用法是反过来你从被动 DNS 或者别的地方拿到了一批候选域名用 CT 日志去验证这些域名历史上签发过哪些证书、证书里还带了哪些兄弟域名。这一步经常能带来意外收获——一张证书的 SAN 里塞了几十个域名你只关心其中三个剩下的几十个可能就包含了你正在找的那个。所以正确的流程是被动 DNS 给候选域名 → CT 日志扩展域名集合 → 回到被动 DNS 验证这些新域名有没有解析到这个 IP → 形成闭环。这个循环跑两三轮通常就能把一个 IP 上的所有相关域名摸得七七八八。5. 交叉验证与踩坑记录5.1 四类高频误判每一种我都踩过第一类是共享 IP。虚拟主机、共享托管环境下一个 IP 上跑着几百个站反查出来的任何一个域名都不具备排他性。判断方法很简单被动 DNS 里关联域名数超过二十个基本可以确定是共享环境这时候这个 IP 属于谁这个问题本身就是错的应该问这个 IP 上哪一个域名跟我有关。第二类是 CDN 和反代。CDN 边缘节点的 IP 会随着调度不断变化同一个 IP 今天服务 A 站、明天服务 B 站完全正常。看到关联域名数极多、且域名之间毫无业务关联性就该怀疑是 CDN 了。这时候反查出来的域名只能说明这个域名曾经在这个节点上有缓存不能说明归属。第三类是 NAT 和出口复用。企业出口、运营商大内网一个公网 IP 背后是成百上千台内网机器。反查出来的域名可能只是这个出口上某一台机器曾经用的跟你要查的那台毫无关系。第四类是停放页和泛解析。有些 IP 上挂的全是域名停放页任何 Host 头都返回同一个广告页有些权威 DNS 配了泛解析随便什么子域名都给你一个 A 记录。这两种情况下你查出来的域名全是噪音得靠这个域名有没有真实内容来过滤。5.2 常见问题速查表现象最可能的原因处理办法dig -x 返回 NXDOMAIN该网段未建反向区或该 IP 未配记录查反查区 NS没有就换路线别死磕dig -x 一直超时解析器不递归反查区或网络被拦换公共解析器加 time2 tries1PTR 返回的名字像随机字符串持有方批量生成无业务含义只当网段标识用别当域名追被动 DNS 查出一堆无关域名共享 IP 或 CDN 节点看域名关联数用证书验证当前绑定openssl 拿到的证书域名对不上没带 SNI拿到默认证书先拿默认证书再用候选域名带 SNI 重试curl 所有 Host 都返回 200配了默认站点或泛解析比对响应体长度和内容哈希不看状态码同一个 IP 两次查询结果不同负载均衡或 CDN 调度多查几次取交集别用单次结果下结论批量脚本卡住不动无超时设置某个 IP 不回包一律设置 2 秒超时和 1 次重试5.3 我在实操里攒下的几条经验最想说的是别信单点。反查这件事最大的陷阱不是技术难度而是过早下结论。我见过太多次一个 PTR 查出来是个看起来很像的域名就直接认定归属结果后面全盘皆错。稳妥的做法永远是至少两个互相独立的来源指向同一个结论才算初步可信三个来源一致才敢写进报告。第二个经验是关于解析器选择的。不同公共解析器对反查区的处理策略不一样有的会积极递归、有的直接拒绝。同一个 IP 在 A 解析器上返回 NXDOMAIN、在 B 解析器上返回正常 PTR这种事我遇到过不止一次。所以关键 IP 我会换两三个解析器交叉验证避免被单个解析器的策略误导。第三个是关于速率。反查看起来是无害的查询但高频打同一个权威服务器在对方眼里和扫描没区别。我给自己的规矩是单目标每秒不超过两次查询批量任务加随机抖动遇到连续超时就降速。这条规矩让我少吃了很多封禁的亏。第四个是关于记录。每次排查完把 IP、查到的域名、来源、时间、结论写进一个固定格式的表格里。这个习惯看起来笨但三个月后再遇到同一个 IP你能立刻翻出当时的判断依据而不是从头再来一遍。我后来把这个表做成了自动追加的小脚本每次查完顺手写一行成本几秒钟收益是长期的。最后一个想说的是心态。标题里那句一查一个准听着爽实际做下来你会发现真正能一查一个准的场景其实很窄——就是你查的是自建机房、有规范 PTR、且不是共享环境的 IP。绝大多数情况下反查域名是一个多源交叉、逐步收敛的过程你要做的是把每条线索的可信度标清楚而不是指望某一条命令给出终局答案。把预期放平反而每次都能挖到有用的东西。
阅读完成 · 觉得有帮助?