前言
虽然上次你已经获取了数据库里的全部内容,但是并没有找到大宝藏。不过你并没有气馁,这反而激起了你雄雄斗志,现在开始专门在网上找一些挂着中二宣传词的网站,有打着寻宝旗号的,有打着鸡汤励志的,也有打着……你觉得下面这个就很不错,于是熟练的干起了老活计。
题目分析
首页如下:
按提示输入参数id后结果如下:
对此你非常淡定,毕竟你也是见过世面的不是?(虽然只见过一次)
你非常自信地输入了一个单引号,结果如下:
竟然做了过滤,不过问题不大,只要没有全部过滤,就总会找到突破口,接着你输入了 " 、 ")等,当输入 " 果然有反应了。结果如下:
因此右边闭合符应为双引号。
之后就是跟之前利用XPATH语法错误进行报错注入一样的操作了,但这次你决定玩点新花样。extractvalue、updatexml虽好,但技多不压身,这回你决定采用floor三件套。
写入以下语句:
"and(select 1 from (select count(*) ,concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a)- -+
结果如下:
可以看到,利用floor三件套同样可以完成之前利用XPATH报错机制进行注入的工作。那floor三件套的原理是什么呢?为什么利用floor三件套进行注入时得到的结果会多一个数字1出来呢?
floor、rand、group by的恩怨情仇
要解决这些问题,就得好好剖析floor三件套中floor、rand、group by三者之间的关系了。三者的作用如下:
floor(x):对x向下取整;
rand(x):对x定义一个随机数;
count……group by x:以x为主键对表中字段进行计数并生成另一张临时表。
此外还需引入伪随机数的概念。所谓的伪随机,就是在出现一段随机序列后再次重复出现该序列。举一个简单的例子,Pi小数点部分任取一个数就是真正的随机数,因为Pi的小数随机截取一段序列后无重复出现该段序列;而在序列111001110011100……中,无论如何截取,总会出现重复序列,因此由该段序列产生的数就是伪随机数。接下来就来看看三者是如何作用的。
floor(rand(0)*2)的作用就是产生伪随机数,其值在序列011011011……中产生。group by floor(rand(0)*2)执行机制为进行计数时:
如果插入记录时第一次计算得到的的主键存在于临时表中,则更新临时表中的数据,此时仅count加一,不再计算rand的值;
如果插入记录时第一次计算得到的主键不存在于临时表中,则在临时表中插入主键所在行的数据,此时除了count加一以外,还会再计算一次rand的值。
以下为执行过程:
当临时表中插入第一条记录时,floor(rand(0)*2)=0,临时表中无该主键,因此floor(rand(0)*2)再执行一次后结果为1,并将该条记录插入临时表中,count加一;
当临时表中插入第二条记录时,floor(rand(0)*2)进行第三次计算,结果为1。此时临时表中存在1的主键,因此floor(rand(0)*2)无须再次计算,仅count加一即可;
当临时表中插入第三条记录时,floor(rand(0)*2)进行第四次锦计算,结果为0,临时表中不存在0的主键,因此floor(rand(0)*2)第五次执行,其结果为1,此时将在临时表中插入一条主键为1的记录。但已经有主键为1的记录存在,此时主键冲突,产生报错。
因此当floor、rand(0)、group by三者组合使用后,在插入第三条记录时必定会因为主键重复而报错
而报错。
细枝末节
在语句:and(select 1 from (select count(*) ,concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a)- -+ 中,为了能够进行嵌套查询,采用了“SQL语句a”的形式,这里的a在之后使用时就代表了前面的SQL语句。另外加上语句“select 1 from”是为了解决and连接的是两个逻辑结果的问题。而rand中的参数之所以选为0,是为了确保出现伪随机序列011011……。如果将0换为其它数则不确定能否产生伪随机数,最终可能达不到主键冲突的结果。而我们得到的结果之所以有个数字1,也是因为主键1产生冲突报错导致的。
总结
在利用floor三件套进行报错注入时,必须确保表中至少存在三条记录,否则无法产生主键冲突;为了能够产生伪随机数,rand的参数必须为0。
以上就是本篇的全部内容,我们下篇见。