文章总结: 本文复盘了严苛WAF环境下的SQL注入绕过实战。目标WAF封禁了关键字与完整函数调用形态,阻断常规注入。作者利用报错获取原SQL结构,发现注入点位于函数参数内,转而构造不闭合的Payload片段,借助原生SQL语句的括号环境闭合函数调用,利用UPDATEXML成功实现报错注入。该方法跳出了构造完整Payload的思维定势,通过精准利用语法环境特性规避规则限制,为实战攻防提供了高价值的参考思路。 综合评分: 88 文章分类: 渗透测试,WEB安全,实战经验,红队
实战复盘:严苛 WAF 防护下的 SQL 注入绕过思路与实现
原创
洞悉安全团队-han 洞悉安全团队-han
洞悉安全团队
2026年3月9日 11:01 浙江
点击上方蓝字关注我们!
在 Web 安全攻防场景中,WAF(Web 应用防火墙)作为核心防护屏障,往往会通过精准的规则拦截封堵绝大多数常规注入手段。本文将复盘一次实战场景下,针对某系统严苛 WAF 规则的 SQL 注入绕过过程,拆解从规则分析到利用环境特性突破限制的完整思路,为同类场景的渗透测试提供参考。
一、环境背景与 WAF 规则研判
本次测试目标系统的注入点位于trainingSite参数处,经模糊测试(Fuzz)后,梳理出 WAF 核心过滤规则如下:
- 比较运算符拦截:直接屏蔽
=、<、>等核心比较符号,阻断常规条件判断逻辑; - 关键字封禁:
SELECT、UNION、LIKE、REGEX等查询类关键字均被拦截,无法构造常规查询语句; - 函数调用形态拦截:只要 payload 中出现 “函数名 + 完整闭合括号” 的调用形态(如
func()、func(1)),直接返回 403 拦截; - 空括号模式拦截:即便无实际函数名,仅出现
xxxx()这类 “字符 + 完整闭合括号” 的结构,同样触发拦截。
上述规则几乎封死了传统 SQL 注入的核心手段:无法构造条件判断、无法引入查询语句、无法直接调用函数(如时间盲注的sleep()、报错注入的extractvalue()等),常规注入思路均难以推进。
二、规则突破:利用原生语法环境规避拦截
分享一下思路,这是正常返回包的情况,注入点在trainingSite参数这里。
我们给他加个aaaa可以看到报错如下
trainingSite=1aaaaaaa
根据报错我们能拿到完整的执行语句
SELECT COUNT(1) FROM (SELECT id,equipment_name,qr_code,equiment_type,upload_img,cover_img,file_video_id,training_site,suitable_people,avoid_people,instructions,create_by,create_time,update_time FROM t_equipment WHERE (FIND_IN_SET (1aaaaaaa, training_site ))) TOTAL
简单分析一下1aaaaaaa是我们的注入点
现在可以开始打sql注入了
首先肯定想到的是用)))payload–
这种形式直接注释掉后续内容直接执行payload不拼接很方便
但是这里行不通因为上面我fuzz后总结的waf的规律可以看出这种形式的payload无法执行任意函数,没有函数也就意味着很难有效的sql注入
如图
仔细对比这三张图,其实差异很明确:
aaaa()这种完整函数调用形态会被直接拦截(403)。1,training_site)%20AND%20FIND_IN_SET(1不闭合括号时不会触发拦截,能正常执行。- 但一旦写成
1,training_site)%20AND%20FIND_IN_SET(1),括号闭合后又会被 ban。
这基本说明:WAF 并不是单纯拦截某个函数名,而是拦截“函数名(…)”这种完整调用结构。因此常见的时间盲注、报错注入等手段都会受影响——因为无论哪种注入方式,几乎都绕不开函数调用;同时 select/union 等关键字也被 ban,= < > 也不可用,整体限制非常苛刻。
在这种前提下,传统的 ) payload -- 思路就基本走不通了:一旦用注释截断后续语句,payload 里又无法写出函数调用,注入很难继续推进。于是我只能转向“闭合结构”本身,先构造出:
1,training_site)%20AND%20FIND_IN_SET(1
但问题仍然存在:payload 里依旧不能出现 substring/concat/sleep 等函数调用,看似会被彻底卡死
不过这里有一个关键点:我们已经拿到了原始 SQL,而且注入点本身就在多层括号和函数参数内部:
... WHERE (FIND_IN_SET(1aaaaaaa, training_site)) ...
也就是说:原 SQL 天然提供了括号环境和“函数形态”的外壳。在上面的 payload 中,FIND_IN_SET 已经是一个现成的函数名,我们理论上可以把它替换成其他函数名(如 sleep、substring 等),并让“最终拼接后的 SQL”形成函数执行。
但继续测试后发现,这个环境几乎被“写死”成只能使用一个函数名: 如果引入多个函数(例如 SUBSTRING + CAST),要么会因为出现完整调用触发 WAF,要么因为括号无法补全导致语法错误。例如下面这种思路虽然直观:
trainingSite=1,training_site)%20OR%20SUBSTRING(@@version,cast(@@version%20as%20signed
而如果为了绕过拦截不写闭合括号,又会变成括号不匹配直接报错。(右括号少一个)
进一步还有一个细节:注入位置后面原本就会拼接 , training_site 这个参数。比如你尝试写 IF(...) 时,最终会被拼成类似:
IF(1=1,5,5,training_site)
这会破坏我们原本的参数结构,导致逻辑难以控制。
因此这里的函数选择必须满足几个条件:
- 只能用一个函数名(否则触发 403 或语法错误)
- 至少需要两个参数(这样才“容得下”后面被拼接进来的
training_site) - 最后一个被拼接进来的参数对整体影响尽量小
- 最好能直接回显信息(否则盲注会非常难写)
基于这些条件,我把方向转为报错注入,并逐个测试常见报错函数后,发现 UPDATEXML 正好满足要求,于是得到最终 payload:
1,training_site)%20OR%20UPDATEXML(1,current_user
利用原 SQL 的括号/参数环境完成拼接后即可成功触发报错回显,从而实现注入。
这里@@version之类的变量也能打
但是不能爆出库名之类的因为database()函数都被ban了….任何函数都不能用
只能爆破一些变量或者current_user之类的
总结:
本次绕过的核心在于跳出 “构造完整 Payload” 的常规思维,精准研判 WAF 拦截规则的核心特征,充分利用目标系统原生的 SQL 语法环境(多层括号、函数参数结构),将 Payload 拆分为 “不完整片段”,借助系统自身的语句拼接完成函数调用,最终实现绕过。
在护网、众测、企业 SRC 等实战场景中,此类依托环境特性突破 WAF 的思路具备较高的实用价值。Web 安全攻防的关键在于对规则的精准拆解与对环境的灵活适配,不同场景下的 WAF 规则差异显著,唯有结合具体环境分析限制条件,方能找到有效突破路径。
红队面试高频 42 题(2026 实战精简版)
众测实战经验-手势密码专测
捷报!洞悉安全斩获漏洞盒子全明星擂台赛大魔王擂台区胜利!
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:洞悉安全团队 洞悉安全团队-han 洞悉安全团队-han《实战复盘:严苛 WAF 防护下的 SQL 注入绕过思路与实现》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论