本节练习涉及到了一个新的概念:双注入。
双注入简单理解为一个select查询里嵌套一个select查询,如果要利用双注入需要人为构造特定的能够造成报错的查询,从而在报错信息里返回我们需要的数据。需要用到的函数和语句有:
1.concat() 作用为连接括号里的参数。例concat(1,~,2) 结果为 1~2
2.floor() 作用为对括号里的非整数进行取整 如1.9取为1,2.1取为2
3.count() 作用为针对查询结果条数进行计数
4.rand() 作用为生成0-1范围内的随机数 (1.括号内如果填写一个固定参数,则每次生成的随机数固定;2.使用* 运算符,可以使取值范围扩大,如 rand()*2 的取值范围为0-2)
5.group by [key]对查询结果进行分组,针对每一个key 列出一条结果。
6.group by [key]和 conut(*)联用,作用为列出所有可能的key和key的查询结果条数。
最后再介绍一种错误类型:Duplicate entry
这种错误一般发生于数据库对某一个字段有UNIQUE限制的情况下,例如某员工信息表里对身份证号字段设置的UNIQUE限制,即不能出现重复的身份证号,当我们插入一条新员工信息时,输入表中已存在的身份证号时就会报Duplicate entry错误,即重复录入。
双重注入构造报错查询的原理就大致基于以上的函数、方法和错误类型,下面是构造查询的思路:
1.首先,rand([整数]) from [x表] ,会基于x表的记录条数,生成数量与x表记录条数相同的随机数序列,又因为指定了rand的参数,根据上面第4条,每次生成的随机数序列都是相同的。
2.接着,rand([整数])*2 from [x表],使得生成的随机数序列的范围从0-1变成了0-2
3.然后 floor(rand([整数])*2 from [x表]), 使得结果变成了非0即1(因为随机数结果范围为0.000000...1到1.999999...9)。
4.再然后,使用payload和非0即1的查询作concat连接,例如
select concat((select database()),floor(rand(14)*2)) from information_schema.tables
得出的结果长得像这样
5.把这个结果利用group by 进行计数
select concat((select database()),floor(rand(14)*2)) as a, count(*) from information_schema.tables group by a
6.出现报错
且某些信息也通过报错信息显示出来了。
发生这个报错的原因如下:
1.使用count(*)和group by 进行计数时,系统会自动生成一张临时表,这里称它为 T
2.T里有两个字段,一个叫group_key,内容为"group by x" 中的x,另一个字段叫tally,内容是根据x分组而重复的记录数。
3.当我们使用
select concat((select database()),floor(rand(14)*2)) as a, count(*) from information_schema.tables group by a
这个查询的时候,内层查询首先查询出来的是这个结果序列,然后再对这个序列进行分组计数。
分组计数的时候,会遍历临时表T,查看即将要插入的key值是否在T表中存在。
1.系统在先临时表T中查找concat((select database()),floor(rand(14)*2)))这个关键词,发现没有这个关键词,于是准备要把它填入第一行的group_key字段里。
2.但不巧的是是这句查询本应作为一个字符串被填入,其实它经过了执行才被填入,因此临时表T第一行的group_key被填上security1,tally填1。
3.接着系统又在临时表T中查找concat((select database()),floor(rand(14)*2)))这个关键词,发现还是没有这个关键词,于是准备要把它填入第二行的group_key字段。
4.它又被执行后填入,临时表T的第二行group_key被填上security0,tally填1
5.继续遍历,发现又没有,又填,这次执行后的值是security1,等到执行插入的时候发现这个在第一行已经填过了,而group_key这个字段使UNIQUE的所以报二次输入的错误,并暴露出相关信息。
根据以上所有理论,可以构造payload
?id=-1' union select 1,concat((select table_name from information_schema.tables where table_schema='security' limit 1,1),floor(rand(14)*2)) as a,count(*) from information_schema.tables group by a--+
结果如下:
修改limit限制可以爆本库下所有表名
同理利用payload可以爆更多数据
至此,本节结束。