关于 web-pentest
web-pentest 是面向获授权目标的实战 Web 应用安全测试技能,适用于黑盒或灰盒评估。它按 OWASP WSTG 分阶段检查,并要求为每项发现保留基线与攻击证据。
主要功能
- 01按 OWASP WSTG 分阶段测试
- 02检查身份验证与访问控制
- 03测试输入验证和业务逻辑
- 04结合源码与线上实例验证
- 05要求成对记录发现证据
适用场景
- 01评估获授权的线上 Web 应用
- 02验证 IDOR、越权及会话问题
- 03将源码审查线索用于实测
- 04为安全发现收集可复核证据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ briiirussell/ cybersecurity-skills --skill web-pentest安装后在 Claude Code 中输入/web-pentest确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/findings-format.mdfindings.schema.jsonseverity-calibration.mdto-sarif.mjsvalidate-findings.mjsverification.md详细介绍
Web Pentest — Web 应用实战测试
针对经授权的目标,对运行中的 Web 应用开展结构化黑盒/灰盒渗透测试。与 recon(用于绘制攻击面)配合,并补充 owasp-audit(用于检查源代码)。先使用 recon;获取目标列表和凭据(或访客访问权限)后,再使用此工具。
授权检查
在接触目标前,请确认:
- 已获得针对该应用的书面授权(渗透测试项目、漏洞赏金计划范围内的域名、CTF/实验环境、自有资产)
- 该应用目前在授权范围内且正在运行(未弃用、未处于维护冻结期)
- 已提供测试凭据(灰盒测试),或已确认可访客访问(黑盒测试)
- 已记录不在范围内的事项——生产用户数据、支付流程、社会工程、DoS
如有任何不清楚之处,请先询问再继续。切勿假定已获得授权。
方法
遵循 OWASP Web Security Testing Guide(WSTG)的结构。每个阶段都会产生证据;请在测试过程中记录所有内容。
阶段 1:配置与部署
目标:了解正在运行的内容及其暴露方式。
- HTTP 标头——使用
curl -I和curl -I -H "Origin: https://evil.com"获取:- 揭示技术栈的
Server、X-Powered-By - HSTS、CSP、X-Frame-Options、X-Content-Type-Options 是否存在及其值
- CORS——
Access-Control-Allow-Origin是否会在没有允许列表的情况下反射来源;Allow-Credentials: true是否与*配对
- 揭示技术栈的
- TLS——使用
testssl.sh https://target或sslyze --regular target - 是否暴露备份/配置文件——
/.git/、/.env、/backup.sql、/web.config、/server-status、/.aws/credentials - 默认管理路径——
/admin、/administrator、/manage、/console、/actuator/、/_debug/、/swagger、/graphql、/.well-known/ - Robots.txt 和 sitemap.xml——通常会列出未被索引但可访问的端点
- 子域名和 Host 标头测试——发送
Host: internal.target.com时,应用的行为是否有所不同?
阶段 2:身份管理
目标:了解谁可以创建账户、如何创建,以及拥有哪些权限。
- 注册——能否自行注册?默认角色是否为 "user" 以外的其他角色?
- 通过注册(“电子邮件已存在”)、登录(“找不到用户”与“密码错误”)和密码重置(“我们已发送电子邮件”与“不存在此用户”)时的差异响应枚举用户名
- 账户开通——是否会收到验证电子邮件?能否跳过验证?重置链接是否会过期?重置链接是否与原始会话绑定?
- 账户锁定与速率限制——连续 100 次登录失败会锁定账户(造成拒绝服务),还是只会降低请求速度(较好)?
阶段 3:身份验证
目标:以不应获得访问权限的身份闯入系统。
- 登录表单——是否强制使用 HTTPS?凭据是否通过 URL 参数发送(会到处被记录)?
- 密码策略——最低长度/复杂度要求、是否检查泄露数据库(haveibeenpwned API)
- MFA——管理员/特权用户是否必须使用?是否存在绕过途径(恢复码、“记住此设备” Cookie 持久化、降级为短信验证)?
- 会话令牌——熵是否足够高?Cookie 是否设置了
HttpOnly、Secure、SameSite=Lax或Strict? - 会话固定——登录时会话 ID 是否轮换?预认证会话 ID 在认证后是否仍然有效?
- “记住我”——是否使用单独 Cookie 中的长期有效令牌;是否能在所有设备上登出时撤销?
- 登出——是否会在服务端真正使会话失效?(登出后尝试重放 Cookie。)
- 密码重置——令牌格式、有效期、是否仅能使用一次,以及 Host 标头投毒(重置邮件链接中使用
Host: evil.com) - OAuth 流程——是否使用 PKCE?是否验证
state参数?是否严格匹配redirect_uri(而非仅匹配前缀)?
第 4 阶段:授权(最有价值的阶段)
目标:访问你不应该访问的内容。
水平权限提升(IDOR / BOLA):
- 以用户 A 的身份登录。获取一个属于用户 A 的资源,并记下 ID。
- 以用户 B 的身份登录。尝试通过 ID 访问用户 A 的资源——直接获取、在更新请求的正文中使用,或在其他操作中将其作为外键。
- 留意响应代码——200(不妙)、403(正常)、404(如果所有未授权请求都返回 404 则正常;如果你自己的 404 看起来不同则不妙)。
- 尝试每个接受 ID 的端点——
GET /users/:id、POST /users/:id/...、DELETE /users/:id、GET /api/users/:id/orders、GraphQLuser(id: ...)
垂直权限提升(BFLA):
- 识别仅限管理员访问的路由(通过探索
/admin/*、查看 JS bundle 字符串、或查看 Burp 的站点地图) - 以普通用户身份访问这些路由。403(正常)、200(非常不妙)
- 检查 HTTP 方法篡改——
DELETE /admin/users/x被拦截,但POST /admin/users/x/delete可以成功 - 批量赋值——注册端点接受
{ role: "admin" },因为它未经过滤就执行了User.create(req.body)
租户隔离(多租户 SaaS):
- 使用用户 U1 创建组织 A。使用用户 U2 创建组织 B。
- 以 U1 的身份尝试访问每个包含组织 / 租户 ID 的 URL,并将其替换为组织 B 的 ID。每次都应该返回 403 / 404。返回 200 表示租户隔离失效。
第 5 阶段:会话管理
- 会话令牌是否出现在 URL 中?如果被记录到任何地方,访问日志就会泄露它。
- 是否允许并发会话?应当可以配置 / 记录。
- 更改密码后令牌是否会在所有地方失效?(在浏览器 1 中更改密码,然后重放浏览器 2 的 cookie 进行测试。)
- CSRF 防护——同步器令牌、SameSite cookie、自定义请求标头?尝试从不同源伪造请求进行测试。
第 6 阶段:输入验证
对每种输入——URL 参数、查询字符串、标头、JSON 正文、文件上传:
- XSS——反射型(出现在错误页面、搜索结果中,或通过
<title>注入)、存储型(出现在个人资料字段、评论、文件名中)、DOM 型(检查innerHTML、eval、location等 JS 接收器)- Payload 库——参见
owasp-auditVerify Fixes XSS payloads
- Payload 库——参见
- SQLi——
' OR 1=1 --、基于时间的盲注('; SELECT pg_sleep(5)--)、基于错误的注入、基于 UNION 的注入- 现代技术栈通常使用参数化查询;找出那个没有采用此做法的端点
- 命令注入——任何涉及文件名、图像处理、PDF 生成或调用 shell 的地方
- SSRF——Webhook URL、图像获取、PDF 渲染——参见
owasp-auditA01 SSRF bypass matrix - XXE——SOAP / SVG 上传 / DOCX 导入路径中的 XML 输入
- 服务端模板注入——在名称字段中输入
{{7*7}},结果显示为49?那就成功了。 - 开放重定向——参见
owasp-auditA01 with control-byte rejection - 不安全的反序列化——对任何不透明令牌进行 Base64 解码,并查找序列化格式标记(PHP 的
O:、Java 的\xac\xed、Python pickle 的cos\nsystem)
第 7 阶段:错误处理
- 500 响应中是否显示堆栈跟踪
- 数据库错误是否泄露架构信息(表名、列名)
- 文件路径是否泄露服务器文件系统布局
- 有效与无效用户名是否返回不同错误(用户名枚举)
/health//status//metrics//actuator/*是否暴露
阶段 8:业务逻辑
大多数扫描器无法触及的类别。审视应用本应执行的操作,然后问:“如果我执行了该操作,但操作有误,会怎样?”
- 竞态条件 — 并发提交同一优惠码 100×;能否兑换多次?
- 负数 — 能否转账
-100并给自己入账? - 工作流顺序错乱 — 能否在完成第 2 步之前先完成第 4 步?
- 配额绕过 — 免费套餐的限制是在服务端强制执行,还是只在 UI 中执行?
- 工作流审批 — 能否篡改
approver_id来批准自己的请求? - 文件上传 — 能否上传
.html文件,并让服务端使用Content-Type: text/html提供该文件?
要深入了解不变量建模、Actor x Action x Resource 矩阵、状态机滥用、限制切片、数值/退款套利漏洞,以及能够证明双重支出的并发测试方法(HTTP/2 单数据包攻击、幂等键作用域、丢失更新 RMW),请使用 business-logic-testing。针对资金流的并发证明需要明确书面授权范围和请求上限 — 优先使用预发布环境 / 测试模式。
阶段 9:客户端
- JS 包审查 — 使用
view-source:/ DevTools,查找内联机密、API 密钥、内部端点提示 - CSP — 尝试注入
<script>,查看是否会被拦截 - 浏览器存储 —
localStorage/sessionStorage/ IndexedDB 中有什么?令牌?PII? - 跨源 — 来自你的源的
postMessage能否在没有源检查的情况下到达应用的窗口?
白盒 + 黑盒组合模式
当你同时拥有目标的源代码和运行中的实例时,使用此模式。owasp-audit 会读取代码;此技能会测试实时应用。两者结合优于单独使用任何一种:代码告诉你漏洞在哪里,实时测试则证明漏洞可触达且可利用。(owasp-audit 在涉及源代码与运行中应用的场景中会链接到此处。)上述授权检查仍完全适用于实时目标 — 阅读源代码并不代表你获准发送请求。
构建目标映射表。 建立一个表格,将每个代码处理器与其服务的实时端点关联起来,并置于共同的身份验证和配置上下文中,以确保你根据代码构造的请求会命中运行中的实例:
| 代码处理器 | 实时端点 | 身份验证上下文 | 备注 / 线索 |
|---|---|---|---|
routes/orders.ts cancelOrder() | POST /api/orders/:id/cancel | 用户 cookie | 状态读取前未检查所有权 |
app/admin/actions.ts promoteUser ('use server') | RPC(无可见路由) | 管理员 | 服务端操作 — 从 JS 包中枚举 |
一次性捕获共享身份验证信息(每个角色和租户对应的 cookie/token),以及将代码映射到运行时的配置(基础 URL、路由前缀、Next.js 服务端操作、tRPC 过程、未显示为路由的 GraphQL 解析器等框架 RPC 接口 — 参照 owasp-audit A01)。
双向确定优先级 — 让两侧相互引导:
- 代码 -> 实时测试。 源代码中的发现(缺少所有权谓词、检查后操作窗口、
redirect(req.query.next))会明确指出需要实时测试的端点、参数和前置条件。你可以跳过盲目模糊测试,直接验证问题。按照代码审查给出的严重性安排实时测试顺序。 - 实时测试 -> 代码。 实时异常(预期为 403 却收到 200、时间差异、泄露列名的错误)会决定下一步代码审查的优先级 — 打开对应的处理器,追踪防护为何未触发。将二者的配合视为一个循环,而非交接:一侧的每项已确认发现都会重新调整另一侧的优先级。
此模式产生的发现包含两方面的证据 — 易受攻击的代码位置,以及证明问题可触达的实时请求/响应。记录判定结果(confirmed / needs_validation / rejected),并附上下方配对的证据。
工具
- Burp Suite Community(免费)— 代理、重放器、入侵者(速率受限)、解码器
- Burp Suite Pro — 扫描器、更快的入侵者、会话处理规则
- OWASP ZAP — 免费替代方案、主动扫描器、模糊测试器
- ffuf / feroxbuster / gobuster — 目录和参数暴力枚举
- sqlmap — SQLi 利用(请谨慎使用;可能产生大量请求并造成破坏——可从
--risk=1 --level=1开始) - dalfox / XSStrike — XSS 扫描器(误报率高;可用作起点)
- nuclei — 模板驱动的漏洞扫描器;其模板本身就很值得阅读
- curl / httpie — 可重复的手动请求;你发现的所有问题都应能归结为一条 curl 命令
概念验证 — 必须提供成对证据
单个请求/响应无法证明某项控制失效——它可能只是应用的正常行为。每个经过验证的发现都必须附带攻击请求和基线/控制请求:两个几乎相同的请求,仅在受测变量上有所不同,这样响应差异才能定位失效的控制。 根据发现类型配对:
- 访问控制(IDOR/BOLA、BFLA、租户隔离): 资源所有者与非所有者。两个请求完全相同——方法、路径、请求正文和标头均一致——仅会话令牌/主体不同。所有者获得包含数据的 200;非所有者必须获得 403/404。非所有者针对同一资源得到 200,而所有者也得到 200,即为证据。没有这组所有者与非所有者的配对请求,IDOR/BOLA 发现均无效。
- 身份验证: 未经身份验证与已身份验证——同一请求分别使用有效会话和不使用有效会话。
- 注入 / 输入验证: 有效载荷与无害输入——针对同一参数,将恶意输入与无害的控制输入对照,证明有效载荷会改变行为(错误、延迟、反射输出),而无害输入不会。
完整捕获两次交互(请求 + 响应),并标明哪一个是控制请求。根据 references/verification.md,记录判定结果——confirmed(配对证据成立)、needs_validation(尚未捕获控制请求;请附上计划)或 rejected(控制请求未发现问题)。
先验证,再记录
先编写 findings.json,验证后再据此生成报告——详见 references/findings-format.md。JSON 是记录依据;文字说明绝不会改变判定、严重程度、阻碍因素或已证实的影响。在确认任何候选项之前,都要按照 references/verification.md 中的步骤逐一进行反证:验证者会重新读取已捕获的交互记录,并指出路径上最有力的控制措施。
实时测试会产生证据文件,而不是源代码行。 将每条捕获的交互记录——攻击请求/响应及其配对的基线/控制请求——脱敏后保存到 <audit dir>/evidence/<name>.txt,并将 location 和每个 evidence[] 条目指向该文件及其中对应的行。**切勿保存真实的会话令牌、密码或客户记录:**将 Cookie 脱敏为其名称和末尾 4 位。在白盒与黑盒结合模式下,还要在 trace[] 中引用源代码处理程序(path/to/handler.ts:line)。
confirmed— 配对证据成立:两条几乎完全相同的交互记录仅在一个受测变量上不同,从而隔离出失效的控制措施(所有者与非所有者、已认证与未认证、攻击载荷与良性载荷;参见上文的“概念验证”)。针对已获授权的目标捕获的配对证据属于动态证明,因此应将reproduced设为true,confidence可以为high。示例:非所有者的GET /api/orders/42返回 200 和订单正文,而所有者的相同请求也返回 200——这是一个 BOLA,且证据文件中包含这两条交互记录。needs_validation— 行为虽有迹象,但未捕获用于隔离问题的控制请求,或某个决定性事实取决于部署环境(如 WAF、会剥除标头的代理或 IdP 设置)。说明阻碍因素,并在validation_plan中写明确切命令。只描述但未执行的检查应标记为needs_validation,而非confirmed。示例:重置邮件中的链接受到Host:污染,但尚未确认已部署的邮件发送程序是否信任该标头。rejected— 在所有可达路径上,位于指定位置的指定控制措施均有效,并以拒绝方式失效关闭:非所有者请求返回 403/404、载荷被拒绝、state经过验证。ruled_out_by应指出控制措施及其运行位置(中间件,或证据中捕获的已部署标头集)。
仅对 confirmed 记录设置严重程度,并依据 references/severity-calibration.md 进行校准:overall ≤ demonstrated impact。不要夸大缺失标头、Cookie 标志、单独的开放重定向或非敏感操作上的点击劫持——除非能追踪到具体影响,否则这些都只是加固建议。不安全的已发布默认设置(宽松的 CORS 默认配置、硬编码的备用密钥)应标记为 confirmed,并设置 system_configuration 条件和 confidence: medium。
在 ext 下记录领域字段(任意记录上均可选的对象):
ext 键 | 含义 | 示例 |
|---|---|---|
wstg | WSTG 测试 ID | WSTG-ATHZ-04 |
endpoint | 已测试的实时端点 | POST /api/orders/{id}/refund |
mode | 评估模式 | black-box | grey-box | combined |
指纹格式:web-pentest/<wstg-or-class>/<endpoint path or resource>/<parameter or operation>,以斜杠分隔,不含行号(验证器会拒绝 :<digits>,因此应使用斜杠分隔的 host:port)。示例:web-pentest/WSTG-ATHZ-04/api/orders/id/refund、web-pentest/reflected-xss/search/q、web-pentest/tls/app.example.com/443/rc4-enabled。
按指纹排序编写 findings.json,然后验证并修复,直至通过:
node references/validate-findings.mjs findings.json
也可选择导出 SARIF:node references/to-sarif.mjs findings.json -o findings.sarif。处置结果(Fixed / Deferred / Accepted Risk / Mitigated (platform/config) / Requires major migration)稍后设置,通常由 finding-triage 处理;误报应记录为 rejected,而不是处置结果。
输出格式
先编写 findings.json 并进行验证;下方报告由 JSON 渲染生成,绝不会更改 JSON 中未包含的判定或严重性。
# Web Application Pentest Report
## Target: [name and scope] ## Methodology: OWASP WSTG ## Mode: [black-box | grey-box | combined]
## findings.json: [path] — validated: [yes] ## Engagement window: [start - end]
### Executive summary
[2-3 paragraphs — overall posture, top findings, business impact]
### Summary
- Confirmed: [N] (Critical [n] | High [n] | Medium [n] | Low [n]) Needs validation: [N] Rejected: [N]
### Confirmed findings
#### [SEVERITY] [Title] `fingerprint`
**Endpoint:** `METHOD /path` **WSTG / CWE:** [WSTG-XXX] / [CWE-XXX] **Confidence:** [medium | high (reproduced)]
**Code location (combined mode):** `path/to/handler.ts:line` — the source behind this endpoint
**What and why it matters:** [the trace, in a few lines]
**PoC — attack request/response:** [from `evidence/<name>.txt`]
**PoC — baseline/control:** [the paired request differing by one variable; label which is the control]
**Fix:** [concrete change] **Verify the fix:** [the check to re-run]
### Needs validation
| Finding | Blockers | Check for the owner to run |
|---|---|---|
### Hardening notes (not findings)
- [gap] — [why it isn't a finding] — [effort]
### Rejected (do not re-raise)
| Fingerprint | Ruled out by | Location |
|---|---|---|
### Out-of-scope / not tested
[Anything skipped, with reason]
### Prioritized remediation plan
1. [highest first — 30 / 60 / 90 day fixes]
严重性仅适用于 confirmed 发现;needs_validation 包含 blockers[] 和 validation_plan,不包含严重性;rejected 则注明拒绝该发现的控制措施及位置。请参照 references/severity-calibration.md 校准严重性。
范围限制
- 严格遵守授权范围——未经明确确认,绝不测试相邻系统、子域名或第三方服务
- 对测试进行速率限制——连续数小时以 100 req/s 运行 Burp Intruder,与 DoS 攻击难以区分
- 绝不修改或销毁真实用户数据——仅使用自己拥有的测试账户,或自己创建的测试数据
- 如果发现正在发生的入侵证据(例如他人的 WebShell、正在进行的数据外泄),立即停止测试并通知用户
- 拒绝测试未经授权的系统
- 拒绝将发现用于武器化——概念验证是最低限度的有效演示,不是可运行的漏洞利用工具包
- 对于 DoS / 可用性测试,须取得明确的书面批准,并注明维护时段
- 对于社会工程 / 网络钓鱼测试,范围必须明确包含此类测试——默认情况下,它不属于渗透测试范围
参考资料
- OWASP Web Security Testing Guide(WSTG)——规范方法
- OWASP Application Security Verification Standard(ASVS)——检查清单版本
- 共享参考资料(构建时复制到
references/):findings-format.md、severity-calibration.md、verification.md - PTES(Penetration Testing Execution Standard)
- Bug Bounty Methodology(Jason Haddix / TBHM)
- PortSwigger Web Security Academy——免费培训实验室
- HackTricks(book.hacktricks.xyz)——技术参考(请对照最新资料核实;HackTricks 汇总了质量参差不齐的社区知识)