搞安全评估这些年,我一直觉得“信息收集”这个词被说小了。很多人以为它就是把端口扫一遍、目录跑一遍,然后拿着报告去交差。实际上,在我经历过的授权测试里,八成的突破口都不是靠某个攻击工具打出来的,而是靠“多收集到的那一层信息”自然生长出来的——多到的那个子域名可能带出一套旧测试系统,多到的那个指纹可能直接告诉你后台用的什么框架,多到的那份源码泄露可能把数据库口令摊在你面前。所以这篇东西我不打算罗列工具清单,而是把子域名、端口、指纹、目录、源码泄露、人员信息这六个维度串成一条完整的行动线,讲清楚每一步为什么做、怎么做、最容易在哪里翻车。
这篇内容适合正准备做一次系统性的授权安全评估的朋友,也适合运维侧想把自己业务“摸清楚”的同行。我不多说理论,尽量给可以直接复用的命令、参数和踩坑记录。
1. 先说思路:信息收集到底在收什么
1.1 六个维度是“漏斗”,不是一份清单
网上很多文章会把信息收集拆成十几个并列模块,看着很全,但真正做项目时你会发现,这六个维度其实是一条漏斗链路:先从域名打开,拿到一批子域名;子域名解析出IP,IP上扫出一堆端口;端口背后跑着不同服务,服务的特征形成指纹;有了指纹就能判断接下来该挖目录还是看源码;源码泄露能直接带出配置和人员信息。层层收窄,一步一步靠近核心资产。
我个人的习惯是把这个漏斗画在笔记里,哪怕不画图也要在脑子里过一遍。比如你拿到了一个域名,第一步不是急着用扫描器,而是先问:它有哪些子域名?子域名里哪些解析到云资产、哪些解析到内网映射?这些IP上开了哪些端口?端口上的服务版本是什么?只有顺着这个顺序往下走,后面每一步才不会被噪声干扰。
还有一个容易忽略的点:目标范围会直接影响你该收集到哪一层。如果授权范围写的是单个IP,那子域名收集意义就不大,直接进入端口和服务识别。如果范围是一整个域名,那子域名就必须做全。很多人一上来就把甲方给的域名丢进字典爆破,结果客户主域名做了CDN,扫到的全是CDN节点,报告写得再厚也没有实际参考价值。
1.2 必须放在开始前的边界问题
这一段我必须先写,因为信息收集本身是一把双刃剑。任何一个扫描器、目录枚举工具、源码下载脚本,都有可能对目标造成不可逆的影响,无论是产生大量请求把业务打挂,还是把不该下载的敏感文件拉下来。所以无论你是什么身份,动手之前一定要确认三件事:一是有没有拿到书面授权;二是授权范围是不是覆盖你即将扫描的IP和域名;三是测试时间窗口是否允许高强度扫描。没有授权的信息收集就叫非法入侵,这一点没有商量余地。
后面我写的所有命令和方法,默认都只用于你拥有合法测试权限的资产,或者你自己搭建的靶机环境。做安全评估和搞破坏的区别,往往就在这条边界上。
2. 子域名:从入口到更多入口
2.1 子域名的三种来源
子域名收集不是靠单一手段就能做全的,我通常会分成三类来源交叉验证。
第一类是证书透明度日志。这是最稳定、最省力的来源,几乎所有HTTPS站点都会给域名签发证书,而证书签发记录会公开保存在日志服务器里。只要查一下某个根域名下的证书记录,就能看到历史上所有申请过证书的子域名。这个方法的优点是覆盖面广,很多年代久远、已经下线但仍解析到资产的子域名都能翻出来,非常适合用来找“被遗忘的入口”。
第二类是DNS主动枚举,也就是大家常说的爆破。通过字典生成一批可能的子域名前缀,然后逐个查DNS解析记录。这个办法的覆盖率完全取决于字典质量,所以我会把通用字典和从目标官网、招聘信息、代码托管平台里提取的关键词结合起来,效果会比单跑一个通用字典好很多。
第三类是被动搜索,包括通过搜索引擎、代码搜索平台、网盘、历史快照等渠道收集已经被公开记录过的子域名。这类来源经常能捡到一些人已经提交在公开页面上的内部地址,价值往往比爆破来的更高。
2.2 用证书透明度日志批量捞子域名
这里给一个最直接的查询方法,我平时几乎不打开浏览器去翻证书平台页面,都是用命令行拉下来处理。以目标域名target.test为例:
curl -s "https://crt.sh/?q=%25.target.test&output=json" | jq -r '.[].name_value' | sort -u注意这个命令里%25是URL编码后的通配符%,含义是匹配所有*.target.test的证书记录。输出结果会包含形如a.target.test、b.target.test的记录,也可能带上一些重复或带通配符的记录,需要再清理一下。我一般会配合sed把*.target.test这类通配符记录里的星号去掉,只保留实际子域。
拿到这批结果之后,最重要的不是整理成表格,而是立刻做一次“存活确认”。很多证书记录对应的子域名早就删除了解析记录,直接扫会浪费大量时间。确认存活最快速的办法是用批量解析工具,也可以写一个简单的循环调dig:
while read sub; do if dig +short "$sub.target.test" | grep -q '[0-9]'; then echo "$sub.target.test" fi done < sub_list.txt2.3 子域名防误报的几个细节
关于“ip子域名大全”这类检索词,网上确实有很多整理好的大字典,但我的体会是,字典可以当概率参考,不能直接当结论用。实际环境中,泛解析是最大的误报来源。有些DNS服务商为了防盗爬虫,会把所有不存在的域名统一解析到一个相同IP上,比如不管输入xxx.target.test还是yyy.target.test,返回的IP都是同一个。这时候如果你不做IP去重,扫报告里会混进一大片根本不存在的“子域名”。
所以我在子域名确认阶段会做两步过滤:第一步看解析出来的IP是否完全相同,如果一批域名指向的是同一个IP,就得怀疑泛解析;第二步对解析结果做历史对比,如果某个子域名在证书日志里出现过,但现在已经不再解析到任何IP,那大概率已被下线。
另外一个容易被忽略的点是子域名接管漏洞。当你发现一个子域名解析到了某个第三方服务商(比如对象存储、代码托管页、CDN服务),但对应的存储桶或资源已经被释放,那么攻击者可以直接重新注册这个资源,从而获得这个子域名的控制权。收集阶段如果发现这类解析记录,我会单独标记出来,这比直接写进“子域名列表”重要得多。
3. 端口与服务:把“门牌号”扫明白
3.1 为什么要做全端口
很多刚开始接触扫描的朋友喜欢只扫个默认前1000个端口,结果报告里就只见80、443、22这几个常见口,看起来干干净净。但真实业务环境里,真正有意思的服务往往藏在高位端口。比如某些公司把测试环境的Web页面挂在8080或8888,把内部代码仓库挂在8443,把数据库运维面板挂在随机高位端口。如果只扫常用端口,这些全部会漏掉。
我平时做端口扫描会分成两轮。第一轮只做全端口开放探测,目的是搞清楚目标IP上一共开了哪些端口,这个阶段不做服务识别,保证速度。第二轮再针对第一轮发现的端口做详细的版本探测和脚本扫描。这样做的好处是,第一轮压力小、速度快、不容易被误判为高频攻击;第二轮有了明确的端口清单,可以慢慢地、细致地识别服务,不容易漏报。
3.2 高效且稳妥的 Nmap 扫描命令
Nmap 是端口扫描绕不开的工具,但很多人只是习惯性地用nmap target,这还远远不够。给你一套我实测下来比较顺手的组合:
# 第一轮:全端口发现,只探测开放状态,不做版本识别 nmap -sS -Pn -n -p- --min-rate 1200 -T4 192.0.2.10 -oA full_port # 第二轮:对已发现端口做服务识别和默认脚本 nmap -sS -Pn -n -sV -sC --version-light -p 22,80,443,8080,8443,9090 192.0.2.10 -oA service_scan这里每个参数都有它的意义,逐个说明一下。-sS表示SYN半开扫描,速度快、相对不容易在目标系统上留下完整连接记录,但在没有root权限的某些环境会失败,那就得换成-sT全连接扫描。-Pn表示跳过主机存活探测,因为很多服务器会屏蔽ICMP报文,你不加这个参数,明明端口开着也会被判断成主机“不可达”。-p-表示1到65535全端口,--min-rate控制发包速率,不能一味求快,否则容易触发目标机房的风控。第二轮里的--version-light是让Nmap在版本探测阶段适度降低耗时的选项,适合端口数比较多的时候用。
我自己在实战里很少一上来就加-A,因为-A会把操作系统指纹、版本探测、默认脚本全部打开,单个目标还行,一旦端口多就会慢到怀疑人生。第二轮已经知道端口范围了,再针对性地带上脚本才是效率最优解。
3.3 常见服务的默认端口要心里有数
不管扫描器多智能,你要是不知道目标服务常用的默认端口,扫出来一堆数字也看不出重点。这里列一个我经常对照的表,都是实际环境里非常容易踩到的高频服务:
| 服务类型 | 默认端口 | 备注 |
|---|---|---|
| Web HTTP/HTTPS | 80 / 443 | 也可能藏在任意高位端口 |
| SSH / RDP | 22 / 3389 | 常见远程管理入口 |
| MySQL / PostgreSQL | 3306 / 5432 | 数据库服务,一般不对外 |
| Redis | 6379 | 未授权访问高发端口 |
| Elasticsearch | 9200 / 9300 | 9200为HTTP接口 |
| Kibana | 5601 | 可视化面板 |
| Jenkins | 8080 | 很多构建系统会暴露 |
| Nacos | 8848 | 注册中心,配置文件易泄露 |
| Docker | 2375 | 未加密的Docker远程API端口 |
| HBase | 16010 / 9090 / 9095 | 16010是HMaster Web UI,9090为客户端接口 |
| MLflow | 5000 | 机器学习平台实验管理界面 |
有些服务还会把端口写成参数,比如常见授权管理软件的SNL服务默认端口是25734,这类业务端口通常不会出现在标准的“常用端口”表里,但只要你在目标的主机名或证书信息里看到相关软件名称,就可以反查对应的默认端口。端口和服务永远要配套着看,单独记端口意义不大。
3.4 端口被占用怎么查才是真需求
这个点本来跟信息收集关系不大,但我发现很多运维朋友搜“端口被占”“端口被占用”是卡在了部署这一步。当你往一台机器上部署新服务时,如果报错提示端口被占用,就要先找出占用进程。Linux下的命令很直接:
ss -ltnp | grep ':8080' lsof -i :8080Windows上则是用netstat -ano | findstr :8080拿到进程PID,再去任务管理器里确认是什么程序。还有一种更隐蔽的情况是端口看起来没有被占用,但进程始终起不来,这时候大概率是SELinux或系统防火墙拦截了监听动作,需要去确认TCP端口的策略配置。做信息收集的时候,偶尔也会遇到目标机上防火墙不响应、端口扫不出来的情况,排查思路同样要从“服务是否真的在监听”“防火墙是否放行”“云安全组是否允许来源IP访问”这三层去查。
4. 指纹识别:让服务现出原形
4.1 指纹信息从这些地方来
端口扫出服务之后,下一步就是搞清楚服务到底是什么、什么版本、有没有已知的历史漏洞。这个过程叫指纹识别。
最基本的指纹来源是HTTP响应头。比如Server: nginx/1.20.1直接就告诉你Web服务器类型和版本,X-Powered-By: PHP/7.4.33又给你一层应用语言信息。这些头字段不一定每个站点都有,也不是每个管理员都会清理,所以只要响应头里泄露了版本,就必须记进笔记。
然后是页面内容和路径特征。不同框架有自己独特的登录页面结构、Cookie名称、静态资源目录名。比如某些Java框架的管理后台默认会带有特定框架的版本号和启动横幅,某些CMS系统在登录页HTML注释里会留下生成工具的标记。这些特征不需要把服务跑一遍,只要用浏览器或curl看一眼源代码就能发现。
4.2 favicon 哈希:一个隐蔽的指纹特征
很多工具和文章已经响应了“指纹”这个热词,但我想重点讲一个不太起眼却很稳定的特征:网站小图标,也就是favicon.ico。很多站点会直接用框架自带的图标,或者只是改了名称没改图标,导致图标文件的哈希值和大量同类站点完全一样。只要算一次哈希,就能用在线指纹库反查它属于哪套系统。
计算favicon哈希最经典的办法是用Python,代码很短:
import requests import codecs import mmh3 url = "http://target.test/favicon.ico" r = requests.get(url, timeout=5) data = codecs.encode(r.content, "base64") hash_value = mmh3.hash(data) print(hash_value)这里用到的mmh3是MurmurHash算法的Python库,安装一下就能用。算出来的数字可以直接在网上的指纹聚合平台里搜索,很多开源Web框架、中间件、物联网设备的默认图标都在数据库里。我实测下来,这个方法对识别那些“隐藏了后台入口”的默认系统特别好用,因为普通目录爆破可能爆破不到根路径,但favicon.ico很多系统都懒得改。
4.3 指纹识别常见的两个坑
第一个坑是版本误判。响应头里的版本号不一定安全,很多系统会故意把版本信息抹掉,或者反向伪造一个假版本,试图误导扫描者。不能只看一个特征就下结论,至少要有两个以上的特征互相印证,比如响应头关联路径特征、页面关键字关联Cookie名称,才能把版本确定下来。
第二个坑是概念混淆。有人说“指纹浏览器”,这和Web应用指纹识别完全是两回事。浏览器指纹是通过读取浏览器的UA、屏幕分辨率、Canvas绘制特征、时区、字体列表等参数来唯一标识一台设备的技术,通常用在反欺诈和防止批量注册场景中,跟安全测试里的“指纹识别”不是一个维度。遇到术语的时候要先分清语境,否则一讨论就容易鸡同鸭讲。
5. 目录与源码泄露:把隐藏路径和泄漏点一起找出来
5.1 目录爆破怎么爆才高效
目录爆破,本质上就是拿着字典去“猜”站点上有哪些隐藏路径。它的速度不慢,但效率差别很大。核心变量有两个:字典质量、响应分析方式。
字典质量直接决定你猜中的概率。我会把字典按场景拆成几类:通用路径字典、备份文件字典、API路径字典、技术栈专属路径字典。比如目标是常见的PHP站点,你就会需要在字典里带上/admin、/backup、/uploads、/config、/.git这些高频路径;如果技术栈是某个特定框架,就要补充对应框架的路由风格,很多时候框架自带的/actuator、/console、/panel这类路径比通用字典里的路径更有效。
响应分析是很多人容易忽略的地方。我见过有人爆破目录只看HTTP状态码,200就留着,404就丢,结果把大量有实际价值的302跳转、403权限目录、405方法不允许全丢了。正确做法是先看全部的响应状态,再把明确的404过滤掉,对剩下所有状态码都做人工确认。推荐用这个思路的命令:
ffuf -u http://target.test/FUZZ -w paths.txt -mc all -fc 404 -rate 30 -t 10-mc all是要求显示所有状态码,-fc 404是过滤掉确定的404,后面的-rate和-t用来控制并发,避免打爆目标。
5.2 响应码语义与403细节:别被假目录骗了
目录爆破结果里,有几类状态码特别值得琢磨。
301和302代表目标路径存在跳转,要顺着跳转地址继续跟进,因为有些后台入口会从/admin跳到/admin/login,也可能跳到另一个域名。403代表路径存在但被禁止访问,这类路径很多人直接忽略,但它恰恰可能是真正的敏感文件或管理目录,只是当前访问方式不对。500和405也不该直接丢,前者可能代表参数触发了逻辑错误,后者说明路径存在但方法不允许,往往需要换POST或PUT再试。
关于“目录深度”,我多说一句。爆破的时候字典覆盖深度很重要,但盲目追求深层目录没有意义。实际业务里,三层以内的目录概率远大于更深层目录。我会把字典分成普通深度和深层两部分,先跑浅层,如果发现某个路径下出现了动态参数,再针对该目录做更深一层的爆破,这样比一次性跑一个超级大字典更稳妥也更高效。
5.3 .git 源码泄露的原理与下载方式
“git目录泄露如何下载”是个非常经典的问题。原理其实很简单:如果开发者在部署时把整个.git目录原封不动传到了Web根目录,而Web服务又允许直接访问以点开头目录里的文件,那么任何人都可以直接访问http://target.test/.git/HEAD查看Git仓库的核心结构。看到这里返回ref: refs/heads/master或者类似内容,就说明源码仓库暴露了。
仅仅确认还不行,真正要做的是把整个仓库拉下来。推荐的工具是git-dumper,它是一个专门把暴露的.git目录里的对象文件分批下载并重建仓库的脚本。
git-dumper http://target.test/.git/ ./dump执行之后,./dump目录下会生成一个完整的Git仓库,你可以在里面执行git log查看提交记录,git status查看当前状态,甚至切到某个历史提交恢复已经被删除过的文件。很多开发环境里,数据库密码、API密钥、云服务密钥都曾经被提交过,后来又因为泄露被删除,但只要仓库完整,历史记录里依然能翻出来。
需要特别强调的是,这个操作会真实下载目标服务器上的敏感文件,所以它的使用边界非常严格,只能在你拥有授权的测试环境中做。不是你的目标,不要碰。
除了.git,还有几种同类泄露也值得检查:.svn/entries暴露SVN仓库结构、.DS_Store泄露当前目录的文件列表、web.config.bak、test.sql、db.sqlite3这类常见备份文件。目录爆破时把这些路径加进字典,会提升不少命中率。
5.4 从泄露信息到加固建议
源码泄露的真正危险点在于“凭据复用”。我在实际项目里见过很多次,业务系统本身防护做得挺严,但源码仓库里却写着测试环境数据库地址、Redis口令、OSS密钥,运维同学图省事直接写了明文。对于安全测试来说,拿到这些信息不应该是终点,而是要把它们写进整改报告。
修复方法也要同步给出:一是Web服务器配置里显式禁止访问所有以点开头的文件或目录;二是构建部署流程里不要把.git目录包含进最终发布产物;三是对生产环境做一次密钥轮换,特别是有任何被历史提交记录的密钥,全部作废重发。只有把漏洞、证据、修复建议三样一起交出去,这份信息收集报告才算是有价值的。
6. 人员信息与社交工程防范
6.1 人员维度的常见公开来源
人员信息收集,也可以叫人员侧的开源情报,是所有信息收集维度里最需要克制的一项。它的价值在于,能帮助判断一个企业对信息的暴露程度,以及员工在用什么样的真实信息注册公司的系统。常见的公开来源有这么几个:一是公司官网和招聘页,上面往往有公司统一邮箱格式、组织架构、关键岗位人员姓名和联系方式;二是GitHub等代码托管平台,员工如果在上面关联了自己的企业邮箱,或提交过包含公司内部路径的代码,就能找出企业技术栈线索,这类信息完全公开,但价值极高;三是社交平台,很多人会在公开简介里写公司名和职位,形成一条清晰的人员关系链。
在授权评估场景里,人员信息的作用是辅助验证,比如确认某个账号是否属于离职员工遗留、确认统一邮件命名规则是否能够被预测。它不应该被用来针对个人发起骚扰或威胁,这不是安全测试的范畴,而是违法犯罪。
6.2 信息使用的边界
信息收集到了一定程度,最难的不是收集,而是判断哪些信息可以用、哪些绝对不能用。我给自己定的标准是:只记录和使用与资产直接相关、确实公开可获取的信息;不收集身份证号、手机号等公民敏感信息;收集到的个人信息不落库、不对外发布、不传播。报告里如果需要体现人员侧风险,我一般只描述“企业邮箱命名规则是否可被猜测”“员工是否在公开平台暴露了内部系统关键词”,而不是把某个真实员工的社交主页截图贴进报告。
客观说,人员信息收集这块最容易被误解和滥用。所以我始终建议安全团队把重心放在“如何防范钓鱼和社交工程”上,而不是花力气去挖掘谁的个人信息。给员工的建议永远优先级更高:企业邮箱和企业密码不要用于任何私人网站注册、不要随意公开GitHub账号关联企业信息、收到疑似内部邮件先电话确认。
合规永远比技术能力值钱。
7. 常见问题与避坑速查
7.1 容易翻车的几个环节
操作多了,翻车点基本都是重复的那几个,我随手列一下,做信息收集之前先看一遍能少走很多弯路。
| 场景 | 常见问题 | 原因与对策 |
|---|---|---|
| 子域名大批量误报 | 泛解析导致大量无效子域名 | 对解析结果做IP去重,确认是否存在统一IP返回 |
| 端口扫不到 | 主机在线但端口无响应 | 检查是否启用-Pn,确认云安全组和防火墙是否拦截来源IP |
| 服务版本识别慢 | Nmap版本探测时间过长 | 先用全端口快扫,后用--version-light扫描已知端口 |
| 目录爆破结果惊数量巨大 | 对302/403/405未处理 | 用-mc all -fc 404先看全部状态,再逐类人工确认 |
| 指纹识别结果矛盾 | 不同工具识别出不同框架 | 至少取两个特征交叉验证,不只看响应头 |
| .git 目录打不开 | 服务器返回403 | 确认是否有限制点目录的配置,或换其它泄露入口(.svn、备份文件) |
| 防火墙规则开放无效 | 端口规则已加但外部不通 | 检查Linux防火墙和云控制台安全组两处规则是否都放行 |
7.2 我自己的巡检清单
收尾之前,分享一份我每次做信息收集都会过的巡检清单,基本就是一张白纸,按步骤打勾。
第一步,域名侧:是否收集了证书透明度、被动搜索、主动枚举三类来源?是否确认过没有泛解析误报?是否标记了可能接管的子域名?
第二步,IP和端口侧:是否做了全端口快扫?是否对开放端口做了服务版本确认?是否查看了常见业务组件的默认端口?是否记录过访问控制规则?
第三步,服务侧:是否提取了响应头和页面特征的指纹?是否算了favicon哈希?是否确认了框架版本和已知漏洞的关联?
第四步,目录侧:是否做了合理的字典覆盖?是否对所有状态码做了人工确认?是否检查了.git、.svn、备份文件等源码泄露路径?
第五步,人员侧:是否仅使用了公开信息?是否对敏感信息做了脱敏?是否把结论落在了加固建议而不是个人身上?
这套清单不复杂,但能保证你每一步都有据可查、不遗漏关键路径。信息收集这活儿,靠的从来不是某个神器工具,而是对每一步“为什么要这么做”想得足够清楚。我自己的体会是,工具可以换、命令可以改,但这套从域名到人员、从公开到深入、从收集到加固的思路,才是真正值钱的东西。