SQL注入:宽字节注入

 SQL注入系列文章:

初识SQL注入-CSDN博客

SQL注入:联合查询的三个绕过技巧-CSDN博客

SQL注入:报错注入-CSDN博客

SQL注入:盲注-CSDN博客

SQL注入:二次注入-CSDN博客

​SQL注入:order by注入-CSDN博客

目录

什么是宽字节注入?

宽字节注入

绕过addslashes的限制

方法1:吃掉\

GB2312与GBK

mysql_real_escape_string防御绕过?

防御

宽字符注入的修复

防御

iconv导致的致命后果

方法2:二次转义


前面和大家分享了很多SQL注入的类型,联合查询,报错注入,盲注,二次注入,和order by 注入转眼间SQL注入已经来到了宽字节,这个注入也是一个比较特别的注入形式,可以说是“中国限定”的一个注入方式了,那么现在我们开始ヾ(◍°∇°◍)ノ゙

什么是宽字节注入?

SQL宽字节注入(SQL wide-character injection)是指利用数据库中的特定编码格式来进行非法操作或者获取未经授权的信息。这种注入通常发生在使用了不安全的输入验证机制、错误地处理用户提供的参数等情况下。

宽字节注入

想要搞清楚宽字节注入,这里我们首先要知道gbk编码是什么

GBK编码是一种汉字字符编码标准,它是在GB2312-80标准的基础上建立的内部码扩展规范。GBK编码采用了双字节编码方案,其编码范围是从8140至FEFE(剔除xx7F),共计23940个码位。GBK编码能够容纳21003个汉字,这些包括了GB2312中的全部汉字以及其他一些生僻汉字和少数民族文字。此外,GBK编码还包括了BIG5编码中的所有汉字。

GBK编码的一个特点是,它在8140至FEFE之间的首字节中,第一个字节的范围是0x81至0xFE,而第二个字节的范围是0x40至0xFE(不包括0x7F)。这样的设计使得总共可以组合出190 * 94 = 17860个不同的汉字和符号。

GBK编码与Unicode编码不同,因为它是专门为中国大陆地区设计的,并不适用于全球通用的情况。GBK编码在早期的Windows操作系统如Windows 95、Windows 98、Windows NT以及Windows 2000、Windows XP、Windows 7中都有支持。然而,随着GB18030-2000标准的推出,GBK被视为该标准的子集,并且在某些方面有所扩展。

总结来说,GBK编码是一个兼容GB2312的双字节编码标准,主要用于中文文本的处理和存储,但它不是国际通用的编码方式。

gbk编码与utf编码的不同之处有很多,其中我们必须要知道的是:

一个gbk编码汉字,占用2个字节。

一个utf-8编码的汉字,占用3个字节。

我们可以使用php来测试一下:

<?php
echo strlen("杨");
?>

这里是utf-8的编码的输出结果,然后我们可以在设置中修改一下编码为bgk,然后再试试:

可以看到修改为bgk后,字节数就变成了2

那么下面就可以一起探讨一下Mysql中的宽字节注入

绕过addslashes的限制

首先我们先写一个存在宽字节注入的前后端代码:

<?php
//连接数据库部分,注意使用了gbk编码,把数据库信息填写进去
$conn = mysql_connect('localhost', 'root', '***') or die('bad!');
mysql_query("SET NAMES 'gbk'");
mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
//执行sql语句
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$sql = "SELECT * FROM news WHERE tid='{$id}'";
$result = mysql_query($sql, $conn) or die(mysql_error()); //sql出错会报错,方便观察
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>宽字节注入</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n";
mysql_free_result($result);
?>
</body>
</html>

可以看到SQL语句是SELECT * FROM news WHERE tid='{$id}',就是根据文章的id把文章从news表中取出来。

在这个sql语句前面,我们使用了一个addslashes函数,将$id的值转义

这是通常cms中对sql注入进行的操作,只要我们的输入参数在单引号中,就逃逸不出单引号的限制,无法注入:

可以看到我们确实无法使用'来闭合单引号,导致提示报错了

那么怎么逃过addslashes的限制?

addslashes函数的作用就是让'变成\',让引号变得不再是原本的“单引号”,没有了之前的语义,而是变成了一个字符。那么我们现在要做的就是想办法将'前面的\给它去除掉:

方法1:吃掉\

既然这函数给'前面加了一个\那么是不是想办法给\前面再加一个\(或单数个即可),然后变成了\\',这样\就又被转义了,这样就成功的逃出了addslashes的限制

但是现在理论知识已经有了,下面就要开始尝试了,这里又该怎么来个给\前面增加一个\呢?

这时宽字节注入就出现了,mysql有一个特性就是在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ascii码要大于128,才到汉字的范围)。如果我们在刚才的代码中传入一个%df'看会怎样:

可以看到这里成功的报错了,既然报错了那说明我们的闭合已经起作用了,说明成功的绕过了addslashes函数的限制了

那么导致我们可以闭合成功的原因是什么呢?

从报错的内容中可以看到,好像是在一个奇怪的字符附近。

这就是因为前面提到的mysql的特性,因为gbk是多字节编码,他认为两个字节代表一个汉字,所以%df和addslashes为我们加的后面的\也就是%5c和成了一起变成了一个汉字“運”而%df后面的'逃逸了出来。

我们可以再看%df%df%27,看看它是否可以绕过:

可以看到,这样却无法闭合,这时因为我们输入的%df和%df组成了一个汉字,%5c和%27不是汉字,仍然是\',所以无法报错

那么这里就值得思考一下mysql怎么判断一个字符是不是汉字,根据gbk编码,第一个字节ascii码大于128,基本上就可以了。

比如我们不用%df,用%a1也可以:

可以看到%1a和%5c构成了一个?,然后后面的'由逃逸出来了

那么既然现在已经使用宽字节绕过了限制,那么就可以直接来注入出信息了,比如说注入出数据库的名称:

可以看到第2,3列是可以显示出来的,那么就可以直接在这里注入出数据库名了:

可以看到,成功的注入出了数据库名

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

如果我们输入%df'看会怎样:

GB2312与GBK

还有一个GB2312,众所周知GBK是GB2312的扩展版本,GBK包含了GB2312的所有字符,同时还包含了更多的汉字和符号。

那么既然GB2312既然也有宽字节的特性,那么这个编码是否可以向BGK那样注入呢?
来试试看,这里把上面的代码的编码修改为GB2312来看看

<?php
//连接数据库部分,注意使用了gbk编码,把数据库信息填写进去
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
// mysql_query("SET NAMES 'gbk'");
mysql_query("SET NAMES 'GB2312'");
mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
//执行sql语句
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$sql = "SELECT * FROM news WHERE tid='{$id}'";
$result = mysql_query($sql, $conn) or die(mysql_error()); //sql出错会报错,方便观察
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>宽字节注入</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n";
mysql_free_result($result);
?>
</body>
</html>

现在再来试试使用%1a和'来闭合一下:

可以看到这里病灭有报错,说明这种方法不能绕过

那么到底是为什么呢?,这归结于gb2312编码的取值范围。它的高位范围是0xA1~0xF7,低位范围是0xA1~0xFE\是0x5c,是不在低位范围中的。所以,0x5c根本不是gb2312中的编码,所以自然也是不会与%1a组成一个宽字节字符。

所以,把这个思路扩展到世界上所有多字节编码,我们可以这样认为:只要低位的范围中含有0x5c的编码,就可以进行宽字符注入。

mysql_real_escape_string防御绕过?

防御1

php中有这样一个函数,官网上是这样介绍的

可以看到这个函数对特殊字符进行转义,那么是否可以使用该函数来防御宽字节注入绕过呢?

还是实践一下:
将代码修改为下列形式,主要就是将addslashes函数修改为mysql_real_escape_string

<?php
//连接数据库部分,注意使用了gbk编码,把数据库信息填写进去
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES 'GBk'");
mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
//执行sql语句
$id = isset($_GET['id']) ? mysql_real_escape_string($_GET['id']) : 1;
$sql = "SELECT * FROM news WHERE tid='{$id}'";
$result = mysql_query($sql, $conn) or die(mysql_error()); //sql出错会报错,方便观察
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>宽字节注入</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n";
mysql_free_result($result);
?>
</body>
</html>

修改后我们再来试试绕过:

还是绕过了,说明这个函数并不能防御我们的绕过

没有绕过的原因就是,没有指定php连接mysql的字符集。我们需要在执行sql语句之前调用一下mysql_set_charset函数,设置当前连接的字符集为gbk。就可以完美的防御了:

<?php
//连接数据库部分,注意使用了gbk编码,把数据库信息填写进去
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
// mysql_query("SET NAMES 'gbk'");
mysql_query("SET NAMES 'gbk'");
mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
//执行sql语句
mysql_set_charset('gbk',$conn);
$id = isset($_GET['id']) ? mysql_real_escape_string($_GET['id']) : 1;
$sql = "SELECT * FROM news WHERE tid='{$id}'";
$result = mysql_query($sql, $conn) or die(mysql_error()); //sql出错会报错,方便观察
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>宽字节注入</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n";
mysql_free_result($result);
?>
</body>
</html>

再来试试:

现在就无法绕过了

宽字符注入的修复

防御2

上面已经演示了一种防御宽字节注入的方法,下面再来介绍一种

但是因为有一些老的cms,在多处使用addslashes来过滤字符串,我们不可能去把addslashes都修改成mysql_real_escape_string。

因此这里就需要用到第二个解决方案:将character_set_client设置为binary(二进制)。

只需在所有sql语句前指定一下连接的形式是二进制:

SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary

这几个变量是什么意思?

当我们的mysql接受到客户端的数据后,会认为他的编码是character_set_client,然后会将之将换成character_set_connection的编码,然后进入具体表和字段后,再转换成字段对应的编码。

然后,当查询结果产生后,会从表和字段的编码,转换成character_set_results编码,返回给客户端。

所以,我们将character_set_client设置成binary,就不存在宽字节或多字节的问题了,所有数据以二进制的形式传递,就能有效避免宽字符注入。

那么就可以再次使用上面的代码来演示一下:

<?php
//连接数据库部分,注意使用了gbk编码,把数据库信息填写进去
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
// mysql_query("SET NAMES 'gbk'");
mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary",$conn);
mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
//执行sql语句
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$sql = "SELECT * FROM news WHERE tid='{$id}'";
$result = mysql_query($sql, $conn) or die(mysql_error()); //sql出错会报错,方便观察
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>宽字节注入</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n";
mysql_free_result($result);
?>
</body>
</html>

尝试注入:

可以看到,防御成功了

iconv导致的致命后果

本来上面两种防御方法已经可以非常完美的防御宽字节注入了,但是有一些人会在网站的后端配置iconc,来对utf-8进行一个编码目的一般是为了避免乱码,特别是在搜索框的位置

iconv('utf-8', 'gbk', $_GET['word']);
//将utf8编码转换为gbk

那我还是使用上面的代码测试一下,上面的代码修改后:

<?php
//连接数据库部分,注意使用了gbk编码,把数据库信息填写进去
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
// mysql_query("SET NAMES 'gbk'");
mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary",$conn);
mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
//执行sql语句
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
iconv('utf-8', 'gbk', $_GET['word']);
$sql = "SELECT * FROM news WHERE tid='{$id}'";
$result = mysql_query($sql, $conn) or die(mysql_error()); //sql出错会报错,方便观察
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>宽字节注入</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n";
mysql_free_result($result);
?>
</body>
</html>

根据龙哥的提示,我们可以输入一个锦'来导致报错 

可以看到居然报错了。说明可以注入。而我只是输入了一个錦'。这是什么原因?

方法2:二次转义

我们来分析一下。“錦“这个字,它的utf-8编码是0xe98ca6,它的gbk编码是0xe55c

那么就非常的清楚了,\的ascii码正是5c。当我们的錦被iconv从utf-8转换成gbk后,变成了%e5%5c,而后面的'被addslashes变成了%5c%27,这样组合起来就是%e5%5c%5c%27,两个%5c就是\,正好把反斜杠转义了,导致’逃逸出单引号,产生注入。

这正利用了我之前说的,绕过addslashes的两种方式的第二种:将\转义掉。

那么,如果我是用iconv将gbk转换成utf-8呢?

$id = iconv('gbk', 'utf-8', $id);

尝试注入:

又成功了。这次直接用宽字符注入的,但实际上问题出在php而不是mysql

我们知道一个gbk汉字2字节,utf-8汉字3字节,如果我们把gbk转换成utf-8,则php会每两个字节一转换。所以,如果\'前面的字符是奇数的话,势必会吞掉\'逃出限制。

那么为什么之前utf-8转换成gbk的时候,没有使用这个方法呢?

这跟utf-8的规则有关,UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

从2我们可以看到,对于多字节的符号,其第2、3、4字节的前两位都是10,也就是说,\(0x0000005c)不会出现在utf-8编码中,所以utf-8转换成gbk时,如果有\则php会报错:

但因为gbk编码中包含了\,所以仍然可以利用,只是利用方式不同罢了。

总而言之,调用iconv时千万要小心,避免出现不必要的麻烦。

到次,SQL注入中的盲注就全部复习和演示完毕了,但是SQL注入的学习并没有结束,后面我会和大家分享更多的SQL注入的技巧和实验,我们后面再见(^▽^)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/657717.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wordcloud库和jieba库的使用

文章目录 wordcloud库的简单示范使用wordcloud库报错记录anaconda安装第三方jieba库jieba库的简单示范任务 1&#xff1a;三国演义中的常见词汇分布在“三国"这两个隶书字上&#xff0c;出现频率高的词字体大任务 2&#xff1a;三国演义中出现频率前十的人名。必须是以下这…

JZ15 二进制中1的个数(牛客)(C语言)

个人博客主页&#xff1a;https://blog.csdn.net/2301_79293429?typeblog 专栏&#xff1a;https://blog.csdn.net/2301_79293429/category_12545690.html 该题我为笨办法,与题解不同,如有疑问和见解,欢迎大家在评论区提出 题目链接: 二进制中1的个数_牛客题霸_牛客网 (now…

【日常总结】如何快速迁移Navicat中的全部连接设置到新安装的Navicat中?

一、场景 二、需求 三、解决方案 Stage 1&#xff1a;“文件”-->“导出连接”。 Stage 2&#xff1a;获取备份文件 connections.ncx Stage 3&#xff1a;导入connections.ncx 四、不足 一、场景 公司电脑换新&#xff0c;所有软件需要重装&#xff0c;包括navicat 1…

如何纯前端实现文件下载

业务场景 有一个下载文件的功能&#xff0c;不引入后端资源&#xff0c;纯前端应该如何实现&#xff1f; 解决方案 在vue2或者vue3项目中&#xff0c;可以把文件放在 public 文件夹下&#xff0c;然后使用a标签进行文件下载。 如&#xff1a;我要下载的文件是模版.xlsx 。首…

Django模型(五)

一、数据的条件查询 参考文档:QuerySet API 参考 | Django 文档 | Django 1.1、常用检索字段 字段检索,是在字段名后加 __ 双下划线,再加关键字,类似 SQL 语句中的 where 后面的部分, 如: 字段名__关键字 exact :判断是否等于value,一般不使用,而直接使用 =contai…

PL/SQL plsql Developer 14最新版注册码 (亲测可用)

plsql14 注册激活&#xff0c;亲测有效 product code: ke4tv8t5jtxz493kl8s2nn3t6xgngcmgf3 serial Number: 264452 password: xs374ca 激活成功

Qt6入门教程 14:QToolButton

目录 一.简介 二.常用接口 1.void setMenu(QMenu * menu) 2.void setPopupMode(ToolButtonPopupMode mode) 3.void setToolButtonStyle(Qt::ToolButtonStyle style) 4.void setArrowType(Qt::ArrowType type) 5.void setDefaultAction(QAction * action) 三.实战演练 1…

k8s从私有库harbor中拉取镜像

一、前言 Docker镜像是构建应用程序的基础。然而&#xff0c;许多组织和开发团队希望保留他们的Docker镜像在私有仓库中&#xff0c;并从中拉取镜像&#xff0c;而不是从公共Docker Hub中下载。这样做的原因有很多&#xff0c;包括&#xff1a; 1. 安全性&#xff1a;私有仓库可…

Java 字符串 07 练习-手机号屏蔽、身份证号信息查看,游戏骂人敏感词替换

注意点&#xff1a;只有返回值才是被截取的小串&#xff0c;所以需要有一个变量去承接它&#xff1b; 自己写的代码&#xff1a; import java.util.Scanner; public class practice {public static void main(String[] args) {Scanner input new Scanner(System.in);String …

Zookeeper分布式命名服务实战

目录 分布式命名服务 分布式API目录 分布式节点的命名 分布式的ID生成器 分布式的ID生成器方案&#xff1a; 基于Zookeeper实现分布式ID生成器 基于Zookeeper实现SnowFlakeID算法 分布式命名服务 命名服务是为系统中的资源提供标识能力。ZooKeeper的命名服务主要是利用Z…

QT自制软键盘 最完美、最简单、支持中文输入(二)

目录 一、前言 二、本自制虚拟键盘特点 三、中文输入原理 四、组合键输入 五、键盘事件模拟 六、界面 七、代码 7.1 frmKeyBoard 头文件代码 7.2 frmKeyBoard 源文件代码 八、使用示例 九、效果 十、结语 一、前言 由于系统自带虚拟键盘不一定好用&#xff0c;也不一…

牛客网-----------[NOIP2006]数列

题目描述 给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列&#xff0c;例如&#xff0c;当k3时&#xff0c;这个序列是&#xff1a; 1&#xff0c;3&#xff0c;4&#xff0c;9&#xff0c;10&#xff0c;12&#xff0c;13&…

2024年重庆市公务员考试报名明天开始,招聘4530人!

2024年重庆公务员招录公告已出&#xff0c;招聘人数&#xff1a;4530人 ✅重庆市考重要时间节点 报名时间&#xff1a;2月1日9:00-2月6日9:00 缴费时间&#xff1a;2月8日 笔试时间&#xff1a;3月16日-17日 笔试查成绩时间&#xff1a;4月15日 面试时间&#xff1a;4月27日-2…

C++文件操作(1)

C文件操作 1.文本的写入及读取文本文件写入文本文件读取 2.二进制文件的写入及读取二进制文件写入二进制文件读取 3.小结 C也有处理文件的能力&#xff0c;其功能实现依赖文件流。文件流是C中用来处理文件输入输出的一种流类。文件流可以用于从文件中读取数据或将数据写入到文件…

《游戏-03_2D-开发》

基于《游戏-02_2D-开发》&#xff0c; 继续制作游戏&#xff1a; 首先要做的时切割人物Idle空闲状态下的动画&#xff0c; 在切割之前我们需要创建一个文件夹&#xff0c;用来存放动画控制器AnimatorContoller&#xff0c; 再创建一个人物控制器文件夹用来存放人物控制器&…

【Ubuntu 22.04.3 LTS】apt-get下载安装有关问题可能原因及解决方法

ubuntu 22.04.3 LTS unaccountably error 装啥啥没依赖 可能是用了不合适的源&#xff0c;换个就好了 Now, let’s take a look at the lsb_release output, with a special focus on the Codename, which could be a crucial piece of information. The lsb_release comm…

认识BPMN2.0

&#x1f496;专栏简介 ✔️本专栏将从Camunda(卡蒙达) 7中的关键概念到实现中国式工作流相关功能。 ✔️文章中只包含演示核心代码及测试数据&#xff0c;完整代码可查看作者的开源项目snail-camunda ✔️请给snail-camunda 点颗星吧&#x1f618; &#x1f496;说在前面 …

STM32单片机基本原理与应用(四)

直流电机驱动控制原理 1、电机正反转控制 在STM32中&#xff0c;直流电机的正反转控制主要通过改变电机输入电源的极性来实现。当电机的电压极性发生变化时&#xff0c;电机的旋转方向也会相应改变。在硬件电路中&#xff0c;可以通过继电器或晶体管等电子开关来切换电机的电源…

【TCP】重传与超时机制

前言 在网络通信的世界里&#xff0c;传输控制协议&#xff08;TCP&#xff09;扮演着一个至关重要的角色。它确保了数据的可靠传输&#xff0c;就像邮差确保每一封信都能准确无误地送达收件人手中一样。但是&#xff0c;网络环境充满了不确定性&#xff0c;数据包可能会因为各…

新书速览|Docker与Kubernetes容器运维实战

帮助读者用最短的时间掌握Docker与K8s运维技能 内容简介 随着云计算和容器技术的发展&#xff0c;Docker与Kubernetes已经成为各个企业首选的部署工具&#xff0c;使用它们可以提高系统的部署效率和运维能力&#xff0c;降低运维成本。本书是一本为初学者量身定制的Docker与Kub…