freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

SQL注入绕WAF姿势:当if被过滤了怎么办?
2025-03-07 10:55:38
所属地 广东省

引言

SQL注入在我们日常的渗透中是属于常见的一类漏洞,但是最令我们头疼的不是什么参数化查询,而是WAF。但是如果直接介绍的话,我发现效果并不好。因为我本身作为一个学习者,发现很多的文章只是单单的把姿势给写出来,但却不介绍以及解释这些姿势背后的特性,以及可能会踩雷的地方,这对初学者极其不友好。正好,我最近自己也在学习绕WAF的方式,就把自己的一些学习所得,进行一个记录以及分享,主要是给大家参考我学习的一个思路,介绍的姿势其实不一定能够绕过WAF,因为不同的WAF绕过的语句都是不同的,还是要通过SQL的官方文档上面的语句自己进行一个多种结合的尝试才可能实现绕过WAF~

目录

本文涉及的函数有:if | case when ... then ... else ... end | IFNULL | NULLIF

注意事项

1.本文的场景默认以:SELECT * FROM users WHERE id='$id' LIMIT 0,1 其中$id是我们的输入点,也就是sqllabs靶场第一关为例。也会涉及到SELECT * FROM users WHERE id='$id' 场景~

2.本次讨论只是 if 被过滤的情况,其他情况不作为本次考虑范围内。

3.文章只讨论布尔注入以及时间注入两种

4.非小白师傅可以直接跳过第一个知识点

正式开始

知识点一:if基础使用

说到if的时候,最为经典也是常用的两种注入类型:布尔注入、时间注入

在这两种注入中,if是我们绕不开的关键字。

例如:

数据库名称为security的前提下

1' and if(database()='security',1,0) --+

1741142702_67c7baae708195da29621.png!small?1741142668095

1' and if(database()='sec',1,0) --+

1741142818_67c7bb2214610317f9e03.png!small?1741142774619

逐一介绍:

if在mysql中的语法是:if(a=b, c, d) --> 当a=b的时候,返回c,否则返回b

if(database()='sec',1,0) --> 当数据库名为sec的时候,if(database()='sec',1,0)会等于1,否则会等于0

那么我们说了,数据库名称为security的前提下,所以if(database()='sec',1,0)会等于0。从而不返回数据。


这时候有人问了,主播主播,为什么返回0了就不回显数据了?

因为这个和 and 有关系,完整的语句是:

这里将 $id 替换为1' and if(database()='sec',1,0) --+
SELECT * FROM users WHERE id='1' and if(database()='security',1,0) --+ LIMIT 0,1

and的逻辑是:

A and B ,只有当A和B同时满足(同时为true)才会返回结果。

1=1 and 1=2 --> 1=1满足了(true),1=2不满足(false),这样就不会返回结果,必须是:
1=1 and 2=2 --> 这样两个都同时相等,同时为(true),才会返回结果

而1和0,你可以理解为代表着true和false,但值得注意的是1和0并不是等价于true与false。

他们其中的逻辑是这样的id='1' and if(database()='security',1,0),如果当前数据库名是security,if()函数返回1(真),此时整个WHERE子句变为id='1' and 1,就会去查询id=1的数据。反之,id='1' and if(database()='sec',1,0),此时整个WHERE子句变为id='1' and 0,在and表达式中,0 --> false,id='1' and false,有一个假条件,所以这个and句子就失效了,不会去执行查询id='1'的过程。

简单来说:1和0分别代表着true和false,当我们and中有false的时候,就不会返回(查询出)任何的数据。


好,现在将所有的概念连在一起:
第一句:SELECT * FROM users WHERE id='1' and if(database()='security',1,0) --+ LIMIT 0,1
第二句:SELECT * FROM users WHERE id='1' and if(database()='sec',1,0) --+ LIMIT 0,1

第一句逻辑if(database()='security',1,0)因为数据库名字为security,所以返回了1 --> true,SELECT * FROM users WHERE id='1'成功进行了查询,所以有数据回显。

第一句逻辑if(database()='sec',1,0)因为数据库名字为security,所以返回了0 --> false,SELECT * FROM users WHERE id='1'没有进行查询,所以没有数据。

理解了上面的,就很好理解下面的常用测试语句:

1' and if('s'=substr(database(),1,1),1,0) -- -

1741144666_67c7c25a75f38a63d3607.png!small?1741144623056

1' and if('x'=substr(database(),1,1),1,0) -- -

1741144652_67c7c24c8933f4ad19771.png!small?1741144608977

substr(database(), a, b)的作用很简单,substr用于切割字符串,a表示切割第几位,b表示切割的长度。

例如:

substr('123456789', 1, 1) --> 1, substr('123456789', 2, 1) --> 2

substr('123456789', 1, 5) --> 12345, substr('123456789', 2, 5) --> 23456

这里我们就是把数据库名字:security 进行了第一位的切割,切割出的结果是:s

if('s'=substr(database(),1,1),1,0) 因为substr(database(),1,1)确实等于s,所以if就返回了1,有数据

if('x'=substr(database(),1,1),1,0) 因为substr(database(),1,1)不等于x,所以if就返回了0,没有数据


那么布尔注入

其实就是把if('X'=substr(database(),1,1),1,0)中的X设置为爆破的目标,使用手工或者工具,将所有的大小写26位字母以及数字进行一次尝试,最终通过if('s'=substr(database(),1,1),1,0),if('s'=substr(database(),2,1),1,0),if('s'=substr(database(),3,1),1,0)一位一位的将数据库名称给试出来


时间注入就更简单了

1' and if('s'=substr(database(),1,1),1,sleep(5)) -- - 这段语句,只要x中的字符不等于数据库的名称,就会响应5秒。如果等于,就会直接返回结果

1' and if('s'=substr(database(),1,1),1,sleep(5)) -- -

1741145411_67c7c543a9de4c64362b5.png!small?1741145368529

补充:

1' and if(114=ascii(substr(user(),1,1)),1,sleep(4))-- - 这个其实和前面没有区别,ascii码是为了更加的便捷进行以及不容易出错进行注入。

Mysql中ascii码转的是十进制,也就是这里114 --> 在ascii码表中对应的是 r 。

ascii函数也很简单,就是把字符转为ascii码,例如字符串为r --> 114 码

但有个特性:​仅处理第一个字符:无论字符串多长,只取第一个字符计算 ASCII 码。

所以才需要使用切片函数substr()

ascii表:

# SQL注入 # sql注入利用方式 # sql注入各种姿势 # sql注入原理
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录