上一章你学会了"读系统",这一章学"规模化地读"。 一个测试项目可能有几百个域名、几千个接口、几万个参数—— 手工点不过来,必须把"逻辑"交给自动化,把"判断"留给自己。 核心心法:自动化放大你的能力,但绝不代替你的判断。
19.0 开篇:手工 vs 自动化,差在哪里
一个真实场景:某公司授权你测试它全部资产。
手工方法:
你打开浏览器,一个个点……第一天测完了主站。
老板问:"子域名呢?" 你说:"我还没找到。"
自动化方法:
① 用子域枚举工具,10 分钟拿到 300 个子域名
② 用爬虫 + 端点提取,拿到 5000 个 URL
③ 用 nuclei 批量扫,筛出 50 个"可疑点"
④ 你只在这 50 个上手工深挖
差距不在"技术",在"规模"。
🔥 自动化的正确位置:
自动化负责:发现(Discovery)+ 筛选(Triage)—— 把"候选"从一万个缩到十个
人负责: 判断(Analysis) + 利用(Exploit) —— 在那十个里找到真的漏洞
❌ 错误认知:自动化能"直接找到漏洞"
✅ 正确认知:自动化能"把值得看的东西挑出来,让你少看 99% 的噪音"
19.1 资产发现:先知道"打什么"
一切自动化的起点,是"资产清单"。 你不可能测试你不知道存在的系统。
19.1.1 子域名枚举
一个主域名背后,往往藏着几十上百个子域名——它们是最容易被忽略的攻击面。
方法一:证书透明度日志(被动,最推荐)
# crt.sh:所有公开 TLS 证书都记录在证书透明度日志里
# 直接访问:
https://crt.sh/?q=%25.example.com
# 或用命令行取
curl -s "https://crt.sh/?q=%25.example.com&output=json" | jq -r '.[].name_value' | sort -u
💡 为什么 ctsh 最有用:完全被动——你只是在查别人公开的信息,目标完全感知不到。
方法二:字典爆破(主动)
# ffuf 挖子域
ffuf -w subdomains.txt -u https://FUZZ.example.com -mc 200,301,302,403
# 或 gobuster dns
gobuster dns -d example.com -w subdomains.txt
方法三:其他被动源
□ DNS 数据集:SecurityTrails、VirusTotal、PassiveTotal
□ 搜索引擎:site:example.com
□ GitHub 代码搜索:搜 "example.com"(可能泄露内部域名)
□ 第三方服务:Shodan、Censys(按证书/组织搜)
子域枚举的产出:一份"资产列表",后面所有测试都基于它。
19.1.2 域名 → IP → 端口
# 解析 IP
dig example.com +short
# 端口扫描(仅在授权范围内!)
nmap -sV -p- target
# 用 masscan 快速扫大量主机(更快)
masscan -p1-65535 --rate=1000 192.168.1.0/24
19.1.3 技术栈指纹识别
知道目标是"什么技术做的",才能"针对性地测"。
# whatweb:识别 CMS、框架、服务器
whatweb https://example.com
# wappalyzer:浏览器插件,或命令行版
# 从响应头、HTML、JS、favicon 综合判断
# 单独看响应头
curl -sI https://example.com
识别什么:
□ Web 服务器(Nginx/Apache/IIS)
□ 语言/框架(Spring/PHP/Django/Node)
□ CMS(WordPress/ThinkPHP/Shiro)
□ CDN / WAF
□ 前端框架(从 JS 文件特征)
□ 用到的第三方服务(从资源域名判断)
19.1.4 一个"资产发现流水线"
① 子域枚举(crt.sh + 字典爆破 + 被动源)→ 得到一堆域名
② 存活探测(批量 HTTP 请求,过滤掉打不开的)
③ 指纹识别(whatweb / wappalyzer)→ 知道每台是什么
④ 端口扫描(nmap)→ 发现非 Web 服务
⑤ 汇总成"资产表格":域名 | IP | 端口 | 技术栈 | 负责人
💡 这份表格,就是你整个测试的"作战地图"。 后面所有工作,都从它出发。
19.2 接口与参数发现:找到"可测的点"
漏洞藏在"接口 + 参数"上。所以自动化的一大任务,就是"把所有接口和参数挖出来"。
19.2.1 爬虫:把"能点的"都点一遍
# katana:现代爬虫(Burp 也有类似能力)
katana -u https://example.com -d 3 -o urls.txt
# 或用 Burp:正常浏览一遍,HTTP history 里就是"爬到的"
爬虫的局限:只能爬"静态链接能到达"的页面。JS 动态渲染、需要交互的页面爬不到。
💡 技巧:用 Burp 的"手动浏览 + 代理记录"往往比自动爬虫更全——因为你会点击 JS 生成的按钮。
19.2.2 从 JS 文件里挖接口(现代应用必做)
现代 SPA 的接口,往往藏在 JS 里,而不是 HTML 链接里。
# 下载所有 JS 文件
katana -u https://example.com -jc # -jc 表示爬 JS
# 或用浏览器把 JS 文件都下载下来
# 在 JS 里搜"像 URL 的字符串"
# 搜索形如 /api/xxx 的路径片段
grep -oE '/[a-zA-Z0-9_/-]*api[a-zA-Z0-9_/-]*' app.js | sort -u
# 搜索完整的 http(s) 链接
grep -oE 'https?://[a-zA-Z0-9._/-]+' app.js | sort -u
💡 LinkFinder 之类的工具专门做这件事——从 JS 里提取 API 路径。
19.2.3 目录 / 文件爆破
# ffuf 目录爆破(过滤掉 404)
ffuf -w dirs.txt -u https://example.com/FUZZ -fc 404
# 带后缀
ffuf -w dirs.txt -u https://example.com/FUZZ -e .php,.html,.bak,.zip,.txt
# 用"递归":对发现的目录继续爆
19.2.4 参数发现(容易被忽略)
同一个接口,多带一个隐藏参数,行为可能完全不同。
# arjun:专门发现隐藏参数
arjun -u https://example.com/api/user
# 或用 ffuf 爆破参数名
ffuf -w params.txt -u "https://example.com/api?id=1&FUZZ=1" -fs 0
# 从 JS 里找(参数名常写在 JS 里)
# 搜索 "params" / "query" 等关键字附近的字段
💡 隐藏参数的经典案例:?admin=true、?debug=1、?test=1、?role=admin——开发者留下的"调试开关",往往就是漏洞入口。
19.2.5 历史 URL(被遗忘的接口)
□ Wayback Machine:web.archive.org —— 历史版本可能暴露已删除的接口
□ 各种"历史 URL"数据集
□ 搜索引擎缓存
为什么重要:"删掉的接口"往往比"现存的接口"更脆弱——因为开发者可能忘了它还在,或其防护没跟上。
19.2.6 一个"接口清单"的构成
最终产出:一份包含所有"可测点"的清单
每一行:方法 | URL | 参数 | 来源(爬虫/JS/猜/历史)
去重后往往有几千到几万条
→ 交给下一步(扫描 / 批量化测试)
19.3 把"经验"变成"扫描规则":nuclei 模板
nuclei 的核心价值:把"你知道怎么检测某个漏洞"这件事,写成一份可复用的 YAML 模板。
19.3.1 一个最简单的模板
id: exposed-git-config
info:
name: Exposed .git/config
author: me
severity: medium
description: 网站的 .git 目录可被访问,可能泄露源码
requests:
- method: GET
path:
- "{{BaseURL}}/.git/config"
matchers:
- type: word
words:
- "[core]" # .git/config 里必然出现的字符串
part: body
结构解析:
id 模板的唯一标识
info 元信息(名称、作者、危害等级、描述)
requests 怎么发请求(method / path / headers / body)
matchers 怎么判断"命中了"(关键字 / 正则 / 状态码 / 响应长度)
19.3.2 几种常用的 matcher
matchers:
# 状态码
- type: status
status: [200]
# 关键字(body 里出现某段文字)
- type: word
words:
- "root:x:0:0"
part: body
condition: and # 或者 or
# 正则
- type: regex
regex:
- "uid=\d+"
# 二进制 / 按响应长度差异
- type: dsl
dsl:
- "status_code == 200 && content_length > 100"
19.3.3 多请求模板(提取数据再用)
id: my-multi-step-check
info:
name: 多步检测
severity: low
requests:
# 第一步:拿 token
- raw:
- |
GET /api/token HTTP/1.1
Host: {{Hostname}}
extractors:
- type: regex
name: token
regex:
- '"token":"([a-f0-9]+)"'
group: 1
# 第二步:用 token 访问受保护接口
- raw:
- |
GET /api/admin/data HTTP/1.1
Host: {{Hostname}}
Authorization: Bearer {{token}}
matchers:
- type: word
words: ["admin_data"]
💡 这个"提取 → 复用"的能力,让 nuclei 能表达"复杂逻辑",而不只是"发个包看响应"。
19.3.4 一个实用的例子:检测 Actuator 泄露
id: spring-actuator-env
info:
name: Spring Boot Actuator env 暴露
severity: high
requests:
- method: GET
path:
- "{{BaseURL}}/actuator/env"
matchers-condition: and
matchers:
- type: status
status: [200]
- type: word
words:
- "systemProperties"
- "propertySources"
condition: or
part: body
extractors:
- type: regex
name: secrets
regex:
- '"(password|secret|key|token)"[^}]{0,200}'
19.3.5 使用与组织模板
# 用官方模板库扫
nuclei -u https://target.com
# 用你自己的模板目录
nuclei -u https://target.com -t ./my-templates/
# 批量扫描
nuclei -l urls.txt -t ./my-templates/ -o results.txt
# 按标签筛选
nuclei -u https://target.com -tags exposure,misconfig
# 只跑高危
nuclei -u https://target.com -severity critical,high
🔥 nuclei 的真正威力,在于"模板化"这件事:
你每发现一种"可检测的模式",就把它写成一份模板。 于是,你的经验不再只服务于"这一次测试",而是沉淀成"可复用的资产"。
19.4 写自己的扫描脚本
当 nuclei 表达不了你的逻辑时,就用脚本(Python 最常用)。
19.4.1 一个基础框架
import requests
# 会话(保持 Cookie,处理登录态)
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 ...", # 伪装成正常浏览器
})
# 目标列表
targets = ["https://a.com", "https://b.com"]
# 测试的 payload
payloads = ["'", "\"", "../", "<script>alert(1)</script>"]
for url in targets:
for p in payloads:
try:
r = session.get(url, params={"q": p}, timeout=10, verify=False)
# 判断命中的标准(状态码 / 关键字 / 长度差异)
if r.status_code == 500 or "SQL syntax" in r.text:
print(f"[!] 可疑: {url} payload={p} status={r.status_code}")
except Exception as e:
print(f"[x] 出错: {url} {e}")
19.4.2 关键设计点
① 【并发】用 concurrent.futures / asyncio,不要在"一个个循环"
⚠️ 但要注意"别把目标打挂"——控制并发数
② 【基线】先发一次"正常请求",记录状态码和响应长度作为基线
之后的异常判断,都是"和基线比"
③ 【去重】同一个漏洞别报一万遍
④ 【限速】请求间隔、失败重试、超时
⑤ 【稳健】任何异常都不能让脚本崩,要 try/except 包住
⑥ 【输出】结果存文件(JSON / CSV),方便后续处理
19.4.3 一个"批量越权测试"的脚本(思路)
import requests
# 两个账号(A 创建资源,B 尝试访问)
sess_a = requests.Session()
sess_b = requests.Session()
# 假设已登录,拿到了各自 Cookie
sess_a.cookies.set("session", "A_SESSION")
sess_b.cookies.set("session", "B_SESSION")
# A 创建资源,拿到 ID
r = sess_a.post("https://target/api/order", json={"productId": 1})
order_id = r.json()["id"]
print(f"[*] A 创建了订单 {order_id}")
# B 尝试访问 A 的资源
r = sess_b.get(f"https://target/api/order/{order_id}")
if r.status_code == 200:
print(f"[!!!] 越权漏洞: B 能访问 A 的订单 {order_id}")
else:
print(f"[ ] 有防护: {r.status_code}")
💡 这个"两账号对比"的思路,是越权自动化的核心。 Burp 的 Autorize 插件做的就是这件事,但自己写脚本你可以控制得更精细。
19.4.4 把脚本"模块化"
不要写一个"万能大脚本",而是拆成小工具:
discover.py 资产发现 / 子域枚举
endpoints.py 接口 + 参数提取
scan.py 批量扫描(调用 nuclei + 自定义逻辑)
vuln_xxx.py 针对某个漏洞的专用脚本
report.py 汇总结果、去重、生成报告
每个工具"只做一件事,做得好",再用管道串起来。
🔥 这是"自动化"的正确姿势:
不是"一个脚本搞定一切",而是"一组小工具,各司其职,用数据串起来"。
19.5 Google Dork:用搜索引擎挖资产
搜索引擎是"最被低估的信息收集工具"。 很多人已经"把内部信息暴露在搜索引擎里",而自己不知道。
19.5.1 常用 Dork 语法
| 语法 | 含义 |
|---|---|
site:example.com | 限定域名 |
inurl:admin | URL 里包含关键词 |
intitle:登录 | 标题包含关键词 |
intext:"密码" | 正文包含关键词 |
filetype:pdf | 指定文件类型 |
ext:sql | 指定扩展名 |
- | 排除 |
| 竖线 | 或 |
"" | 精确匹配 |
19.5.2 常见的"信息泄露"搜索
【找后台】
site:example.com inurl:admin
site:example.com inurl:login
site:example.com intitle:"管理"
【找敏感文件】
site:example.com filetype:sql
site:example.com filetype:env
site:example.com ext:log
site:example.com filetype:bak
【找配置/凭证】
site:example.com intext:"api_key"
site:example.com intext:"password"
site:example.com inurl:".git"
【找调试接口】
site:example.com inurl:swagger
site:example.com inurl:actuator
site:example.com inurl:phpinfo
【找目录列表】
site:example.com intitle:"Index of"
19.5.3 对"人"的 Dork(社工前置)
□ 员工邮箱格式:site:linkedin.com "example company"
□ GitHub 泄露:site:github.com "example.com" password
□ 员工技术博客(可能泄露内部架构)
□ 公开的会议资料 / 招聘 JD(可能泄露技术栈)
⚠️ 注意:Dork 本身不违法,但"用 Dork 找到的东西去攻击"是违法的。 只能在授权范围内使用。
💡 对授权测试:Dork 帮你找到"目标自己都没注意到的暴露面"——这对于"评估真实暴露面"极有价值。
19.6 一条完整的自动化流水线
把前面所有工具串起来,就是一条完整的流水线。
【阶段 1:资产发现】
子域枚举(crt.sh + ffuf + 被动源)
→ 存活探测(httpx)
→ 端口扫描(nmap)
→ 指纹识别(whatweb)
↓ 产出:资产清单
【阶段 2:接口发现】
爬虫(katana)
→ JS 提取(LinkFinder)
→ 目录爆破(ffuf)
→ 参数发现(arjun)
→ 历史 URL(wayback)
↓ 产出:可测点清单
【阶段 3:批量扫描】
nuclei(模板库 + 自定义模板)
→ 自定义脚本(针对特定漏洞)
↓ 产出:可疑点清单
【阶段 4:人工深挖】
对"可疑点"逐个手工验证
→ 确认漏洞 → 构造 POC → 评估危害
↓ 产出:漏洞报告
19.6.1 用 httpx 做"存活 + 指纹"
# 批量探测哪些域名是活的,并提取标题/技术栈/状态码
cat subdomains.txt | httpx -title -tech-detect -status-code -o alive.txt
19.6.2 用一条命令串起来
# 一个简化的"子域 → 存活 → 扫描"流水线
cat subdomains.txt \
| httpx -silent \
| nuclei -t ./my-templates/ -silent \
| tee results.txt
💡 Linux 管道的哲学:每个工具"读取输入、输出结果",用管道串起来,就能组合出复杂的能力。
19.6.3 让流水线"可复用"
□ 把每个阶段写成独立脚本 / 命令
□ 用一份"配置文件"管理:目标列表、字典路径、并发数、输出目录
□ 用一个"主脚本"按顺序调用各阶段
□ 输出统一格式(JSON),便于后续处理
□ 关键:加日志 + 加异常处理 + 加"断点续跑"
19.7 自动化的边界与陷阱
自动化很强,但用错了会"翻车"。
19.7.1 四个陷阱
① 【过度依赖工具】
工具报的"可能漏洞"90% 是误报或需人工确认
→ 不做人工验证就上报 = 被打脸
② 【把目标打挂】
高并发扫描可能让目标服务不可用(尤其生产环境)
→ 严格限速;授权书里通常有"不得影响业务"的条款
③ 【触发告警 / 被封】
激进扫描很容易被 WAF / IDS 发现并封 IP
→ 适当伪装、控制速率、必要时用代理
④ 【测试了范围外的资产】★ 最危险
自动化"顺手"扫到了不在授权范围的域名
→ 这可能构成"越权测试",法律风险
→ 严格的"scope 白名单",脚本层面做限制
🔥 第 ④ 点最危险。 自动化脚本很容易"一不小心"扫到授权范围外的资产。一定要在脚本里做 scope 校验。 这不是技术问题,是执业底线。
19.7.2 自动化"做不了"什么
□ 业务逻辑漏洞(第 16 章)—— 需要理解业务
□ 复杂的越权(需要多账号、多状态组合)
□ 需要"多步交互"的漏洞(验证码、状态机)
□ 需要"上下文理解"的漏洞(判断 IDOR 是否真的有危害)
□ 需要"创造性"的绕过(第 20 章)
💡 一句话:自动化处理"模式化"的问题,人处理"模式之外"的问题。
19.7.3 自动化检查清单
□ 有 scope 白名单,脚本层面强制
□ 有严格的速率限制
□ 有异常处理和超时
□ 有日志记录(万一出问题可追溯)
□ 结果有人工验证环节
□ 不碰"破坏性"操作(DELETE / DROP / 大量写)
□ 敏感数据(拿到的凭证 / 隐私)妥善处置,不传播
□ 测试时间 / 范围符合授权书
19.8 动手任务
任务 1:搭一条最小流水线
① 拿一个你自己搭的靶场(或授权目标)
② 用 ffuf 做目录爆破,产出结果
③ 把结果喂给 nuclei
④ 对 nuclei 报出的东西,**逐个手工验证**
⑤ 记录:哪些是真的,哪些是误报
任务 2:写一个 nuclei 模板
□ 找一个"你熟悉的、有明确特征的"检测点
(比如某个特定框架的特定路径)
□ 写成一份 nuclei 模板
□ 在靶场上验证它"能命中"
□ 再在"不存在该漏洞的目标"上验证它"不误报"
任务 3:写一个"两账号越权"脚本
① 在靶场注册两个账号 A、B
② 用 Python 写脚本:A 创建资源,B 尝试访问
③ 自动判断"是否越权"
④ 体会"自动化越权测试"的思路
任务 4:做一次"被动信息收集"
□ 对一个你**有授权**的域名,用 crt.sh 查子域
□ 用搜索引擎 Dork 查"暴露的文件"
□ 全程不用任何"主动扫描"(纯被动)
□ 记录:光靠被动收集,能发现什么?
任务 5:为你自己建一个"工具箱"
把常用的命令、脚本、模板,整理进一个目录:
tools/
├── recon/ 资产发现
├── endpoints/ 接口提取
├── templates/ nuclei 模板
├── scripts/ 自定义脚本
└── wordlists/ 字典
以后每次测试,直接从这里出发。
19.9 本章小结
核心结论
- 自动化的定位:发现 + 筛选(把候选从一万缩到十),判断 + 利用留给人。
- 资产发现是起点:子域枚举(crt.sh 被动最推荐)、端口扫描、指纹识别。
- 接口发现:爬虫 + 从 JS 挖接口(现代应用必做) + 目录爆破 + 参数发现 + 历史 URL。
- 隐藏参数(?admin=true / ?debug=1)是常见的漏洞入口。
- nuclei 的核心价值:把"经验"写成"可复用的 YAML 模板",且有"提取→复用"能力表达复杂逻辑。
- 自定义脚本:控制并发、建立基线、去重、限速、异常处理、结果存文件。
- 越权自动化的核心:两账号对比(Burp Autorize 做的就是这件事)。
- Google Dork 是"最被低估的被动信息收集"手段;只能在授权范围内使用。
- 自动化流水线:资产 → 接口 → 扫描 → 人工深挖;用 Linux 管道把工具串起来。
- 四个陷阱:过度依赖、把目标打挂、被封 IP、扫到范围外(法律风险最大)。务必在脚本里做 scope 校验。
随身口诀
自动化只做"发现和筛选",判断永远留给自己;crt.sh 挖子域,JS 里挖接口,arjun 挖参数;nuclei 把经验变成模板,脚本把模板变成流水线;别忘了 scope 白名单——扫到范围外就是事故。
19.10 预告:下一章我们去哪
有了资产、有了接口、有了自动化的"筛选能力",接下来就是"怎么真正打进去"。
真实的系统早就不"裸奔"了——它们前面有 WAF,代码里有各种过滤,参数有各种校验。
所以,"怎么绕过"就成了实战中最重要的能力之一。而绕过不是"背 payload",而是理解一件事:
防护是"某种规则",绕过是"让它看到的东西"和"实际执行的东西"不一样。
第 20 章:绕过大全。 从"方法论"高度讲透绕过。
📌 本章金句 "自动化的价值不是'让机器替你思考',而是'让机器替你搬砖'。它能帮你把值得看的十个从一万个里挑出来,但'这十个里哪个是真的',永远需要你的脑子。 一个不懂手工测试的人写的自动化脚本,只会生产更多的噪音。"