白帽故事 · 2025年12月8日

机器“聪明”与人“狡黠”:黑客机器人如何用参数污染“突破”顶级WAF

简介

在最近的一次自主渗透测试中,国外研究团队的引擎在一个客户的应用程序中发现了一个有趣的 XSS (跨站脚本) 漏洞。

目标是一个运行在 Web 应用程序防火墙 (WAF) 后面的 ASP.NET 应用程序,该 WAF 具有非常严格的配置。

漏洞本身很简单,攻击者可以突破由单引号分隔的 Javascript 字符串。然而,由于应用程序受到高度限制性 WAF 的保护,传统的 XSS Payload 会被阻止了。今天的文章主要讲述如何绕过该 WAF 从而引导我们进入一个“兔子洞”的故事。

这种情况给我们带来了一个经典的安全挑战:当防御机制主动阻止漏洞利用时,如何证明漏洞的可利用性?

这是一个典型的 PoC||GTFO 的情况,与往常一样,细节决定成败。

研究人员需要发挥创造力,并了解如何滥用 WAF 引擎、参数解析器和 Javascript 解释器之间的解析差异,Javascript 解释器最终将在受害者浏览器中执行代码。

当之前滥用 ASP.NET 的参数污染行为来利用其他类型的注入时,突破就来了。

将这种技术与手中漏洞的特定上下文相结合似乎非常有可能,我们可以通过在不同的参数之间拆分代码来构建有效的 Javascript,以避免 WAF 检测。

构建Payload

了解参数污染

HTTP 参数污染是一种利用不同技术处理重复 HTTP 参数的方式不一致的技术。当请求中存在多个具有相同名称的参数时,各种 Web 框架会以不同的方式处理它们。

有些连接所有值,有些只取第一个或最后一个出现的值,有些甚至会创建数组。

参数污染的行为在不同的 Web 技术中差异很大。其他研究人员已经编译了关于不同框架如何行为的非常全面的总结 [1-3]。

由于测试用例非常具体,我们过滤掉了所有未在最终输出中包含所有参数的框架,因此只剩下 5 个不同的框架:

框架 输入 输出
ASP.NET param=val1&param=val2 param=val1,val2
ASP param=val1&param=val2 param=val1,val2
Golang net/http – r.URL.Query()["param"] param=val1&param=val2 param=[‘val1′,’val2’]
Python – Zope param=val1&param=val2 param=[‘val1′,’val2’]
Node.js param=val1&param=val2 param=val1,val2

幸运的是,ASP.NET 的行为特别有趣,并且符合我们的用例。

当 ASP.NET 遇到多个具有相同名称的参数时,它会使用 HttpUtility.ParseQueryString() 方法将它们的值与逗号连接起来。

此行为记录在 Microsoft 的官方文档中,提到“同一查询字符串参数的多次出现被列为单个条目,每个值之间用逗号分隔”。

当与 Javascript 注入上下文结合使用时,此类参数污染的威力变得显而易见。

考虑一个类似于我们所面临的场景,其中用户输入反映在 Javascript 字符串中:

userInput = 'USER_CONTROLLED_DATA';

解决问题的一个简单方法是尝试使用引号来突破并注入代码:

'; alert(1); //

然而,大多数 WAF 都配备了检测这种明显模式的功能 (文章后面会提到),参数污染方法采用不同的策略。

Javascript 的语法允许使用逗号分隔的表达式,其中可以按顺序执行多个语句。这种语言特性与 ASP.NET 的逗号连接行为相结合,为复杂的绕过创造了机会。

当 ASP.NET 处理像这样的查询字符串时:

/?q=1'&q=alert(1)&q='2

它将这些值连接成:

1',alert(1),'2

当被插入到上面的 Javascript 上下文中时:

userInput = '1',alert(1),'2';

生成的 Javascript 在语法上是有效的,并将执行 alert 函数。

Javascript 中的逗号运算符从左到右计算每个表达式,并返回最后一个表达式的值,这种模式广泛用于 Javascript 缩小和混淆。

为了好玩和 JS 注入而绕过 WAF

研究人员决定测试最流行的 WAF 是否适合以上的想法。

显然,我们不认为这可能是某种万能的 WAF 绕过,但如果不能确切地知道这种技术有多好,好奇心也会杀死我们。

WAF 技术的类型

现代 Web 应用程序防火墙使用两种主要的检测方法运行,每种方法在防御复杂攻击方面都具有不同的优势和局限性。

基于签名的 WAF 是传统 Web 安全中的主要防御形式之一。这些系统维护已知攻击模式的数据库,并将传入的请求与这些签名进行比较。

当检测到匹配项时,WAF 可以记录、警告或阻止该请求。基于签名的检测的主要优势在于其精确性。

当攻击与已知签名匹配时,误报通常很低。签名也可以按其置信度进行排名,从而允许配置优先选择较低的误报率而不是更严格的安全性。但是,这些系统难以应对新的攻击媒介,并且需要不断更新签名才能保持有效。

基于机器学习的 WAF 代表了 Web 应用程序安全的下一步。这些系统分析流量模式和用户行为,以识别可能指示攻击的异常请求。

与基于签名的系统不同,基于机器学习的 WAF 可以潜在地检测 0-day 漏洞和以前未知的攻击媒介。

这显然是有代价的,因为不能保证低误报率,并且如果不与良好的预训练真值源相结合,可能会使流量水平低的应用程序更容易受到攻击。

为什么 WAF 难以应对参数污染

研究人员提出了几个原因,说明为什么传统 WAF 在尝试检测基于参数污染的攻击时面临多个挑战:

  • WAF 通常分析单个参数,它们可能会错过多个参数之间的关系,这些参数在组合时会形成恶意代码
  • 大多数 WAF 缺乏对不同 Web 框架如何处理参数解析的深入了解,它们可能不会模拟 ASP.NET 的特定逗号连接行为
  • 基于规则的 WAF 依赖于已知的攻击模式,参数污染技术创建的Payload与传统的 XSS 签名不匹配,同时在功能上保持等效
  • 当将此技术与各种混淆技术相结合时,通过静态分析很难检测到实际的恶意意图

为了检测这些攻击,WAF 需要实施特定于框架的参数解析逻辑和上下文感知的 Javascript 分析,这些功能远远超出了模式匹配。

还值得注意的是,为 WAF 配备执行此类分析的必要手段将是一场性能噩梦,因为 WAF 旨在在代理请求时尽可能减少开销。

WAF 配置测试

评估包括了 17 种不同的 WAF 配置,涵盖主要的云提供商和安全供应商。

所有配置都代表了 Web 安全的不同方法,从传统的基于规则的解决方案到基于机器学习的解决方案。

厂商/产品 配置 规则集
AWS WAF – AWS托管规则集 默认 管理员保护、Amazon IP信誉列表、匿名IP列表、核心规则集、已知恶意输入、Linux操作系统、PHP应用、POSIX操作系统、SQL数据库、Windows操作系统、WordPress应用
AWS WAF – Cloudbric 规则集 默认 API保护、OWASP Top 10规则集
AWS WAF – Cyber Security Cloud 规则集 默认 API网关/无服务器、高安全级别OWASP集
AWS WAF – F5 规则集 默认 API安全规则、Web攻击利用(OWASP)规则、CVE规则
AWS WAF – Fortinet 规则集 默认 API安全、OWASP Top 10 – 完整规则集
Google Cloud Armor 所有规则启用最高敏感度 SQL注入、XSS(跨站脚本)、本地文件包含、远程文件包含、远程代码执行、方法强制执行、扫描器检测、协议攻击、PHP、会话固定、Java、Node.js (v33-stable)
Azure WAF 默认 默认规则集 2.1
FortiWeb 内联标准防护 默认
FortiWeb 扩展标准防护 默认
Cloudflare WAF 默认 Cloudflare托管规则 + OWASP核心规则
open-appsec 中+敏感度 默认、基础模型
open-appsec 高+敏感度 默认、基础模型
open-appsec 仅关键敏感度 默认、基础模型
Akamai 默认 默认
F5 Big-IP高级WAF 签名分级停用 + 低准确度签名 快速部署策略
NGINX App Protect WAF 默认 默认
NGINX App Protect WAF 严格 严格

测试方法

研究人员开发了三个Payload,用于评估每个WAF对基于参数污染的JavaScript注入攻击的敏感性:

Payload1 – 简单注入:

q=';alert(1),'

这个基础Payload旨在测试基本的JavaScript注入检测能力,它通过非常明显地尝试跳出字符串上下文并在单个参数中执行代码来实现。

Payload2 – 带分号的参数污染:

q=1'+1;let+asd=window&q=def='al'+'ert'+;asd1&q=2;'

这个Payload引入了参数污染,并加入了一些巧妙的变量赋值和字符串连接,以逃避模式匹配检测。

Payload3 – 带换行符的参数污染:

q=1'%0aasd=window&q=def="al"+"ert"&q=asd1+'

这个有Payload使用换行符(%0a)代替分号来开启一个新的JavaScript表达式。

这种特意设计使这两个Payload能够独立于注入上下文工作,因为并非所有上下文都支持逗号操作符,所以必须创建一个新的JavaScript表达式。

Payload4 – 基于启发式的方法:

研究人员还使用其自研引擎的当前能力来测试了每个WAF,以判断基于启发式的技术是否能检测到受WAF保护的资产中的此类XSS攻击。

测试结果

测试结果如下表所示(✅ = 被拦截,❌ = 绕过/未检测到):

WAF Payload1 Payload2 Payload3 Ethiack 引擎
AWS WAF – AWS托管规则集
AWS WAF – Cloudbric 规则集
AWS WAF – Cyber Security Cloud 规则集
AWS WAF – F5 规则集
AWS WAF – Fortinet 规则集
Google Cloud Armor – 预配置的ModSecurity规则
Azure WAF – Microsoft默认规则集 2.1
FortiWeb – 内联标准防护
FortiWeb – 内联扩展防护
Cloudflare WAF – 托管和OWASP核心规则集
open-appsec* – 中+敏感度
open-appsec* – 高+敏感度
open-appsec* – 仅关键敏感度
Akamai
F5 BIG-IP高级WAF – 快速部署策略
F5 NGINX App Protect WAF – 默认
F5 NGINX App Protect WAF – 严格

*测试结果是使用open-appsec默认配置中的基本模型获得的结果

测试结果揭示了关于现代WAF能力的几个有趣发现:

  1. 仅5种配置成功拦截了全部3个Payload:

    • 采用ModSecurity规则的Google Cloud Armor
    • 采用Microsoft默认规则集2.1的Azure WAF
    • open-appsec的所有3种配置。
  2. 3个AWS WAF规则集被所有测试的Payload绕过:

    • AWS托管规则
    • Cyber Security Cloud规则集
    • F5规则集
  3. **随着Payload复杂性的增加,易受攻击的WAF比例也随之上升。

简单Payload(Payload1)的绕过率仅为17.6%,而最复杂的参数污染Payload(Payload3)绕过了70.6%的已测试配置。

然而,基于启发式的方法显示出100%的绕过率,有效绕过了所有WAF防御。

这些数据表明,传统的基于签名的WAF难以应对参数污染技术,而融合了机器学习的更现代解决方案虽然展现出了更优越的防御能力,但事实证明(至少在训练数据量较少的情况下)它们不足以抵御他们专有的基于启发式的检测机制。

黑客机器人(Hackbot)能做得更好吗?

在手动评估之后,研究人员的好奇心并未停歇,他们决定部署完全自主的黑客机器人,去攻击那些成功拦截了所有手动制作的测试Payload的WAF配置(Google Cloud Armor, Azure WAF 和 open-appsec)。

目的是探究黑客机器人是否能发现遗漏的东西。

Azure WAF

黑客机器人找到了针对先前“未被击败”的、采用Microsoft默认规则集2.1的Azure WAF的绕过方法。

尽管他们手动制作的Payload已被完全拦截,但黑客机器人发现了一个令人惊讶的简单绕过,这个绕过在之前的Payload构思中被忽略了:

test\\';alert(1);//

这个Payload利用了Azure WAF处理转义字符的方式与JavaScript处理方式之间的细微解析差异。

双反斜杠和单引号组合(\\’)在WAF的模式匹配和JavaScript解析器中的解释不同。

当JavaScript会转义那个转义了引号的反斜杠时,Azure WAF会将该转义了引号的反斜杠解释为一个被转义的引号本身。

file

Google Cloud Armor

不幸的是,研究人员发现黑客机器人并未能找到绕过配置非常严格的Google Cloud Armor的方法。

不过,在其竭力搜索可有效规避WAF的Payload时,确实揭示出一些之前分析中被忽略的有趣应用层行为。

在探测应用程序的过程中,黑客机器人推断出服务器对参数的解析是不区分大小写的,并随即在后续测试中开始运用这一特性,试图突破WAF的防护。

这难道不令人惊叹吗?

file

open-appsec

而当将黑客机器人用于测试open-appsec时,情况则大不相同。

研究人员原本对此不抱期望,但他们的黑客机器人却在创纪录的时间内让人们大吃一惊。仅仅用了30秒,它就为处于“仅关键敏感度”配置下的open-appsec找到了一个有效的绕过方法。

这结果绝对令人瞠目结舌,别误会,之前绕过Azure WAF也没花太多时间,但这次的发现无疑摘得了桂冠。

file

由于open-appsec依靠机器学习进行判断,研究人员决定测试一下,如果最初的Payload被拦截,他们的黑客机器人是否能够自我调整。

研究人员生成了足够的流量,使得基于alert的Payload开始被WAF屏蔽,然后让黑客机器人自由发挥。

这一次,几乎是眨眼之间,黑客机器人就找到了一个绕过方法——它用confirm函数替代了alert函数。

file

研究人员同样测试了“中+敏感度”和“高+敏感度”配置,结果同样迅速,黑客机器人不仅成功复现了相同的结果,甚至还发现了额外的Payload,例如:q='+new Function('a'+'lert(1)')()+'

**测试结果是在open-appsec默认配置下使用基础模型获得

对于这个"小家伙"来说,这表现可真是“聪明”!

这些发现凸显了研究人员所坚信的最重要的原则之一:

自动化是对手动测试的补充
虽然人类的专业知识对于开发新的攻击技术至关重要,但黑客机器人可以帮助探索那些在手动测试中可能被忽略的变体。这非常有益,因为它意味着人类可以将精力集中在发现更具创造性的漏洞上——正如上面所做的那样!

最终思考

参数污染的“兔子洞”

在手动研究中最惊人的发现,是参数污染技术对传统WAF的极高有效性。绕过成功率从简单Payload的17.6%飙升至复杂参数污染Payload的70.6%,数据清晰地表明,依赖模式匹配的WAF难以抵御那些利用WAF与Web应用在底层解析上存在差异的攻击。

此漏洞源于一个最根本的安全挑战:WAF必须在未完全模拟应用程序解析行为的情况下做出安全决策,ASP.NET的逗号连接行为所引发的差异,很难通过传统的签名分析来检测。

机器学习的优势

基于机器学习的WAF表现出更高的检测率,这表明行为检测相比基于规则的方法具有显著优势。即使Payload与已知签名不符,这些系统也能识别恶意内容,从而为抵御新型攻击向量提供了保护。

然而,黑客机器人证明,该模型仍存在缺陷。尽管研究人员(通过生成良性流量)证实了这类WAF对恶意流量具备一定的适应性,但黑客机器人依然成功规避了其学习过程,并且几乎“瞬间”就找到了替代的绕过方法。

复杂性悖论

或许最令人失望的发现是,复杂的攻击技术竟能与极其简单的绕过方法共存。

尽管研究人员开发的复杂参数污染Payload击败了大多数WAF,但黑客机器人揭示,即使是像Azure WAF和open-appsec这样看似坚固的产品,也能被相对直接的Payload绕过。

这一发现突显了基础安全策略中的一个关键弱点:企业可能投入巨资部署昂贵的WAF技术,却依然暴露在那些利用基础实现缺陷或配置疏忽的攻击之下。

这也提醒我们,绝不能将WAF用作修复不安全代码这一根本问题的“创可贴”。

黑客机器人的崛起

最后,本文也展示了黑客机器人所蕴含的力量。

一方面表明研究人员的引擎能够做到极致的隐蔽,在不触发任何被测WAF警报的情况下检测此类XSS。

另一方面,借助黑客机器人强大的原始黑客能力,达到了更高的目标——对那些先前仅靠自身研究无法攻克的WAF,进行了更细致、更系统的评估。

参考资料

[1] https://swisskyrepo.github.io/PayloadsAllTheThings/HTTP%20Parameter%20Pollution/#methodology
[2] https://www.intigriti.com/researchers/hackademy/http-parameter-pollution
[3] https://www.madlab.it/slides/BHEU2011/whitepaper-bhEU2011.pdf

原文:https://blog.ethiack.com/blog/bypassing-wafs-for-fun-and-js-injection-with-parameter-pollution