[Web 安全] PHP 反序列化漏洞 —— PHP 序列化 反序列化

关注这个专栏的其他相关笔记:[Web 安全] 反序列化漏洞 - 学习笔记-CSDN博客

0x01:PHP 序列化 — Serialize

序列化就是将对象的状态信息转化为可以存储或传输的形式的过程,在 PHP 中,通常使用 serialize() 函数来完成序列化的操作。

下面笔者直接简要点列出各个数据类型序列化之后的结果,不信的崽崽可以自己跑一下:

 echo serialize(null);       // N;echo serialize(123);        // i:123;   => int 类型的值为 123echo serialize(123.3);      // d:123.3; => double 类型的值为 123.3echo serialize(true);       // b:1;     => Boolean 类型的值为 Trueecho serialize("Blue17");   // s:6:"Blue17"; => String 类型的值为 Blue17echo serialize(array("Blue17", 17, null)); // a:3:{i:0;s:6:"Blue17";i:1;i:17;i:2;N;}

0x0101:序列化结果解析 — Array 类型

这部分笔者就简单分析一下上面 Array 类型序列化后的结果:

 echo serialize(array("Blue17", 17, null)); // a:3:{i:0;s:6:"Blue17";i:1;i:17;i:2;N;}​/*a:3               => array 中有三个元素i:0;s:6:"Blue17"  => index 为 0 的地方是一个长度为 6 的 String 类型的元素,值为 Blue17i:1;i:17;         => index 为 1 的地方是一个 int 类型的元素,值为 17i:2;N;            => index 为 2 的地方是一个 Null 类型的元素。*/

0x0102:序列化结果解析 — 类

类的序列化结果基本大差不差,但是不同 “访问类型” 的变量序列化的结果有很大差异,这部分笔者就按照 “访问类型” 进行分类,并对每个单独进行讲解。

1. 类序列化结果解析 —— Public 型

这里我们开始进入正规,讲讲最常见的类的序列化结果,先来一个最常见的试试水:

 <?php​class demo {public $var1;               // 这个变量没有赋值public $var2 = "Blue17";    // 这个变量赋予了字符串类型的值var $var3 = 17;          // 虽然修饰符是 var 但其实还是 public 类型的​function printVar($var) {$localVar = $var;    // 类方法中的局部变量echo $localVar;}}​// O:4:"demo":3:{s:4:"var1";N;s:4:"var2";s:6:"Blue17";s:4:"var3";i:17;}echo serialize(new demo(array(123)));

下面我们仔细分析一下结果,可以看到,它序列化的结果基本全是变量,类中方法其实是没有被序列化的,类中的局部变量也没有被序列化

 O:4:"demo":3:{s:4:"var1";N;s:4:"var2";s:6:"Blue17";s:4:"var3";i:17;}​// O:4:"demo":3 => Object 对象是一个 4 字的叫 demo,其中有 3 个属性(变量)// s:4:"var1";N; => 属性名称占 4 字节,叫 var1 其值是 Null 类型// s:4:"var2";s:6:"Blue17" => 属性名称占 4 字节,叫 var2,其值是 String 类型,长度为 6 内容是 Blue17// s:4:"var3";i:17; => 属性名称占 4 字节,叫 var3,其值是 int 类型,值为 17。

2. 类序列化结果解析 —— Protected 型

下面我们来看看如果类的属性中混入了 Protect 型的变量它序列化的结果长啥样吧:

 <?php​class demo {protected $var1;               // 这个变量没有赋值protected $var2 = "Blue17";    // 这个变量赋予了字符串类型的值protected $var3 = 17;          // 虽然修饰符是 var 但其实还是 public 类型的}​echo serialize(new demo()) . "\n";// O:4:"demo":3:{s:7:"*var1";N;s:7:"*var2";s:6:"Blue17";s:7:"*var3";i:17;}​echo urlencode(serialize(new demo()));// O%3A4%3A%22demo%22%3A3%3A%7Bs%3A7%3A%22%00%2A%00var1%22%3BN%3Bs%3A7%3A%22%00%2A%00var2%22%3Bs%3A6%3A%22Blue17%22%3Bs%3A7%3A%22%00%2A%00var3%22%3Bi%3A17%3B%7D

下面我们仔细分析一下结果,这里笔者特意对它序列化后的结果做了一个编码,因为里面其实有一些不可见的字符,不编码是看不出来的,大部分内容其实与 Public 一致,但是被 protected 修饰的变量序列化后的内容就有很大不同了:

 O:4:"demo":3:{s:7:"*var1";N;s:7:"*var2";s:6:"Blue17";s:7:"*var3";i:17;}​// s:7:"*var1";N; => 属性名称占 7 个字节?怎么数着只有 5 个?​// 这个是 URL 编码后的内容:s%3A7%3A%22%00%2A%00var1%22%3BN%3B// 这个是简单解码后的样子:s:7:"%00*%00var1";N;

如上,可以发现,Protected 属性序列化后明面看只有 *var1 这样,但其实 * 两边其实还藏了两个 ASCII 码值为 0 的字符 (这也引出后面一个 Bug,在尝试构造反序列化值得时候,不建议通过直接复制就篡改被 Protected 或者 Private 修饰的值,因为你复制得内容一般都不全,会丢掉这个特殊的 %00)。

3. 类序列化结果解析 —— Private 型

下面我们来看看如果类的属性中混入了 Private 型的变量它序列化的结果长啥样吧:

 <?php​class demo {private $var1;               // 这个变量没有赋值private $var2 = "Blue17";    // 这个变量赋予了字符串类型的值}​echo serialize(new demo()) . "\n";// O:4:"demo":2:{s:10:"demovar1";N;s:10:"demovar2";s:6:"Blue17";}​echo urlencode(serialize(new demo()));// O%3A4%3A%22demo%22%3A2%3A%7Bs%3A10%3A%22%00demo%00var1%22%3BN%3Bs%3A10%3A%22%00demo%00var2%22%3Bs%3A6%3A%22Blue17%22%3B%7D

下面我们仔细分析一下结果,这里笔者特意对它序列化后的结果做了一个编码,因为里面其实有一些不可见的字符,不编码是看不出来的,大部分内容其实与 Public 一致,但是被 Private 修饰的变量序列化后的内容就有很大不同了:

 O:4:"demo":2:{s:10:"demovar1";N;s:10:"demovar2";s:6:"Blue17";}​// s:10:"demovar1";N; => 属性名称占 10 个字节?怎么数着只有 8 个?​// 这个是 URL 编码后的内容:s%3A10%3A%22%00demo%00var1%22%3BN%3B// 这个是简单解码后的样子:s:10:"%00demo%00var1";N; => %00 算一位,数一数,刚好 10 位

如上,可以发现,Private 属性序列化后明面看只有 demovar1 这样,但其实类名两边其实还藏了两个 ASCII 码值为 0 的字符,所以其真实格式为(URL 编码后的哈,不编码的话 ASCII 值为 0 的其实是不可见字符) %00类名%00变量名

0x02:PHP 反序列化 — Unserialize

以下是反序列化相关的几个特性:

  • 反序列化就是将序列化得到的字符串转化为一个对象的过程。

  • 反序列化生成的对象成员属性值由被反序列化的字符串决定,与原来类预定义的值无关。

  • PHP 中通过 unserialize() 函数进行反序列化,序列化使用 serialize() 函数。

  • 反序列化不触发类的成员方法,需要被调用方法后才会被触发。(不一定,这个后面讲)

下面笔者就以 Public 型的类为例,讲解一下反序列化的用处(另外两种类型,流程一致,但是要特别注意 %00 到底有没有被复制过去,如果报错了,一般就是这个的问题)。

0x0201:反序列化 —— 正常流程

首先是比较简单的 Public 型类的反序列化,我们先创建一个类,假设叫 Note (笔记)类吧,然后我们写笔记就要实例化这个类,然后往这个类的对象里写东西,代码如下:

<?phpclass Note {public $title;   // 笔记标题public $content; // 笔记内容// 记录标题 & 内容function write($title, $content) {$this -> title = $title;$this -> content = $content;}// 读取标题 & 内容function read() {echo "Title: " . $this -> title . "\n";echo "Content: " . $this -> content . "\n";}
}// 实例化笔记类
$note = new Note();
// 往笔记里写东西
$note -> write("Hello, World!!", "Today Is a Nice Day!!");

如上,我们已经往笔记里写东西了,写了你要保存吧,可是你是个对象你咋保存?这时就可以使用序列化,把 $note 这个对象里的内容序列化然后存储在一个文件里:

// 保存 $note 笔记里的东西
echo serialize($note); // O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:21:"Today Is a Nice Day!!";}

OK,保存了你过段时间得看吧,给你看下面这个东西你又看不懂是不是:

O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:21:"Today Is a Nice Day!!";}

这个时候就需要用我们软件进行反序列化然后再调用 read 方法了是吧:

// 保存 $note 笔记里的东西
$save = serialize($note); // O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:21:"Today Is a Nice Day!!";}// 查看保存的内容
$raw = unserialize($save); // 对序列化的内容进行反序列化
$raw -> read();

如上,可以看到,通过反序列化被保存的值,我们成功还原了用户笔记里写的东西。下面是整个测试的源码(这里笔者特别提醒,反序列化的环境中要有序列化的那个类,不然即使反序列化了也是无法执行类的方法的):

<?php// 创建笔记类
class Note {public $title;   // 笔记标题public $content; // 笔记内容// 记录标题 & 内容function write($title, $content) {$this -> title = $title;$this -> content = $content;}// 读取标题 & 内容function read() {echo "Title: " . $this -> title . "\n";echo "Content: " . $this -> content . "\n";}
}// 实例化笔记类
$note = new Note();
// 往笔记里写东西
$note -> write("Hello, World!!", "Today Is a Nice Day!!");// 保存 $note 笔记里的东西
$save = serialize($note); // O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:21:"Today Is a Nice Day!!";}// 查看保存的内容
$raw = unserialize($save); // 对序列化的内容进行反序列化
$raw -> read(); // 执行类的成员方法

0x0202:反序列化 —— 异常流程

我们继续假设,我们刚刚是本地的,假设你写了笔记,然后你要上传,那你上传服务端的序列化的内容就是下面这个:

O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:21:"Today Is a Nice Day!!";}

假设,攻击者截获了这个内容,按照 PHP 序列化的格式自己改了一下(主要是改内容和长度):

O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:25:"Today Is NOT a Nice Day!!";}

如上,我们添加了一个单词 Not ,然后修改了长度,然后我们 “发送” 到服务端,让他读一下,代码如下:

<?php// 创建笔记类
class Note {public $title;   // 笔记标题public $content; // 笔记内容// 记录标题 & 内容function write($title, $content) {$this -> title = $title;$this -> content = $content;}// 读取标题 & 内容function read() {echo "Title: " . $this -> title . "\n";echo "Content: " . $this -> content . "\n";}
}
// 接收的信息
$receive = 'O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:25:"Today Is NOT a Nice Day!!";}';$raw = unserialize($receive); // 对序列化的内容进行反序列化
$raw -> read(); // 调用读方法

如上,可以看到,结果就这样被修改了。这就是前面介绍的反序列化的一个特性 “反序列化生成的对象成员属性值由被反序列化的字符串决定,与原来类预定义的值无关。”,也是我们后面 “反序列化漏洞的依据”。

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

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

相关文章

航空装配自动化神器Ethercat转profient网关搭配机器人精准控制

生产管理系统通过网关与装配机器人连接&#xff0c;加快航空器机身的装配速度&#xff0c;减少人为误差。 航空制造对装配线的精度和效率有着极高的要求。某航空制造厂使用的耐达讯Profinet转EtherCAT协议网关NY-PN-ECATM&#xff0c;将其生产管理系统与装配机器人连接&#xf…

什么是MySql的主从复制(主从同步)?

主页还有其他面试题总结&#xff0c;有需要的可以去看一下&#xff0c;喜欢的就留个三连再走吧~ 1.什么是MySql的主从复制原理&#xff1f; 主从复制的核心就是二进制binlog&#xff08;DDL&#xff08;数据定义语言&#xff09;语句和DML&#xff08;数据操纵语言&#xff09…

自然语言处理:初识自然语言处理

介绍 大家好&#xff0c;博主又来给大家分享知识了。从这次开始&#xff0c;博主给大家分享自然语言处理这个领域的内容。这也是博主非常感兴趣的研究领域。 最开始&#xff0c;博主计划在自然语言处理系列的第一篇博文中&#xff0c;和大家聊聊文本规范化这个话题。毕竟在自…

【保姆级视频教程(二)】YOLOv12训练数据集构建:标签格式转换-划分-YAML 配置 避坑指南 | 小白也能轻松玩转目标检测!

【2025全站首发】YOLOv12训练数据集构建&#xff1a;标签格式转换-划分-YAML 配置 避坑指南 | 小白也能轻松玩转目标检测&#xff01; 文章目录 1. 数据集准备1.1 标签格式转换1.2 数据集划分1.3 yaml配置文件创建 2. 训练验证 1. 数据集准备 示例数据集下载链接&#xff1a;P…

【人工智能】蓝耘智算平台盛大发布DeepSeek满血版:开创AI推理体验新纪元

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 蓝耘智算平台 蓝耘智算平台核心技术与突破元生代推理引擎快速入门&#xff1a;三步调用大模型接口&#xff0c;OpenAI SDK无缝兼容实战用例文…

【网络编程】几个常用命令:ping / netstat / xargs / pidof / watch

ping&#xff1a;检测网络联通 1. ping 的基本功能2. ping 的工作原理3. ping 的常见用法4. ping 的输出解释5. ping 的应用场景6. 注意事项 netstat&#xff1a;查看网络状态 1. netstat 的基本功能2. 常见用法3. 示例4. 输出字段解释5. netstat 的替代工具6. 注意事项 xargs&…

【C++】:STL详解 —— list类

目录 list的概念 list的构造函数 list的大小 size() resize() empty() list的插入 push_front()和emplace_front() push_back()和emplace_back() insert()和emplace() list的删除 pop_front() pop_back() erase() remove() remove_if() unique() clear()…

【数据结构】(11) Map 和 Set

一、Map 和 Set 的简介 1、Set 和 Map Map 和 Set 是集合类框架学习的最后一部分。Map 和 Set 都是接口&#xff0c;需要通过 TreeSet、HashSet 和 TreeMap、HashMap 实例化。注意&#xff0c;Set 实现了 Collection&#xff0c;Map 并没有。 Set 存放的是键&#xff08;Key&a…

关于CanvasRenderer.SyncTransform触发调用的机制

1&#xff09;关于CanvasRenderer.SyncTransform触发调用的机制 2&#xff09;小游戏Spine裁剪掉帧问题 3&#xff09;Dedicated Server性能问题 4&#xff09;.mp4视频放入RT进行渲染的性能分析闭坑指南 这是第421篇UWA技术知识分享的推送&#xff0c;精选了UWA社区的热门话题…

Kronecker分解(K-FAC):让自然梯度在深度学习中飞起来

Kronecker分解&#xff08;K-FAC&#xff09;&#xff1a;让自然梯度在深度学习中飞起来 在深度学习的优化中&#xff0c;自然梯度下降&#xff08;Natural Gradient Descent&#xff09;是一个强大的工具&#xff0c;它利用Fisher信息矩阵&#xff08;FIM&#xff09;调整梯度…

【HTML— 快速入门】HTML 基础

准备工作 vscode下载 百度网盘 Subline Text 下载 Sublime Text下载 百度网盘 vscode 下载 Sublime Text 是一款轻量好用的文本编辑器&#xff0c;我们在写前端代码时&#xff0c;使用 Sublime Text 打开比使用记事本打开&#xff0c;得到的代码体验更好&#xff0c;比 vscode…

鸿蒙开发深入浅出01(基本环境搭建、页面模板与TabBar)

鸿蒙开发深入浅出01&#xff08;基本环境搭建、页面模板与TabBar&#xff09; 1、效果展示2、下载 DevEco Studio3、创建项目4、新建页面模板5、更改应用信息6、新建以下页面7、Index.ets8、真机运行9、图片资源文件 1、效果展示 2、下载 DevEco Studio 访问官网根据自己的版本…

自动驾驶泊车算法详解(一)

自动驾驶泊车算法是自动驾驶技术中的重要组成部分&#xff0c;主要用于实现车辆在复杂场景下的自动泊车功能&#xff08;如垂直泊车、侧方位泊车、斜列泊车等&#xff09;。其核心目标是通过感知、规划和控制技术&#xff0c;使车辆在无人工干预的情况下安全、高效地完成泊车动…

鸿蒙next 点击穿透实现

点击穿透可以参考华为开发的保留文章,该章节只能在developer preview版本下查看 点击穿透 主要的方法是hitTestBehavior // xxx.ets Entry Component struct HitTestBehaviorExample {build() {// outer stackStack() {Button(outer button).onTouch((event) > {console.i…

27.[前端开发-JavaScript基础]Day04-函数基本使用-递归-变量作用域-函数式编程

一、JavaScript函数 1 认识JavaScript函数 程序中的foo、bar、baz 认识函数 函数使用的步骤 2 函数的声明和调用 声明和调用函数 函数的参数 有参数的函数练习 函数的返回值 函数的练习 arguments参数&#xff08;JS高级再学习&#xff09; 3 函数的递归调用 函数中调用函数…

蓝桥杯练习代码

一、最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 ""。 示例 1: 输入:strs = ["flower","flow","flight"] 输出:"fl"示例 2: 输入:strs = ["dog",&q…

添加成对约束后的标签传播算法研究:使用Python语言编写算法,在空手道数据集下验证算法的准确性,在一定程度上解决非对齐问题

背景&#xff1a; 辅导的过程中遇到了一个比较新颖的问题&#xff0c;下面是我对这个问题的分析和简要思路介绍。 思路分析&#xff1a; 这算机器学习下面的无监督学习&#xff0c;标签传播算法简称LPA&#xff0c;传统的标签传播算法会出现非对齐问题&#xff0c;一句话描述就…

鸿蒙开发第4篇__关于在鸿蒙应用中使用Java语言进行设计

本博文很重要 HarmonyOS从 API8 开始不再支持使用Java作为开发语言&#xff0c;未来的新功能将在ArkTS中实现. API 8对应的是HarmonyOS 3.0.0版本。请看下图&#xff1a; 因此&#xff0c; 读者如果看到类似《鸿蒙应用程序开发》(2021年版本 清华大学出版计)书 还使用Java语言…

sklearn机器学习 Python代码通用模板

以下是一个使用 scikit-learn&#xff08;sklearn&#xff09;进行机器学习的通用 Python 代码模板。这个模板涵盖了数据加载、预处理、模型训练、评估和预测的基本流程&#xff0c;适用于常见的机器学习任务。 python # 导入必要的库 import numpy as np import pandas as …

P9420 [蓝桥杯 2023 国 B] 双子数--最高效的质数筛【埃拉托斯特尼筛法】

P9420 [蓝桥杯 2023 国 B] 双子数 题目 分析代码 题目 分析 首先&#xff0c;我们如何找到双子数&#xff1f; 1&#xff09;找到所有质数满足范围内的质数&#xff08;即至少质数^2<23333333333333) 我们看见双子数x的范围2333<x<23333333333333&#xff0c;又因为…