子域枚举这种活看起来不难,实际跑起来却特别考验工具链的整合能力。Anubis这名字听着比较硬核,本质上就是一个聚合型的子域发现工具,它会把多个被动数据源拉回来的记录汇总、去重、再到DNS层面做校验,最后输出一份相对干净的子域清单。可这里有个很现实的分水岭:不配API密钥,Anubis跑出来的结果只是“基础班”,很多数据源会被跳过,关键信息明显缩水;把Shodan的API密钥配好之后,同一批域名的输出可能直接带上端口状态、服务横幅、组织归属这类额外信息。这篇配置指南就讲三件事:环境安装与验证、Shodan密钥如何正确塞进Anubis、以及拿到密钥后怎么把Shodan的额外信息榨出来。适合正在搭自己侦察工具箱的人,也适合单纯想搞清楚“API密钥到底在哪一步生效”的同学。
1. 先搞清楚Anubis在那一环:子域枚举与API密钥的定位
1.1 Anubis到底解决什么问题
子域枚举是资产管理、安全巡检、信息收集里非常常见的一步,思路基本分成两派。一派是暴力枚举,拿一个大字典对着目标域名不停地发DNS查询,猜子域名;另一派是被动聚合,不去猜,而是从证书透明日志、历史DNS记录、第三方情报库这些地方把已经出现过的子域名找出来。
Anubis属于典型的被动聚合加校验思路。你给它一个主域名,它负责调用多个数据源接口,把每个角落里出现过的子域记录捞回来,然后去重、合并、解析。这和你手动一个接口一个接口去请求完全不一样,它把这些动作封装成了一个并发管道,省掉的不是一点半点的时间。
用一个生活化类比来说:暴力枚举就像挨家挨户敲门问“你这里是不是叫某某某”,而Anubis这类被动聚合工具更像是查商会登记簿,先看看哪些名字已经被登记过。Anubis的价值在于它一次性帮你查很多本“登记簿”,并且自动处理了那些重复条目和已经失效的条目。所以它的适用人群很明确:需要快速梳理资产的人、做安全自查的人、或者单纯不想被DNS限速折磨的工程师。
1.2 没有API密钥时,Anubis会损失什么
这是很多人第一个踩坑的地方:以为工具装好就能拿到完整结果,实际跑完发现比自己手动查还少。
原因很简单,Anubis本身不完全是一个本地扫描器,它更像一个“数据源调度器”。很多数据源要靠API密钥才能返回完整数据,或者干脆没有密钥就不让你查。没有配置密钥时,Anubis会跳过那些需要密钥的接口,并留下警告日志,然后继续用其他公开数据源跑。表面上工具没报错,但结果清单已经被悄悄砍掉了一大块。
下表是典型的数据源与密钥关系,方便你理解“少哪个密钥,缺哪块料”:
| 数据源类型 | 没有密钥时的表现 | 配好密钥之后的改进 |
|---|---|---|
| Shodan | 子域发现能力明显受限,很多场景直接跳过 | 能把历史扫描中的主机名、解析关系带回来,还能反查主机服务信息 |
| 证书透明日志 | 公开日志通常不需要密钥 | 不受影响,属于公共数据 |
| 商业被动DNS/威胁情报 | 绝大多数只给极少量示例数据 | 返回完整记录,才能看到资产全貌 |
我在自己维护的测试域上做过一次对比。不配密钥跑,返回结果只有十几个子域名,里面还有几个早就不解析的僵尸记录。把Shodan相关密钥配上以后,同一域名下多出二十多条资产记录,有一部分是历史曾经解析过、现在已下线但还能从Shodan数据库里翻出来的,这种记录对追溯变更特别有用。
1.3 Shodan在数据链条里的位置
很多人把Shodan理解成“公网设备搜索引擎”,这个方向是对的,但它和子域枚举的关系值得再拆细一点。
Shodan提供两类对Anubis这类工具很重要的能力。第一种是按照域名反查它数据库里关联过的主机名,相当于它帮你保留了很长一段时间的DNS解析记忆。第二种是对已验证的IP调用主机详情接口,返回这个IP上有哪些端口在监听、跑的是什么服务、响应横幅是什么、证书信息、地理位置、ASN号等等。
这两类能力放到Anubis的使用场景里,效果就是:一个域名被解析成IP以后,你不仅能知道它是什么子域,还能知道这个子域对应的服务器到底对外暴露了什么。这比单纯拿一个域名清单要立体得多。端口开没开、中间件是什么版本、有没有暴露在公网的管理后台,这些才是后续判断风险时真正需要的信息。所以Anubis加上Shodan密钥,本质上是一种“发现加情报增强”的组合,一个是找名字,一个是看底细。
2. 准备环境与安装Anubis
2.1 环境需求与网络准备
安装Anubis没有太苛刻的要求,但几个前置条件还是要提前检查,否则后面跑的时候会出现来源不明的问题:
- 操作系统:Linux和macOS用起来最顺手,Windows也能跑,只是环境变量配置和命令行习惯会有差异。
- 软件依赖:如果你选择源码编译,需要Go 1.18以上版本和Git;直接下预编译二进制则不需要这些。
- 网络连通性:安装阶段能访问官方仓库就够了,但真正跑到Shodan数据源时必须能正常访问Shodan的API端点,这是一个容易被忽略的网络条件。
验证基础环境可以用下面几条命令,哪条报错就先补哪个:
go version git --version curl -I https://api.shodan.io前两条是为了确认编译环境,第三条是为了确认API网络路径通不通。别小看第三条,很多人密钥一直“不生效”,最后排查下来其实是公司网络或本地防火墙直接把对Shodan的请求拦了。
2.2 通过源码编译安装
如果你本机已经有Go环境,推荐直接源码编译,这样能保证拿到当前版本的最新代码,也方便在本地改一些关键参数。基本步骤是这样:
git clone <官方仓库地址> cd Anubis go build编译完成后,当前目录下会生成一个Anubis可执行文件。直接在当前路径运行或者把它放到系统PATH目录里都可以。
sudo mv anubis /usr/local/bin/ anubis --help源码编译最大的好处是你能随时切到最新分支重新编译,缺点则是需要自己处理依赖。如果出现依赖下载失败的情况,先检查Git配置和Go环境,再考虑换网络环境,不要一上来就改动源码。另一个细节是,不同版本的Go编译出来的二进制在行为上没有太大差别,但你至少应该保证主版本号在两位数以上。
2.3 用预编译二进制安装
如果你不想折腾Go编译环境,走预编译包是最快的路径。到官方发布页面下载对应当前系统的压缩包,常见的组合是linux_amd64、darwin_arm64这类命名,解压之后做三件事:
chmod +x anubis sudo mv anubis /usr/local/bin/ anubis --version这里必须提醒一句:下载任何安全类工具前,养成校验哈希的习惯。发布页面一般会附一个校验值,用sha256sum和发布页给出的值比对一下,确认你拿到的文件没被中间环节动过手脚。不要嫌这个步骤麻烦,安防类工具一旦被污染,后果远比多等一分钟严重。
2.4 跑一次无密钥安装验证
安装完成后不要急着配置密钥,先跑一次“无密钥状态”的扫描,目的是确认工具链路本身是通的。
anubis -t example.com这时你会看到Anubis开始调用各个数据源,日志里大概率会出现密钥缺失之类的警告。只要它最终能输出一些子域名,不管数量多少,都说明编译、环境变量、网络DNS解析这整条链路是正常的。接下来再去配置密钥,就不会把“工具坏了”和“密钥没配好”这两个问题混在一起排查。
3. API密钥设置:最容易出错但也最值钱的环节
3.1 申请一个Shodan API Key
Shodan的密钥入口在账户设置里面,注册一个普通账户就能看到。进入设置页后找到API Key区域,点一下显示完整密钥,复制出来就行。
这里有几个很实际的坑。第一,复制的时候看到密钥是一长串字符,很容易只复制前半段或把结尾的空格带进去,导致后面请求一直401。建议复制完先粘贴到文本编辑器里看一遍,确认首尾没有多余字符。第二,免费账户的查询额度非常有限,是按月计算的,不是个无穷大的数字。你在配置之前看一眼当前账户还剩多少额度,以免配置完一跑就撞上限。第三,不要把密钥贴在聊天工具里、截图发给别人,或者提交到代码仓库里。密钥泄露的代价是你自己的数据来源被薅,严重时候账户会被直接封掉。
3.2 Anubis读取密钥的机制
Anubis本身不是一个需要登录的云服务,它读密钥靠的是环境变量。你可以把环境变量理解为操作系统发给每个进程的一张“纸条”,进程启动时去读纸条上写的内容,拿到之后就用自己的逻辑去调用对应数据源。
具体变量名在不同版本里可能略有差异,但常见形式是SHODAN_APIKEY这种命名风格。之所以强调“以官方文档为准”,是因为有一些修改版或二次开发分支改了变量名,你照着网上的老教程配了半天,其实变量名早就变了。最稳妥的方法是在安装完成后先运行一次:
anubis --help帮助信息里通常会列出它支持的环境变量名称或相关参数。看到准确名字之后再去配置,就能避免“密钥其实生效了,但Anubis读的是另一个变量名”这种尴尬情况。
3.3 把密钥写入环境变量:Linux、macOS与Windows实例
Linux下临时生效的方式是在当前终端会话里执行:
export SHODAN_APIKEY="your-shodan-api-key"但这种方式只对当前终端窗口有效,关掉就没了。更常见的做法是写进shell配置文件里,让每次打开终端都能自动加载。
echo 'export SHODAN_APIKEY="your-shodan-api-key"' >> ~/.bashrc source ~/.bashrc如果你用的是zsh,文件名要改成.zshrc,命令结构一样:
echo 'export SHODAN_APIKEY="your-shodan-api-key"' >> ~/.zshrc source ~/.zshrcWindows用户可以用setx把密钥写进用户环境变量:
setx SHODAN_APIKEY "your-shodan-api-key"但setx只影响新开的终端窗口,当前窗口里需要手动设置一次才能立刻生效:
$env:SHODAN_APIKEY = "your-shodan-api-key"写配置文件时有几个禁区要注意。不要在命令行里给密钥加多余的单引号,不要用中文输入法输入引号,也不要在密钥字符串里塞换行。看似小得不能再小的事,真能让人排查半天。
3.4 用包装脚本管理密钥,避免污染Shell
环境变量配置虽然方便,但把密钥明文写进.bashrc或.zshrc,总有种“裸奔”的感觉。我自己更推荐一种做法:把密钥单独放在一个只有自己能读的文件里,然后用一个包装脚本来加载它。
比如先在本地建一个密钥文件:
mkdir -p ~/.secrets echo -n 'your-shodan-api-key' > ~/.secrets/shodan_key chmod 600 ~/.secrets/shodan_key然后写一个启动Anubis的脚本:
#!/usr/bin/env bash export SHODAN_APIKEY="$(cat ~/.secrets/shodan_key)" exec anubis "$@"这样密钥不暴露在全局配置里,也不会出现在终端历史记录中,脚本本身还可以自由切换不同的密钥文件。对经常在多个工作区切换的人来说,这种方式的体验比清空一堆export命令舒服得多。
3.5 如何确认密钥已经生效
配置完之后,先不要急着跑整段Anubis扫描,先用Shodan自己的轻量接口验证密钥是否可用:
curl -s "https://api.shodan.io/api-info?key=${SHODAN_APIKEY}"如果返回一段包含账户信息的JSON,说明密钥没问题,网络也通。接着再跑一次Anubis:
anubis -t example.com观察日志里是否还有“shodan key not provided”之类的提示。没有这类提示,说明Anubis已经读到了密钥。如果你还想进一步确认Shodan侧的解析数据能否正常返回,可以直接调用Shodan的DNS域名接口:
curl -s "https://api.shodan.io/dns/domain/example.com?key=${SHODAN_APIKEY}"能返回子域名列表,说明密钥、网络、数据源三方面全部就绪,这时才算真正进入“带着额外信息干活”的阶段。
4. Shodan额外信息获取:把子域变成“会说话的主机”
4.1 哪些算Shodan额外信息,为什么值得看
很多人把Anubis跑完的输出当成终点,实际上那只是起点。Anubis给你的是“哪些域名存在”,而Shodan能告诉你“这些域名对应的主机上到底跑着什么”。这两种信息的价值差别非常大。
下面这些字段就是典型的Shodan额外信息:
| 信息类型 | Shodan返回字段示例 | 使用价值 |
|---|---|---|
| 端口列表 | data[].port | 快速判断暴露面,看到22、3306、6379就知道运维暴露面不小 |
| 服务与产品 | data[].product, data[].banner | 确认中间件类型和版本,比如nginx、OpenSSH、Redis |
| SSL证书 | data[].ssl | 判断证书重用、能否关联同一主体的其他域名 |
| 组织与ASN | org, asn | 帮助资产归属梳理,方便区分自建机房和云上资产 |
| 地理位置 | city, country | 判断服务部署分布,有时候直接暴露区域运营情况 |
把这些字段和子域清单合在一起看,就能从“我有一堆域名”升级到“我知道这堆域名里哪些开了公网数据库、哪些证书快过期、哪些服务已经暴露在公网上”。对于安全自查和资产管理场景,这几乎是刚需。
4.2 基础工作流:从Anubis结果反查Shodan Host API
我日常用的流程可以分为四步,每一步都很简单,但组合起来效率很高。
第一步,用Anubis枚举子域并规整成干净的清单:
./anubis -t example.com > raw_subs.txt awk '{print $1}' raw_subs.txt | sort -u > subs.txt第二步,把子域批量解析成IP。这里用了dig,Windows环境可以换成nslookup:
while read -r d; do ip=$(dig +short "$d" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -n1) if [ -n "$ip" ]; then printf "%s %s\n" "$d" "$ip" fi done < subs.txt | sort -u > resolved.txt第三步,对每个IP调用Shodan的Host API,返回结果存成JSON文件:
while read -r d ip; do curl -s "https://api.shodan.io/shodan/host/${ip}?key=${SHODAN_APIKEY}" > "shodan_${ip}.json" sleep 1 done < resolved.txt第四步,把JSON汇总成一张简洁的TSV表,方便直接打开查看:
jq -r '[.ip_str, (.hostnames | join(",")), ([.data[].port] | unique | join(",")), .org] | @tsv' shodan_*.json > shodan_report.tsv这套工作流看起来普通,但实际执行时会省掉你大量手动复制粘贴的时间。十几二十个IP跑完,一张表就出来了,哪个IP开了什么端口、属于哪个组织一目了然。后续要拿去做告警、做趋势对比,都方便。
4.3 在Shodan侧交叉搜索子域的进阶用法
除了按IP反查,Shodan还有几个接口和搜索语法值得叠加使用。
第一种是直接用于域反查。Shodan的DNS解析接口能返回一个域名下它数据库里存在的子域名记录,虽然和Anubis的数据源有重叠,但它是独立情报,拿来做交叉验证很靠谱:
curl -s "https://api.shodan.io/dns/domain/example.com?key=${SHODAN_APIKEY}"第二种是使用Shodan搜索语法做面态搜索。你可以用hostname:example.com去搜所有出现过该主机名的历史记录,从中发现那些没有在常规子域枚举结果里出现的老资产。注意这里的返回结果会消耗搜索积分,不要一次性拉太多页。
第三种是结合SSL证书做资产关联。拿到某个IP的SSL证书信息后,再用ssl.cert.subject.cn:example.com这种语法反查同证书下的其他域名。这个方法在找同一主体多个业务系统时特别管用,经常能带出一些没被公开DNS覆盖到的内部域名。
这三种方式没有一个需要额外装其他工具,全靠Shodan API和一点脚本组合,属于“信息收集技巧”里性价比很高的一类。
4.4 批量操作时的配额与限速策略
Shodan的免费配额不多,批量反查IP时一定要有“配额预算”的概念,否则跑到一半弹401很扫兴。每个Host API请求通常都会消耗一次查询额度,所以不要写那种毫无节制的循环。
建议做法是:先跑一批,存下来,观察额度消耗速度,再决定要不要继续。脚本里加一个跳过逻辑,已经拉过的IP不再重复请求:
[ -f "shodan_${ip}.json" ] && continue同时给请求加一个轻量延时,比如一秒。这不光是为了照顾免费配额,也是避免触发服务端限速。服务端返回429 Too Many Requests时就说明你已经太急了,这时可以退避几秒再继续。把结果全部落盘到本地还有一个好处,就是后面重新分析数据不用再去请求API,既不花钱又省时间。
这个阶段最重要的原则是“先落盘再分析”。不要边请求边管线输出,一旦中间断网,前面拿到的数据就全丢在了内存里,又要重新花钱去拉一遍。
5. 常见问题与排查步骤实录
5.1 密钥看起来没生效,日志还在警告
这个问题在论坛里出现频率最高,我几乎每次帮人看都会先查环境变量。
先确认当前终端确实有变量:
env | grep SHODAN没有输出就是变量没加载,或者变量名不对。接下来分两种情况处理。如果刚改过配置文件,先执行source刷新当前的shell环境;如果是在一个终端里export了密钥,又打开另一个终端跑Anubis,那另一个终端自然读不到,必须在同一个终端会话里运行。
还有一种隐蔽的情况是使用了sudo。默认sudo会清掉大部分环境变量,即使你的shell里有SHODAN_APIKEY,sudo之后Anubis也看不到。解决办法是用sudo -E把当前环境变量保留下来,或者干脆把环境变量加载逻辑写进Anubis的启动脚本里,再用sudo执行脚本。
5.2 API返回401或403
如果你手动curl请求Shodan接口,收到401,那说明提供的密钥本身有问题。先检查密钥字符串是否完整、有没有多余空格、是否复制错了一个相似字符。如果用文本编辑器看着没问题,那就直接去Shodan设置页重新复制一遍再试。
收到403的情况,大概率是配额受限。许多时候不是你的网络问题,也不是Anubis问题,纯粹是免费账户当月的查询额度已经烧完。登录Shodan网页看账户信息页,里面会明确显示剩余配额。如果额度耗尽,要么等下一个周期重置,要么升级付费方案。至少我的经验里,90%的403都出在这个环节,跟“被墙”没有关系。
5.3 请求返回“No information available”
这个不是错误,而是Shodan数据库里确实没有该IP的扫描记录。常见原因有三类:IP是私网地址,Shodan不会收录;IP太新,扫描周期还没轮到;或者目标IP属于Shodan尚未覆盖的偏远IDC。
处理方式也很简单,先不要急着认定主机不存在。换个角度想想,也许是解析到了一个CDN或负载均衡节点,真实源站IP根本不在这个地址上。你可以把过滤私网地址和回环地址作为前置条件:
grep -vE '^(10\.|127\.|192\.168\.|169\.254\.|172\.(1[6-9]|2[0-9]|3[0-1])\.)' resolved.txtCDN节点本身也有攻击面分析的必要的,但它和真实源站的性质不一样,分开维护会更清楚。
5.4 Windows环境变量不生效
Windows上最常见的问题是setx操作完成后,当前PowerShell窗口里还是不行。原因很简单,setx只影响之后新开的进程,当前窗口不会自动同步。你可以在同一个窗口执行:
$env:SHODAN_APIKEY = "your-shodan-api-key"或者直接关掉终端重新开一个。还有一个隐蔽问题是有些终端会在后台缓存环境变量,即使setx成功,旧的会话树里跑起来的进程也读不到新值。遇到这种情况,重启一次终端软件是最快的解决办法。
5.5 输出文件重复或半截JSON
批量循环时如果中途Ctrl+C,正在写入的那个JSON文件很可能只写了一半,后续脚本读到它时会报解析错误。建议在脚本开头做一个“清理半成品”的动作:
find . -name "shodan_*.json" -size -200c -delete小文件大概率是空响应或半截内容,删掉再重新跑即可。另一个经验是存储文件名不要只叫shodan_${ip}.json,最好把日期也加进去,比如shodan_${date}_${ip}.json。这样每天跑一次也不会互相覆盖,历史对比时才能找出“哪天开了新端口”这种细节信息。
5.6 常见问题速查表
把上面这些经验整理成一张表,方便你在遇到问题时直接对号入座。
| 现象 | 可能原因 | 快速解法 |
|---|---|---|
| 跑Anubis时仍提示密钥缺失 | 环境变量没加载,变量名不对,或sudo清掉变量 | 检查env输出,重新source,改用sudo -E |
| curl请求返回401 | 密钥复制错误、多了空格 | 重新复制密钥,确认首尾干净 |
| 请求返回403 | 免费配额用完、账户受限 | 查看Shodan账户额度,等重置或升级 |
| 单个IP返回Not Available | Shodan没收录该IP或IP是私网地址 | 查证真实IP,过滤私网地址,换时间再试 |
| Windows环境变量无效 | setx只对新窗口生效 | 新开窗口或手动设置当前窗口变量 |
| JSON半截无法解析 | 中断写入导致文件损坏 | 删除小于200字节的半截JSON再重跑 |
6. 使用边界与实操心得
6.1 边界意识比跑多快更重要
工具用起来顺手之后,很容易让人产生“到处跑一下试试”的冲动,但这里有一条非常清晰的分界线:只对自己有权限、有授权、或者自己负责维护的域名做枚举和查询。子域枚举和Shodan查询本质上属于信息收集手段,本身没有对目标发起攻击,但未经授权去大量扫描别人的资产,于情于理都不合适。
我自己的做法是,在配置Anubis的同一台机器上维护一份“授权清单”,只有清单里的域名才允许跑扫描,不在清单里的直接不碰。这不是增加麻烦,而是让整个工作流程有据可依。安全研究的前提是明确边界,一旦踩线,再熟练的手段也会变成麻烦。
6.2 把整个流程固化成可重复执行的脚本
手工执行四步命令解决一次问题很舒服,但如果你每周都要做一次资产巡检,就要考虑把这套流程固化成脚本。
一个简单的启动脚本结构大概是这样:先加载密钥文件,再跑Anubis枚举,解析IP,调用Shodan API,最后生成报告。整个过程输出到一个带日期的目录里,日志单独存放,方便回溯。
由于我在本地已经验证过,这个脚本跑下来基本能稳定输出几十个资产记录。哪怕中间有一个API接口临时不可用,脚本也会跳过失败项继续往下走,等跑完再集中看错误日志。这样做的收益不只是省时间,更重要的是可重复。你可以在下周复制同样的命令,生成第二份报告,然后和这周的报告比对。哪些子域名消失了,哪些IP新开了高危端口,一对比就全部暴露出来。
6.3 最后分享一个很小的经验
Shodan返回的数据本质上是一个历史快照,它体现的是“某个时间段内,这台主机在公网上呈现过这些端口和服务”,不代表当前时刻的实时状态。所以你在引用这些数据做结论时,一定要记得标注数据日期,不要把一个上周的端口信息当成今天的暴露面来汇报。
我自己第一次用Shodan增强报告时,就差点闹过这个乌龙。看到某个子域名对应的IP上开着很多端口,正准备写进当天报告,后来仔细查了才明白这个记录是两个月前的。后来我在所有生成报告的脚本里都强制加上时间戳,数据是哪天的,结论就覆盖到哪天,不准模糊处理。信息收集最怕的不是数据不够,而是把旧数据当成新事实。