news 2026/10/17 5:04:15

XSS-labs靶场实战:从原理到绕过,系统掌握XSS漏洞利用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
XSS-labs靶场实战:从原理到绕过,系统掌握XSS漏洞利用

1. 靶场到底在练什么:先看懂XSS-labs的关卡地图

XSS-labs(也有人叫XSS挑战靶场)是我接触过的Web安全练习环境里,最适合用来系统刷一遍XSS技能树的平台。界面确实朴素——一排带序号的关卡,每条输入框构造出不同的过滤场景,但正是这种朴素,让每一关的考察点特别清楚。你提交一个payload,页面的表现只有三种:弹窗、不弹窗、报错。没有多余干扰,这对理解XSS漏洞的本质非常有帮助。

靶场总共20关左右,难度并不是线性上升,而是按“过滤手段”分组递进的。前几关基本不设防,目的是让你体会XSS能出现在哪些输出位置;中间关卡开始引入标签过滤、关键字替换、编码绕过;后半段则涉及HTML实体、空格过滤、DOM型注入等更贴近真实业务场景的组合条件。刷完一套题,你基本能把反射型XSS的常见匹配规则、浏览器解析机制、各类绕过思路都过一遍。

我把整个靶场的考点整理成了一张表,方便你在做题之前先建立整体认知:

关卡范围主要考点输入输出特点突破思路核心
Level 1-5无过滤、属性闭合输入直接拼接到HTML标签内先用无害值观察输出位置,再构造闭合
Level 6-10大小写过滤、事件属性过滤不区分大小写或只过滤单个关键字利用多种标签与大小写混合绕过过滤
Level 11-15请求头注入、DOM上下文输入位置在Referer、UA、Cookie等头字段找到输出位置,在HTTP头字段中构造payload
Level 16-20空格过滤、正则替换、编码绕行输入被多层处理,payload需还原原始意义掌握HTML实体、URL编码、解析顺序,组合技绕过

这张表看着简单,但它解决了一个关键问题:做题时最容易犯的错,就是拿到输入框就盲目贴一个经典payload,弹不出窗就开始换下一个,完全不看页面给了你什么信息。XSS-labs的每一关其实都在暗示你“这条过滤是怎么写的”,你要做的是根据题目特征推断过滤规则,而不是拿payload试错。读靶场,重点是学会建模:输入在哪个位置?输出是否被转义?转义发生在服务端还是前端?过滤规则是删标签、换关键字还是改编码?把这些问题回答清楚,payload的构造就有了依据。

2. 先垫三层基础:XSS原理、payload构成与浏览器解析

2.1 三种数据流决定三种XSS类型

在开始刷关之前,我建议你先搞清楚XSS的类型划分,否则后面做题容易乱。

反射型XSS指的是,服务端把用户输入直接拼进返回的HTML里,浏览器解析时执行了你的脚本。靶场大部分关卡都是这种类型,特点是payload只影响当前请求的响应。存储型XSS则是输入被存到了服务端数据库,其他用户访问时也会触发,靶场里体现得不太明显,但你在真实业务中遇到评论、留言功能时要重点排查这里。DOM型XSS跟前两者完全不同,服务端完全没参与,是前端JavaScript拿到输入后,把数据写进DOM导致执行。XSS-labs后几关会涉及这种场景,你需要直接看浏览器的开发者工具,去观察输入被脚本处理后的位置,而不是只看源码。

对做题而言,类型判断决定了你排查问题的方向。如果是反射型,抓响应包改请求就能定位;如果是DOM型,必须断点调试JavaScript才能找到漏洞触发点。

2.2 payload不是唯一,能执行才是核心

很多初学者喜欢背一堆经典payload,比如<script>alert(1)</script>、<svg onload=alert(1)>,但我不建议一上来就背。你先拆解一个payload的组成,理解它为什么能执行:

  • 标签本身:<script>是合法script标签,<svg>可以加载外链脚本,<img>、<a>等标签本身不执行JS,但配合事件或属性可以。
  • 闭合符号:当输入被放在标签属性值里时,你必须先闭合掉前面的引号和标签,才能注入自己的标签。比如输入被放在<input value="你的输入">中,你的payload就要以"开头,再跟上>来结束标签,后面才能接新标签。
  • 事件属性:onmouseover、onfocus、onerror这类属性可以直接触发JavaScript执行,通常不需要额外标签。
  • 伪协议:javascript:、data:这类URL协议可以在特定位置执行脚本,但会受到浏览器策略限制。

2.3 浏览器解析顺序,才是绕过的底层逻辑

掌握解析顺序,你能做到“不用背payload也能现场造一个”。简单说,浏览器拿到HTML响应后,要经历多个阶段的解析:

  • HTML解析阶段:浏览器把标签、属性、正常文本分别归类。如果你输入<img src=x onerror=alert(1)>,浏览器会识别出一个img标签,并在加载失败时触发onerror。
  • URL解析阶段:如果某个属性的值是URL,浏览器会再次按URL规则解析,比如href="javascript:alert(1)"。
  • JavaScript解析阶段:当标签被识别为可执行脚本时,浏览器才运行JS引擎去解析代码字符串。此时引号、反斜杠、换行等字符都有特殊含义。

一个payload能不能成功,关键看你输入的字符,在它经过每一层解析时,是否会因为编码、转义、过滤而失去原有语义。这也是为什么有些payload看起来和过滤规则“擦边”,却能弹窗。

举个生活化的例子:你给收件人寄快递,地址写错了没关系,只要快递员能看懂并最终把包裹送到正确的人手里就行。XSS也是这个逻辑,你的payload经过层层处理,只要最终能到达可执行的位置,就算成功。

3. 逐关实战:解题思路与可复现payload整理

这一部分我按实际闯关的顺序,把每一关的难点和最终payload整理出来。需要提前说明:以下payload全部用于XSS-labs靶场本地环境验证,请勿对任何未授权的互联网网站使用。

3.1 Level 1-5:从无过滤到属性闭合

Level 1考察的是最基础的反射型XSS。你在输入框提交任意字符串,刷新后能看到它直接出现在页面上。第一步不是直接打payload,而是先输入一个无害值,比如test,然后看页面源码,确认输入被放在了什么位置。确认是原样插入页面后,直接提交:

<script>alert(1)</script>

如果弹窗出现,说明靶场验证通过。此时你该意识到:无过滤场景中,script标签是优先级最高的选择,但真实业务很少这么裸奔,很多WAF会拦截它。

Level 2开始有过滤了。输入test后查看源码,你会发现输入被放进了<input value="test">这样的属性里。这里有个关键认知:你怎么知道它在属性里?开发者工具里看DOM结构,输入内容是否被引号包住,旁边有没有value=前缀。确认之后,payload要闭合引号和标签:

"><script>alert(1)</script>

第一个双引号用来闭合value属性值,紧接着的>结束input标签,后面注入新标签。这里如果不先闭合,你注入的标签会被整体吞进value属性里变成纯文本,永远不会执行。

Level 3同样把输入放在value属性中,但前面加了个HTML实体编码处理,你把"提交上去,源码里看到的是&quot;,也就是说引号被转义成实体了。这时直接闭合引号没用,因为服务端把你输入的引号变成实体,浏览器解析后引号只是文本,不会闭合属性。这一关真正要考察的是:能不能找到绕过HTML实体编码的路径。经过实测,如果输出位置是在input标签的value属性值中,且没有任何检测,你依然可以尝试:

' onmouseover='alert(1)

看题目的具体过滤逻辑。Level 3的设计其实是把输入包在双引号里,单引号不会被转义,所以闭合的是单引号场景——你没看错,这关输入点是在单引号包裹的属性里。做题时务必先看源码确定引号状态,再决定payload用什么符号。

Level 4会过滤<script>标签,大小写也被处理过,但过滤规则不完整。试探时提交<SCRIPT>alert(1)</SCRIPT>,大概率能成功。原理很简单:过滤规则可能只匹配了全小写的<script>,没有做大小写归一化。碰到这类过滤,先试大小写变体,成本最低。如果小写、大写都不行,再考虑用其他标签替代,比如<svg onload=alert(1)>。

Level 5过滤了<script>、onerror等字样,但允许你使用src属性。提交一个<script src=...>可能会发现script关键字被删,所以换思路。可以构造一个a标签链接到外部JS(本地起一个简单的HTTP服务承载js文件即可),但靶场环境没有外网文件时,更推荐直接换可执行点:

<svg onload=alert(1)>

把重点从script标签切换到事件属性上。Filter拦你的事件名时,再考虑其他事件或者编码。

3.2 Level 6-10:大小写绕过与关键字替换的攻防

Level 6的过滤规则里把script、on、src等关键字都过滤了一遍,但没禁用大小写混合写法。我提交的是:

<sCrIpT>alert(1)</sCrIpT>

直接就弹窗了。这一关的启示是:很多开发写正则时没有加i标志(忽略大小写),或者只拦小写,大小写混合是绕过该类过滤的最基础手段。

Level 7把script、on、src这些关键字直接删掉,而且删得比较粗糙。这里有个非常经典的绕过思路——利用删除后的字符拼接。举个例子,如果你提交<scr<script>ipt>,过滤删除掉中间的<script>后,剩下的字符正好拼成<script>。这是“抽词拼接”类绕过,现实中很多过滤确实能用这个思路打穿。

但更稳定的做法是换一个不常见但可执行的标签。我实测可用的是:

<img src=x onerror=alert(1)>

如果连onerror都被覆盖删除,就尝试将onerror写成onerror的某个变体,或者改用其他事件。把备选事件池准备充分是很重要的基本功。

Level 8是相对于前几关的一个转折点。输入被拼接到<a href="你的输入">中,并且把javascript关键字的出现做了适配。如果你直接提交javascript:alert(1),会看到javascript被替换成java\0script之类的东西,导致无法执行。

这时候可以用字符实体绕过匹配:比如将javascript中的某个字母换成HTML实体编码形式,就让正则匹配失灵、浏览器却按字符解析成功。不过在href这种URL上下文中,先尝试大小写绕过更稳:

JavaScRipt:alert(1)

如果也会被大小写归一化,就试下面的编码写法(在本地验证环境中,将字符串进行实体编码后粘贴进去):

&#106;avascript:alert(1)

因为浏览器在解析href属性时,会先把HTML实体解码成原始字符再进行URL解析。而服务端的正则拿到的可能是原始字符串,恰好错过一次匹配时机。

Level 9在Level 8基础上要求输入中必须包含http://字样,否则不会进入下一环节。我最初的思路是构造一段注释包裹伪协议,例如:

javascrip&#116;:alert(1)/*http://*/

新增的部分是/*http://*/,用CSS/JS注释的方式让http://只作为注释文本存在,不影响前面的JS执行。这类“塞垃圾数据满足正则”的绕过思路,在真实业务里也很常见,毕竟很多校验只是机械地检查字符串是否包含某个子串,根本不管这个子串的上下文。

Level 10有个小陷阱,表面输出一个隐藏的input框,你的输入会被放进隐藏域。盲打XSS时看不到输出位置,但源码中能找到。核心操作是:根据源码确定参数名,尝试注入额外参数覆盖原值,让隐藏域变成可触发事件的元素。实际提交时可以考虑:

?t_sort=1" autofocus onfocus=alert(1) x="

通过autofocus加onfocus,让浏览器进入页面时就自动聚焦并触发事件,不需要用户交互。这一点在真实XSS中价值很大,因为你不可能要求每个受害者都去移鼠标。能降低交互成本,就是提高攻击稳定性。

3.3 Level 11-15:请求头字段里的XSS与DOM型初探

Level 11考察的是HTTP头字段的反射。输入点不是表单,而是Referer头。你需要用Burp Suite或者浏览器开发者工具修改请求的Referer值。先正常发送请求,确认页面中有一个hidden input的value来自Referer,你只需要给Referer填入无害值看回显,然后构造:

"><script>alert(1)</script>

如果过滤不严就能直接弹窗。这关的核心是提醒你:输入点并不只在页面表单里,HTTP头字段同样是反射数据源。做渗透测试时,遇到过很多安全运维只关注body参数、忽略请求头的情况。

Level 12和Level 11同理,只不过反射点从Referer换成了User-Agent。UA头有长度限制,但这么短的payload完全没问题。用开发者工具把UA改成payload后刷新即可。这里我踩过一个坑:浏览器或某些代理组件会自动给请求头添加额外字符,但靶场里基本不受影响。做题时注意看清楚参数名再改。

Level 13是Cookie反射。你设置一个自定义Cookie字段,例如user,值为攻击脚本,页面里就会把这个Cookie值输出到某个位置。因为有多个Cookie字段时,过滤逻辑和拼接位置可能不同,建议先设置一个普通值抓包确认对应关系。

Level 14更偏向于外部资源引用。靶场里大致是要求你通过一个URL参数加载外部图片或外链,如果目标允许http://并拼到img src中,可以尝试拼接事件。不过这类关卡依赖外网环境,做题受限时建议直接把思路记录在笔记里,重点理解“URL参数可能控制src”的漏洞模式就行。

Level 15是很多人卡住的一关。它采用了某个前端模板引擎(在知名靶场中常见的是AngularJS的ng-include指令),你可以通过请求一个自定义URL,将参数作为模板路径,最终把指定文件的内容包含进来。观众能成功弹窗的方式通常是把请求换成符合题目要求的URL。如果环境无法运行,也不影响你理解:这本质上是前端模板注入类XSS,跟普通服务端拼接HTML完全不同。你需要在开发调试里看清哪个指令在处理你的输入、它支持哪些外部资源引用协议,然后构造含有恶意内容的资源地址。

3.4 Level 16-20:空格、正则与编码组合,把payload打磨到极限

Level 16过滤了空格,这是一道分水岭。常规payload里到处都是空格,一旦空格没了,整个标签结构会直接失败。你需要找到替代空格的字符。最常见的方法是使用换行符%0a或回车符%0d,还有/和Tab字符%09。在HTML解析中,很多空白字符都能起到分隔属性的作用。我最终通过的payload类似:

<svg%0aonload=alert(1)>

如果你在浏览器地址栏做编码时没成功,就换用Burp或开发者工具直接改请求体发送原始字节。编码是否被二次解码,直接决定了%0a能不能变成真正的换行。

Level 17和Level 18的考点比较类似,输入会被拼到两个HTML属性的拼接处,一个出现在标签名位置,一个出现在属性值位置。突破关键还是通过闭合前面的标签与引号,再注入自己的事件属性。我用的payload是:

"><img src=x onmouseover=alert(1)>

不过事件触发方式容易受交互限制,所以你在本地验证时,哪怕只是移动到图片上就弹窗也算正确,不需要被“必须点击”误导。

Level 19和Level 20比较复杂。网上很多教程会说这关基于Flash的跨域配置,听起来跟普通XSS没关系。就做题环境而言,现在大部分浏览器都不再默认加载Flash,因此这两关更多是“读代码理解思路”而非实际弹窗。如果你是为了面试或实际防御,建议重点看前面的反射型关卡;如果你是打CTF,也可以尝试用其他标签替代,但价值有限。我个人的习惯是:把这两关的原理笔记保存下来,不做无谓耗神。

4. 做题卡壳时怎么办:排查流程与高频坑位

4.1 先确定真实渲染结果,再判断为什么失败

卡关时,很多人的第一反应是换payload,但我推荐你先打开浏览器的开发者工具,切到Elements面板,查看输入位置的实际DOM结构。比如你提交一个",页面源码里它变成&quot;,那说明服务端做了HTML实体转义;如果开发者工具里显示你的引号已经成功闭合了标签但还是不弹窗,那问题可能出在JavaScript解析层,比如引号截断逻辑不对。

我遇到太多人,提交一个<script>alert(1)</script>不弹窗,就直接认定是WAF拦截,完全没意识到自己的输入其实是被放在某个标签的属性值里了,脚本根本没有执行上下文。定位到真实DOM结构,很多问题能当场解决。

4.2 高频报错与对应原因速查

现象可能原因下一步操作
脚本不弹窗,但源码中能看到输入的标签输入被当成文本,未进入可执行HTML节点看DOM上下文,补闭合引号和标签
标签源码变成&lt;、&quot;等实体服务端做了HTML实体转义尝试大小写、编码、换标签来绕过过滤规则本身
javascript:开头的href不行关键字被过滤或浏览器策略限制使用HTML实体编码、外部JS引用等替代方案
空格被过滤后整个payload失效过滤了空格字符用%0a、%0d、Tab、/替代分隔符
提交后页面源码没变化输入点不在GET参数,可能在请求头或DOM逻辑中检查Referer、UA、Cookie字段的渲染位置,或打开Network面板

4.3 刷完靶场后,我沉淀下来的三条做题习惯

第一条,每次只改动变量中的一项。比如先改闭合方式,再改标签种类,最后改动编码方式。如果你同时改了三个东西,成功了也不知道哪个变量起作用,真的会浪费大量时间。

第二条,用Burp或浏览器开发者工具直接看请求,而不是只改输入框。因为某些输入点会被框架二次编码,你在输入框里看到的字符串,和实际发送到服务端的字节不一样。看请求体才能确认最终形态。

第三条,把每个过关的payload记录下来,并附上“为什么这个能过”。不要只存一份最终答案。我自己的笔记里会写“这一关是过滤了onerror,所以用了onmouseover,且属性前用/代替空格”。一旦养成记录原因的习惯,下次碰到类似场景,你甚至可以从笔记里反推过滤规则,而不是每次都从头试起。

5. 实战之外:学习XSS的正确姿势

把XSS-labs刷完,你只是建立了基本的XSS攻击面认知,距离真正的实战还有很大的距离。我做这类靶场练习已经比较长的时间,个人最有价值的体会是:靶场是在帮你建立“输入点-处理过程-浏览器解析-触发执行”的思维模型,而真实业务里的XSS远比这些关卡复杂。

你需要额外补的知识点包括:CSP策略如何影响XSS利用(如果响应头里带着Content-Security-Policy,即使你成功注入了标签,也可能被策略拦截而无法执行);HttpOnly与Cookie的关系(HttpOnly能防止脚本读取Cookie,但不是XSS的根本防御手段);浏览器自带XSS保护机制在哪些场景会自动拦截部分payload;以及服务端过滤的常见实现方式(黑名单、白名单、正则替换、HTML实体处理)。

如果你还想继续往下深化,建议做这几件事:把XSS-labs与Burp Suite联动,自己尝试抓包分析每一次请求,观察payload在被服务端处理前后发生了哪些变化,这是任何教程都替代不了的“手感”训练。用靶场加深对DOM型XSS的理解,尤其是前端JS对location.hash、document.referrer、window.name这些数据源的处理逻辑,这部分在真实前端框架里经常出现。最后一个建议是,把你收集到的payload整理成自己的笔记库,按“绕过场景”分类,而不是按“第几关”分类,以后碰到新场景可以快速查阅。

我个人做题时养成的一个小习惯是:每过一关,就在本子上画一遍“我的输入经过什么过滤、在什么位置触发、为什么能执行”。画得多了,很多能力就在不知不觉中长在身上。希望这篇心得能帮你在XSS这条路少走一点弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 5:03:28

ComfyUI+MiniMax H3本地部署:低成本批量视频生成实战

1. 为什么这套组合值得折腾&#xff1a;从云端订阅到本地工作流的转向AI视频生成这块&#xff0c;过去一年我最大的感受就是“云端排队排到怀疑人生”。尤其是做批量分镜测试的时候&#xff0c;一个镜头改三次参数&#xff0c;云端额度就见底了&#xff0c;更别提那些需要反复抽…

作者头像 李华
网站建设 2026/10/17 5:02:04

ASP.NET Web Forms信息发布系统:本地IIS部署+SQL Server完整源码

简介&#xff1a;这是一套面向计算机专业本科生的毕业设计级信息发布系统源码&#xff0c;融合C#、ASP.NET Web开发与基础数据库实践&#xff0c;适用于课程设计、毕设选题及.NET初学者项目实战。资源包含577个文件&#xff0c;主体为228个C#类文件&#xff08;如VideoPlayer、…

作者头像 李华
网站建设 2026/10/17 5:01:49

网络工程毕业设计选题指南:四个可落地方向与避坑要点

如果你也正在为网络工程毕设的选题头大&#xff0c;这一篇值得认真看完。前阵子一位师弟抱着一份“基于深度学习的网络异常检测研究”开题报告来找我&#xff0c;说想往安全方向做&#xff0c;细问之下数据集还没找到、检测指标也没定义&#xff0c;甚至连“准备检测哪一类异常…

作者头像 李华
网站建设 2026/10/17 5:01:35

大衍数构造稀疏校验矩阵的LDPC码误码率仿真与对比

LDPC 码的仿真调试起来&#xff0c;比很多人想象中要麻烦。麻烦的不是 BP 译码本身&#xff0c;而是从校验矩阵到对比实验的那一整条链路&#xff1a;矩阵怎么构造才够稀疏、短环怎么避开、迭代次数和码率码长对误码率的影响怎么分开看。这篇文章要讲的&#xff0c;是一套我用 …

作者头像 李华
网站建设 2026/10/17 5:01:14

从智能体到物理AI:2026年AI技术趋势与落地实践观察

1. 今天的AI圈在聊什么&#xff1a;一份来自一线的观察切片如果你每天泡在AI相关的社群、开源仓库和论文推送里&#xff0c;会明显感觉到2026年下半年的讨论风向和上半年不太一样了。大家不再疯狂追逐“某某模型又刷榜了”这种表面热度&#xff0c;而是开始扎堆讨论几个更本质的…

作者头像 李华
网站建设 2026/10/17 5:01:06

Python调用Netconf自动化配置H3C静态路由

简介&#xff1a;本资源是一套面向网络运维工程师与Python自动化初学者的H3C交换机NETCONF路由配置实践方案&#xff0c;聚焦静态路由条目的增删自动化&#xff0c;解决传统CLI手工配置效率低、易出错、难复用等痛点。压缩包共14个文件&#xff0c;含8个核心Python脚本&#xf…

作者头像 李华