Loading [MathJax]/jax/output/CommonHTML/fonts/TeX/SansSerif-Italic.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >php宽字节注入,[投稿]宽字节注入详解

php宽字节注入,[投稿]宽字节注入详解

作者头像
全栈程序员站长
发布于 2022-11-04 09:39:35
发布于 2022-11-04 09:39:35
3.5K0
举报

前言

mysql中,用于转义的函数有addslashes,mysql_real_escape_string,mysql_escape_string等,还有一种情况是magic_quote_gpc,不过高版本的PHP将去除这个特性。

首先,宽字节注入与HTML页面编码是无关的,笔者曾经看到

Default

<meta charset=utf8>

1

<metacharset=utf8>

就放弃了尝试,这是一个误区,SQL注入不是XSS。虽然他们中编码的成因相似,不过发生的地点不同。

很多网上的材料都说程序使用了宽字节来处理程序,却又不指出具体是指什么程序。本文就介绍一下具体漏洞发生的原理与简单的利用。在这里我们限定使用的语言是PHP5.4,数据库MYSQL5.6。

涉及到的一些概念

字符、字符集与字符序

字符(character)是组成字符集(character set)的基本单位。对字符赋予一个数值(encoding)来确定这个字符在该字符集中的位置。

字符序(collation)指同一字符集内字符间的比较规则。

UTF8

由于ASCII表示的字符只有128个,因此网络世界的规范是使用UNICODE编码,但是用ASCII表示的字符使用UNICODE并不高效。因此出现了中间格式字符集,被称为通用转换格式,及UTF(Universal Transformation Format)。

宽字节

GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节。宽字节带来的安全问题主要是吃ASCII字符(一字节)的现象。

MYSQL的字符集转换过程

1. MySQL Server收到请求时将请求数据从character_set_client转换为character_set_connection;

2. 进行内部操作前将请求数据从character_set_connection转换为内部操作字符集,其确定方法如下:

• 使用每个数据字段的CHARACTER SET设定值;

• 若上述值不存在,则使用对应数据表的DEFAULT CHARACTER SET设定值(MySQL扩展,非SQL标准);

• 若上述值不存在,则使用对应数据库的DEFAULT CHARACTER SET设定值;

• 若上述值不存在,则使用character_set_server设定值。

将操作结果从内部操作字符集转换为character_set_results。

重点:宽字节注入发生的位置就是PHP发送请求到MYSQL时字符集使用character_set_client设置值进行了一次编码。

PHP测试代码:

Default

<!DOCTYPE html>

<meta charset=”gbk”><!–仅用于基础的显示,换成utf8也行就是不好看–>

<?php

error_reporting(0);

$conn = mysql_connect(‘127.0.0.1′,’root’,”);

mysql_select_db(‘mysql’,$conn);

mysql_query(“set names gbk”); //不安全的编码设置方式

$res = mysql_query(“show variables like ‘character%’;”); //显示当前数据库设置的各项字符集

while(row=mysqlfetcharray(res)){

var_dump($row);

}

user=addslashes(_GET[‘sql’]); //mysql_real_escape_string() magic_quote_gpc=On addslashes() mysql_escape_string()功能类似

Extra open brace or missing close braceuser}'”;

echo $sql.'</br>’;

if(res=mysqlquery(sql)){

while(row=mysqlfetcharray(res)){

var_dump($row);

}

}

else{

echo “Error”.mysql_error().”<br/>”;

}

?>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

<!DOCTYPEhtml>

<metacharset=”gbk”><!–仅用于基础的显示,换成utf8也行就是不好看–>

<?php

error_reporting(0);

$conn=mysql_connect(‘127.0.0.1′,’root’,”);

mysql_select_db(‘mysql’,$conn);

mysql_query(“set names gbk”);//不安全的编码设置方式

$res=mysql_query(“show variables like ‘character%’;”);//显示当前数据库设置的各项字符集

while(row=mysqlfetcharray(res)){

var_dump($row);

}

user=addslashes(_GET[‘sql’]);//mysql_real_escape_string() magic_quote_gpc=On addslashes() mysql_escape_string()功能类似

Extra open brace or missing close braceuser}'”;

echo$sql.'</br>’;

if(res=mysqlquery(sql)){

while(row=mysqlfetcharray(res)){

var_dump($row);

}

}

else{

echo”Error”.mysql_error().”<br/>”;

}

?>

Default

http://localhost/xl.php?sql=root%df%27%20or%201=1%23

1

http://localhost/xl.php?sql=root%df%27%20or%201=1%23

是可以执行成功的!

URL解码sql=rootß’ or 1=1#

解析过程:

Default

$_GET[‘sql’] 经过 addslashes编码之后带入了‘\’

1、root%df%5C%27%20or%201=1%23

2、带入mysql处理时使用了gbk字符集

%df%5c -> 運 成功的吃掉了%5c

%27 -> ‘ 单引号成功闭合

1

2

3

4

5

6

7

8

9

10

$_GET[‘sql’]经过addslashes编码之后带入了‘\’

1、root%df%5C%27%20or%201=1%23

2、带入mysql处理时使用了gbk字符集

%df%5c->運成功的吃掉了%5c

%27->‘单引号成功闭合

执行了插入的sql语句。

怎么吃的:

GBK编码,它的编码范围是0x8140~0xFEFE(不包括xx7F),在遇到%df(ascii(223)) >ascii(128)时自动拼接%5c,因此吃掉‘\’,而%27、%20小于ascii(128)的字符就保留了。

补充:

GB2312是被GBK兼容的,它的高位范围是0xA1~0xF7,低位范围是0xA1~0xFE(0x5C不在该范围内),因此不能使用编码吃掉%5c。

其它的宽字符集也是一样的分析过程,要吃掉%5c,只需要低位中包含正常的0x5c就行了。

安全过滤

上文中代码使用了mysql_query(“set names gbk”)来设置编码,其实在mysql中是推荐mysql_set_charset(“gbk”);函数来进行编码设置的,这两个函数大致的功能相似,唯一不同之处是后者会修改mysql对象中的mysql->charset属性为设置的字符集。

同时配套的过滤函数为mysql_real_escape_string()。上面代码中列出了几个过滤的函数,他们之间的区别就是mysql_real_escape_string()会根据mysql对象中的mysql->charset属性来对待传入的字符串,因此可以根据当前字符集来进行过滤。

同理可得

由上文可得宽字节注入是由于转编码而形成的,那具有转编码功能的函数也成了漏洞的成因。

转码函数

mb_convert_encoding()

iconv()

以下用iconv()来演示,修改上面的代码:

Default

<!DOCTYPE html>

<meta charset=”gbk”>

<?php

error_reporting(0);

$conn = mysql_connect(‘127.0.0.1′,’root’,”);

mysql_select_db(‘mysql’,$conn);

mysql_set_charset(“utf8”); //推荐的安全编码

user=mysqlrealescapestring((_GET[‘sql’])); //推荐的过滤函数

user=iconv(GBK,UTF8,user);

Extra open brace or missing close braceuser}'”;

echo $sql.'</br>’;

res=mysqlquery(sql);

while(row=mysqlfetcharray(res)){

var_dump($row);

}

?>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

<!DOCTYPEhtml>

<metacharset=”gbk”>

<?php

error_reporting(0);

$conn=mysql_connect(‘127.0.0.1′,’root’,”);

mysql_select_db(‘mysql’,$conn);

mysql_set_charset(“utf8”);//推荐的安全编码

user=mysqlrealescapestring((_GET[‘sql’]));//推荐的过滤函数

user=iconv(GBK,UTF8',user);

Extra open brace or missing close braceuser}'”;

echo$sql.'</br>’;

res=mysqlquery(sql);

while(row=mysqlfetcharray(res)){

var_dump($row);

}

?>

Default

http://localhost/xl.php?sql=root%e5%27or%201=1%23

1

http://localhost/xl.php?sql=root%e5%27or%201=1%23

同样可以执行成功,编码解析的过程依然如上。

总结一下漏洞成因:

代码一

1、使用了不安全的字符集设置函数与过滤函数。

2、漏洞发生在PHP请求mysql时使用character_set_client值进行一次转码。

代码二

1、使用了推荐的设置函数与过滤函数。

2、解析错误发生在iconv()函数转码时,GBK转向UTF8吃掉了“\”

3、PHP请求mysql时转码安全。

另外:

当改变编码方向时user=iconv(UTF8,gbk,user);

这种情况下需要两个参数来配合注入。

例如:

Default

http://localhost/xl.php?sql=root%e9%8c%a6¶=%20or%201=1%23

1

http://localhost/xl.php?sql=root%e9%8c%a6¶=%20or%201=1%23

总结:

宽字节注入跟HTML页面编码无关。

Mysql编码与过滤函数推荐使用mysql_real_escape_string(),mysql_set_charset()。

转编码函数同样会引起宽字节注入,即使使用了安全的设置函数。

参考文献

mysql字符集的设置:http://www.laruence.com/2008/01/05/12.html

赏金发放情况:本文获得赏金100RMB,已于4.3日发放到作者账号。

征稿启事:91RI一直相信“你不与人分享,谁与你分享”,分享的确是件非常有意义的事情。为了让优秀的同学有地方分享自己的独到见解,也为了让更多同学从分享中受益,同时我们也希望给那些愿意分享的小伙伴们一点点心意作为感谢,所以我们隆重了推出“有奖征文”活动!本次活动的详情可以围观《征稿启事》

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/181945.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年10月14日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
HIBERNATE 持久化基础
Hibernate 是一个开放源代码的对象关系映射框架,它通过对 JDBC 进行轻量级的对象封装,使 Java 程序员能够随心所欲地使用面向对象的编程思维来操作数据库。Hibernate 不仅提供了 Java类与数据表之间的映射,而且还提供了数据查询与恢复机制。相对于 JDBC 手工操作数据库而言,Hibernate 大大减少了操作数据库的工作量。另外,Hibernate 能够利用代理模式简化载入类的过程,大大减少了利用 Hibernate QL 从数据库提取数据代码的编写工作量,节约了开发时间及成本。Hibernate 能够与多种 Web 服务器或者应用服务器良好地集成,基本上支持所有流行的数据库服务器。本章主要通过引人持久层及分层结构介绍 Hibernate。
用户9184480
2024/12/17
1160
HIBERNATE 持久化基础
Hibernate的搭建
       Hibernate是Java世界中使用最广泛的数据持久化框架,使用ORM(对象关系映射)模式简化关系型数据库的的数据增删改查功能。
用户10175992
2022/11/15
5480
Hibernate的搭建
【Android从零单排系列四十三】《浅谈Android数据持久化》
小伙伴们,在前面的几篇文章中,我们谈到了Android开发中的几种数据存储方式,本文我们总结介绍下Android数据持久化的一些内容。
再见孙悟空_
2023/07/17
6150
Hibernate技术原理、高级特性、大数据处理及与Mybatis对比
Hibernate 是一个 Java 平台上的对象关系映射 (ORM) 框架,它提供了一种高效的方式来处理 Java 应用程序与关系型数据库之间的交互。其核心技术原理主要包括以下几个方面:
用户7353950
2024/04/25
2790
Hibernate技术原理、高级特性、大数据处理及与Mybatis对比
iOS - 模型数据持久化保存实现
image.png 在iOS开发实际中,可以在 AppDelegate.m 的 didFinishLaunchingWithOptions方法中,快速定位需要当前需要开发的控制器 但是,如果要开发的控制器,需要之前的控制器传值怎么办呢? image.png ==> 解决办法 : 方法1:不设置rootVC = 当前开发控制器(TwoVC),默认使用homeVC,一步一步点击,似魔鬼的步伐一般进入TwoVC 方法2 :还是设置rootVC = 当前的开发控制器(TwoVC),同时,使用数据持久化保存,保存
小蠢驴打代码
2018/05/24
2K0
鸿蒙用户首选项数据持久化
用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。当用户希望有一个全局唯一存储的地方,可以采用用户首选项来进行存储。Preferences会将该数据缓存在内存中,当用户读取的时候,能够快速从内存中获取数据,当需要持久化时可以使用flush接口将内存中的数据写入持久化文件中。Preferences会随着存放的数据量越多而导致应用占用的内存越大,因此,Preferences不适合存放过多的数据,也不支持通过配置加密,适用的场景一般为应用保存用户的个性化设置(字体大小,是否开启夜间模式)等。
龙儿筝
2025/03/13
1160
鸿蒙用户首选项数据持久化
Java开发面试--Redis专区
Redis是一个开源的、基于内存的高性能键值对存储系统。它主要用于缓存、数据存储和消息队列等场景。
忆愿
2024/08/12
1440
Java开发面试--Redis专区
[ Java面试题 ]持久层篇
1、什么是ORM?   对象关系映射(Object-Relational Mapping,简称ORM)是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术;   简单的说,ORM是通过使用描述对象和数据库之间映射的元数据(在Java中可以用XML或者是注解),将程序中的对象自动持久化到关系数据库中或者将关系数据库表中的行转换成Java对象,其本质上就是将数据从一种形式转换到另外一种形式。 2、Hibernate中SessionFactory是线程安全的吗?Session是线程安全的吗(两个
Kevin_Zhang
2018/05/22
1.4K0
【Java 基础篇】Java持久化详解
在Java开发中,持久化是一种将数据存储到持久存储介质(如磁盘)上,并能够在需要时重新加载数据的机制。持久化允许应用程序将数据持久保存,以便在应用程序重新启动或在其他场景下使用。本文将详细介绍Java中的持久化概念、持久化技术的种类和使用方法,并提供一些示例代码。
繁依Fanyi
2023/10/12
6860
Flutter 应用数据持久化指南
数据持久化是指将应用程序中的数据保存在持久存储介质(如硬盘、数据库等)中的过程。在计算机科学领域,持久化数据是指数据在程序退出或系统关机后仍然存在的能力。这种持久性使得数据可以在不同的应用程序运行周期之间保持不变,以便稍后进行检索、处理和使用。
繁依Fanyi
2024/04/05
5710
数据持久化技术(Python)的使用
利用 pymysql.connect 建立数据库连接并执行 SQL 命令(需要提前搭建好数据库):
霍格沃兹测试开发Muller老师
2022/06/06
3970
redis的数据持久化方案
Redis的持久化方案有两种 1.Rdb方式:快照形式,定期将内存中的数据持久化到硬盘。是Redis默认的数据持久化的形式。 Rdb:缺点是:数据还没有更新到磁盘上,突然断电,造成数据的不完整性。 在
用户2146856
2018/05/18
8560
Redis的数据持久化
主从同步数据选择的方式-----数据持久化操作  Redis在正常关闭时触发rdb操作
星哥玩云
2022/08/18
3560
MVVM的数据持久化(一)——ROOM的集成
之前我们分别介绍了MVVM框架的悲剧,项目搭建以及网络请求,接下来在这篇文章当中,我们来聊一聊MVVM数据持久化的问题,也就是我们常说的缓存
Demo_Yang
2018/12/07
1.5K0
Redis 数据持久化
Redis支持两种数据持久化方式:RDB方式和AOF方式。前者会根据配置的规则定时将内存中的数据持久化到硬盘上,后者则是在每次执行写命令之后将命令记录下来。两种持久化方式可以单独使用,但是通常会将两者结合使用。
星哥玩云
2022/09/15
1.4K0
Redis 数据持久化
DDD落地,如何持久化聚合
聚合是一组始终需要保持一致的业务对象。因此,我们作为一个整体保存和更新聚合,以确保业务逻辑的一致性。聚合是 DDD 中最为重要的概念,即使你不使用 DDD 编写代码也需要理解这一重要的概念 —— 部分对象的生命周期可以看做一个整体,从而简化编程。一般来说,我们需要对聚合内的对象使用 ACID 特性的事务。最简单的例子就是订单和订单项目,订单项目更新必须伴随订单的更新,否则就会有总价不一致之类的问题。订单项目需要跟随订单的生命周期,我们把订单叫做聚合根,它就像一个导航员一样
ThoughtWorks
2021/11/19
2.7K1
DDD落地,如何持久化聚合
【Hibernate那点事儿】—— Hibernate知识总结
前言: 上一篇简单的讲解了下Hibernate的基础知识。这里对Hibernate比较重要的一些知识点,进行总结和归纳。 总结的知识点: 1 关于hibernate映射的实体类标识符访问权
用户1154259
2018/01/18
1.1K0
【Hibernate那点事儿】—— Hibernate知识总结
Java 数据持久化系列之JDBC
前段时间小冰在工作中遇到了一系列关于数据持久化的问题,在排查问题时发现自己对 Java 后端的数据持久化框架的原理都不太了解,只有不断试错,因此走了很多弯路。于是下定决心,集中精力学习了持久化相关框架的原理和实现,总结出这个系列。
程序员历小冰
2019/11/26
1K0
Java 数据持久化系列之JDBC
Flutter开发 - 数据持久化
数据持久化的应用场景有很多。比如,用户的账号登录信息需要保存,用于每次与 Web 服务验证身份;又比如,下载后的图片需要缓存,避免每次都要重新加载,浪费用户流量。
用户1483438
2022/03/28
1.7K0
Redis系列(二)——数据持久化介绍与配置
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
逝兮诚
2019/10/30
3680
推荐阅读
相关推荐
HIBERNATE 持久化基础
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文