做资产梳理的时候,我经常被人问:Amass和Subfinder到底有什么区别,能不能只装一个?我的回答一般是:可以,但你大概率会漏东西。这是我自己跑了无数次子域发现之后得出的结论,不是替哪个工具站台。Amass是OWASP体系里的攻击面映射工具,Subfinder是ProjectDiscovery出品的被动子域发现工具,两个都开源、都在快速迭代,但它们的侧重点完全不同。把Amass与Subfinder做深度集成,本质上是把“被动数据挖掘”和“主动测绘验证”两套能力拼在一起,让子域清单从“能用”变成“尽量全”。
我见过不少朋友只在命令行里敲一条subfinder -d example.com就跑,然后干等结果;也见过有团队拿Amass硬跑,一跑就是两三个小时,最后输出一屏ASCII图形,不知道该怎么用。这两种用法都有点浪费。Amass和Subfinder各自能解决一部分问题,但把它们放在同一个工作流里,互补效果才真正拉满。这篇文章会从设计思路讲到安装配置,再到三种不同的集成玩法,最后把我踩过的坑和排查思路一起放出来。适合做资产测绘的安全工程师、做授权渗透测试的同行,以及想把自己域名台账管清楚的运维同学参考。
1. 为什么这两个工具值得被放在一起
1.1 Amass和Subfinder的定位差异
先说Amass。它的全名是OWASP Amass,早期版本就叫amass,后来项目组织改到owasp-amass下。它给自己的定位是攻击面枚举框架,而不是单纯的子域爆破器。它会把你枚举过程中收集到的域名、IP、CIDR、ASN这些信息关联起来,默认输出甚至是一个可视化图形,数据还可以落到LevelDB里供后续分析。它支持passive、active、brute等至少三种枚举模式,并且内置了大量数据源接入点。换句话说,Amass的设计目标是“把目标资产的脉络摸清楚”,而不是“快速输出几百行域名”。
再说Subfinder。它是ProjectDiscovery全家桶的一员,和httpx、nuclei这些工具生态共享。它的定位是被动侦察,核心诉求是速度和安静。Subfinder几乎不会主动向目标基础设施发探测,主要依赖证书透明日志、DNS数据集、第三方API来收集子域名,输出就是干干净净的域名列表。这种设计在自动化工作流里非常友好,它的输出可以直接被下一个工具消费,不需要你做多余的数据清理。
这两个工具的定位差异,可以用一个不太严谨但很形象的类比:Subfinder像是一个跑得很快的侦察兵,先去把目标地盘的轮廓探明白;Amass更像一支拿着无人机、地图和数据模型的测绘队,花的时间更长,但能把道路、地块、重要建筑全部标出来。你单独用侦察兵,能快速知道大概,但会漏掉藏在深处的小路;你单独用测绘队,精度高,但前期的等待和配置成本也高。所以深度集成不是多余动作,而是让两种能力各司其职。
1.2 深度集成能带来哪些实际收益
把两个工具集成到同一套流程里,我在实际工作中得到最直观的收益有几个:
- 数据源覆盖面的互补。Subfinder依赖的被动源和Amass内置的数据源并不完全重合,同一个目标跑出来的结果经常有几百上千条的差异,规模稍大的企业域名,差集可能达到数百条。
- 主动与被动的互补。Subfinder不会主动向目标DNS服务器发探测,而Amass的active模式会尝试主动解析、获取证书信息,这部分数据是纯被动工具拿不到的。
- 速度与深度的互补。Subfinder几秒钟就能出结果,适合先打底;Amass可以后台慢慢跑,跑出来的结果再补充回底表里。
- 交叉验证。如果一个域名被两个工具同时发现,它的可信度会更高,优先投入存活验证;如果只有一个工具发现,反而会提醒我去检查另一个工具的API额度或数据源配置有没有问题。
这四点几乎是所有集成的核心动机。你不需要把两个工具当成“二选一”的竞品,它们在真实工作中更像互相补位的搭档。
2. 安装、配置与输出规范化
2.1 安装方式选型和版本验证
安装这两个工具的方式比较多,我整理了一个简单的对比:
| 安装方式 | 适用场景 | 备注 |
|---|---|---|
| Go install | 有Go环境的开发机 | 需要提前配好GOPATH和PATH |
| Release二进制 | 不想折腾环境 | 推荐,下载解压即可用 |
| Docker | 隔离环境、定时任务 | 镜像体积较大,更新需拉新 |
| 包管理器 | 尝鲜、快速验证 | 版本可能滞后 |
我个人的习惯是直接下载release二进制,省去编译和依赖问题。如果你本来就是Go生态用户,用go install也很方便:
go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest go install -v github.com/owasp-amass/amass/v4/...@latest装完第一件事是验证版本:
subfinder -version amass -version版本有一个容易踩的坑:Amass的老版本还在caffix/amass仓库,现在官方迁移到owasp-amass组织下,v3和v4的配置格式有变化。不管你在哪里下载,安装完先看-help,确认参数名。比如Amass的枚举命令是enum,信息收集是intel,不要把老博客里的命令硬套到新版本上。Subfinder同理,v2之后的主流用法比较稳定,但API provider配置文件的字段名偶尔会调整。
2.2 子域发现的命脉:API密钥配置
这两个工具的开箱即用体验都不差,但“开箱即用”和“榨干性能”之间,隔着一堆API密钥。
Subfinder的配置文件默认在~/.config/subfinder/provider-config.yaml,结构大概是这样的:
securitytrails: - SECURITYTRAILS_API_KEY virustotal: - VIRUSTOTAL_API_KEY censys: - CENSYS_USERNAME - CENSYS_SECRET这些看起来只是几行配置,实际影响却非常大。不带key跑,Subfinder只能用一小部分不需要认证的数据源;带key之后,尤其是SecurityTrails、VirusTotal、Censys、Shodan这些,结果数量和稳定性会明显上升。我第一次给Subfinder配齐这些key,跑同一个目标,结果从几千条涨到了接近两万条。
Amass同理,配置文件里每个数据源都有一个key字段,你留空,它就跳过那个源;你填上,被动阶段就会多一块数据来源。Amass配置文件的写法在不同版本略有差异,但核心思路一致:
# amass config.yaml 中数据源部分写法(不同版本字段名有差异) data_sources: - name: SecurityTrails key: your_securitytrails_key - name: VirusTotal key: your_virustotal_key配置这里有三点提醒。第一,不要把密钥提交到Git仓库,一个简单的.gitignore就能避免大多数泄露事故。第二,用-config显式指定配置文件,比依赖默认路径更可靠,尤其在不同机器上跑任务时。第三,密钥额度耗尽时,工具不会报错,而是安静地跳过这个数据源。所以当结果显著变少时,先去看API剩余配额,而不是怀疑工具坏了。
2.3 输出格式差异与标准化处理
Subfinder的输出默认是一行一个域名,加-silent会去掉所有干扰信息,只保留域名本身:
subfinder -d example.com -all -silent -o subfinder_raw.txtAmass的输出则要小心很多。默认情况下它会往标准输出画ASCII图形,看起来很有科技感,但下游工具根本没法解析。所以我强烈建议用-json参数输出结构化数据:
amass enum -passive -d example.com -json amass_raw.jsonAmass的JSON输出是JSON Lines格式,每一行一个对象,域名在name字段里。抽取域名通常用jq:
jq -r '.name' amass_raw.json | sed 's/\.$//' | tr 'A-Z' 'a-z' | sort -u > amass_clean.txt为什么要加sed和tr?因为Amass的域名字段偶尔会带末尾点,大小写也可能不一致,而Subfinder的输出相对干净。如果不做标准化就合并,www.example.com和www.example.com.会被当成两个域名,后续去重和比对都会出错。这个细节我在真实项目中踩过,所以特意放在前面讲。
3. 三种深度集成的实战玩法
3.1 双枚举合并去重,生成权威子域清单
这是最基础也是最实用的玩法:两个工具各自跑一遍,然后把结果合并去重,得到一份完整的子域清单。
# 第一步:Subfinder 快速打底 subfinder -d example.com -all -silent -o subfinder_raw.txt # 第二步:Amass 后台补全 amass enum -passive -d example.com -json amass_raw.json # 第三步:格式标准化 tr 'A-Z' 'a-z' < subfinder_raw.txt | sed 's/\.$//' | sort -u > subfinder_clean.txt jq -r '.name' amass_raw.json | tr 'A-Z' 'a-z' | sed 's/\.$//' | sort -u > amass_clean.txt # 第四步:合并去重 cat subfinder_clean.txt amass_clean.txt | sort -u > all_subs.txt wc -l all_subs.txt这一步做完,你会得到一份比单独跑任何一个工具都更完整的子域清单。在脚本里我建议加一个简单的记录逻辑:把两个原始输出文件都保留下来,后续排查时能知道某一条结果到底来自哪个工具。不要只保留合并后的文件,否则遇到来源疑问时要重跑一遍。
这里也可以写一个简单的Python脚本做同样的事,顺便为后续API查询留扩展口子:
import json def load_subfinder(path): with open(path) as f: return {line.strip().lower().rstrip('.') for line in f if line.strip()} def load_amass(path): domains = set() with open(path) as f: for line in f: try: domains.add(json.loads(line)['name'].lower().rstrip('.')) except (json.JSONDecodeError, KeyError): pass return domains all_domains = load_subfinder('subfinder_clean.txt') | load_amass('amass_clean.txt') with open('all_subs.txt', 'w') as f: f.write('\n'.join(sorted(all_domains)))3.2 被动打底、主动补漏的分工模式
如果目标规模比较大,或者你对目标的抗打扰能力有要求,建议用被动打底、主动补漏的分工模式。
先让Subfinder用被动源把所有能拿到的子域都拉下来,这是一轮基本不接触目标基础设施的操作。然后再让Amass以active模式跑一轮,用主动解析、证书获取等方式补充被动源覆盖不到的边角。这样既能控制请求量,又能比单用被动得到更完整的覆盖。
Amass active模式的命令大概是这样的:
amass enum -active -d example.com -timeout 20 -max-dns-queries 1000 -json amass_active.json-timeout控制单次查询的等待时间,-max-dns-queries限制DNS查询总量。这两个参数要按目标规模调整,默认值不一定适合你的场景。不同版本参数名也有区别,所以跑之前一定先看-help。
先被动后主动还有一个隐藏好处:被动结果可以很快进入存活验证流程,而主动结果跑完再合并,相当于两批子域在不同时间点汇入资产台账。自动化任务可以按照“被动先跑、主动跟进、统一合并”的顺序串起来,不会出现所有任务挤在一起等结果的情况。
3.3 差异化比对,用交叉验证发现盲区
合并去重是集成的基础玩法,差异比对才是进阶玩法。两个工具跑同一目标,结果不会完全一致,这些差异恰恰能反映很多问题。
# 交集:两个工具都发现 comm -12 <(sort subfinder_clean.txt) <(sort amass_clean.txt) # 仅在 Subfinder 中的结果 comm -23 <(sort subfinder_clean.txt) <(sort amass_clean.txt) # 仅在 Amass 中的结果 comm -13 <(sort subfinder_clean.txt) <(sort amass_clean.txt)这里有个细节必须提醒:comm要求两个输入文件都是按字典序排好序的,否则结果完全不可信。所以不要直接把原始文件丢进去,先sort再喂。
对比结果可以用下面这个思路来解释:
| 对比结果 | 通常意味着 |
|---|---|
| 两个工具同时发现 | 可信度高,优先做存活验证 |
| 只有Subfinder发现 | 检查Amass数据源是否跳过或额度耗尽 |
| 只有Amass发现 | 主动模式或特定数据源覆盖的深层子域 |
现实中这两个工具的差异我见过很多次。有一次Amass靠主动解析找到了一个老子域,Subfinder所有被动源都没有收录;也有一次Subfinder借助某个API的缓存记录反超Amass。所以不要迷信单一工具,交叉验证才是把误报和漏报同时降下来的办法。
3.4 接续探测:把域名清单变成活资产
拿到合并去重后的子域清单,还只是资产测绘的第一步,因为清单里的域名可能包含已失效、仅内网解析或早已下线的记录。我通常会把清单交给httpx做一轮存活探测,把状态码、标题、服务器、Web技术栈这些信息一起拿回来:
httpx -l all_subs.txt -silent -status-code -title -web-server -tech-detect -o live.txt说明一下,httpx这里没有做任何漏洞扫描动作,只是HTTP/HTTPS存活探测和指纹识别。在这个环节之后,才会根据授权范围决定要不要继续做端口扫描或模板扫描。整个链路是“子域发现→存活验证→指纹识别→风险评估”,Amass和Subfinder负责第一步,后面的工具负责把第一步的清单转化为可决策的信息。
4. 常见问题与排查技巧实录
4.1 Amass跑很久没有输出,不一定是死机
我先说一个最常见的误解:Amass默认输出是往标准输出画ASCII图形,很多人第一次跑的时候看到全程没反应,以为卡死了。其实它可能在正常收集数据,只是没有把进度打到你预期的地方。我的建议是:只要结果需要给下游工具用,就明确指定-json输出文件,不要盯着屏幕上那几张图。
如果确认Amass运行异常慢,排查顺序是这样:
- 看配置文件路径是否生效。最稳的做法是用
-config显式指定,不要依赖默认路径。 - 看API配额是否耗尽。配额不足时数据源会等待超时,表现就是卡住。
- 看是否需要设置
-timeout,避免某些数据源长时间不响应。 - 先拿一个只有两三个子域的小目标跑通流程,再切换到正式目标。
大目标第一次跑耗时很长是正常的,我在一次企业级资产梳理任务里,Amass被动模式跑了将近四十分钟。关键是不要让无效等待浪费你的时间,该设超时就设超时,该加日志就加日志。
4.2 Subfinder结果偏少的常见原因
Subfinder的一个特点是你配置有问题也不影响命令跑通,这反而会掩盖问题。结果偏少时,我一般按下面几步排查:
- provider配置是否生效。用
-pc显式指定配置文件,或者先确认默认路径下的yaml能被正确读取。 - 有没有加
-all。默认只使用一部分不需要认证的源,加了-all才会尝试所有已配置的源。 - API key是否写错或额度用完。我遇到过把多个key塞进同一个列表项导致yaml解析失败,Subfinder会直接跳过整段配置。
- 网络问题导致部分源超时。可以用
-timeout 30配合-max-time 120把总耗时控制住,至少不会干等。
我排障时习惯先用一个小域名跑带-all的命令,再跑默认命令,对比结果量。如果两者差异极大,说明配置源基本没生效;如果差异不大,说明你配的源本身就不多,这时候可以考虑补充更高质量的数据源。
4.3 合并去重时的格式陷阱
前面提过末尾点和大小写问题,这里再说一个更隐蔽的:通配符记录。有些数据源会把*.example.com这样的记录混进来,它不是真实存在的子域名,而是泛解析配置的体现。合并后的清单需要过滤掉带星号的条目,一行命令就能解决:
grep -v '^\*\.' all_subs.txt > for_dedupe.txt但要注意,像_dmarc.example.com这样的TXT记录专用名不算通配符,它虽然不能当Web资产访问,但它在DNS层面确实存在。是否保留取决于你的目的:我做资产台账时会保留,做Web资产存活验证时会交给httpx自己判断。
还有一个跟DNS解析相关的陷阱:同一个域名在不同网络环境下解析结果可能不同,尤其内网域名。所以在做跨环境比对时,不要把A环境的解析结果当作另一环境的标准答案,最好在目标环境内重新验证。
4.4 限制速率与授权测试注意事项
无论跑哪个工具,我都建议先想清楚目标边界。主动模式会真实触达目标基础设施,如果不加控制,大规模并发请求会让对方的DNS服务器收到明显流量,既影响业务,也容易被安全设备记录。Subfinder被动模式相对温和,但配置了API key后,它会频繁请求第三方API,也要注意API本身的调用频次限制。Amass的active模式要重点看-max-dns-queries这类参数,宁可多等一会儿,也不要把并发拉满。
更重要的一条:这些工具只应该用在你有明确授权的目标上。我个人习惯是每个任务开始前先更新一下授权资产清单,把允许测试的域名写进一个目标文件,再交给工具去跑。这样既能防止手滑,也能保证所有操作都有据可查。做这行时间越长,越会明白“能力边界”比“技术上限”更值得关注。
如果你已经看到这里,大概率也在规划自己的资产发现流程。我可以分享一个我目前比较稳定的节奏:每周一用Subfinder跑一遍全部授权域名的被动底表,周三让Amass用passive模式慢慢补,周五合并去重后交给httpx做存活验证。这样既不追求一次跑完,也不至于让旧数据过期太久。工具组合用下来,最大的体感不是某个工具多强,而是两个视角互相补盲后,资产清单从“大概全”变成“知道哪里还有漏”。最后一个小提醒:Amass跑大目标时优先输出JSON而不是默认的图模式,机器内存小的情况下差别非常明显。