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

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

0x01:PHP 序列化 — Serialize

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

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

 echo serialize(null);       // N;
 echo serialize(123);        // i:123;   => int 类型的值为 123
 echo serialize(123.3);      // d:123.3; => double 类型的值为 123.3
 echo serialize(true);       // b:1;     => Boolean 类型的值为 True
 echo serialize("Blue17");   // s:6:"Blue17"; => String 类型的值为 Blue17
 echo 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 类型的元素,值为 Blue17
 i:1;i:17;         => index 为 1 的地方是一个 int 类型的元素,值为 17
 i: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 (笔记)类吧,然后我们写笔记就要实例化这个类,然后往这个类的对象里写东西,代码如下:

<?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 这个对象里的内容序列化然后存储在一个文件里:

// 保存 $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(); // 调用读方法

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

国科大——数据挖掘(0812课程)——课后作业

前沿&#xff1a; 此文章记录了2024年度秋季学期数据挖掘课程的三次课后作业&#xff0c;答案仅供参考。 第一次作业 1 假定数据仓库中包含4个维&#xff1a;date, product, vendor, location&#xff1b;和两个度量&#xff1a;sales_volume和sales_cost。 1&#xff09;画…

从电子管到量子计算:计算机技术的未来趋势

计算机发展的历史 自古以来人类就在不断地发明和改进计算工具,从结绳计数到算盘,计算尺,手摇计算机,直到1946年第一台电子计算机诞生,虽然电子计算机至今虽然只有短短的半个多世纪,但取得了惊人的发展吗,已经经历了五代的变革。计算机的发展和电子技术的发展密切相关,…

Redis核心数据结构与底层实现

5种基础数据结构 String 字符串list 列表hash 字典set 集合zset 有序集合 deepseek的回答 String 内部编码 redis根据当前值的类型和长度决定使用哪种内部编码&#xff0c;共3种内部编码&#xff1a; int &#xff1a;value为整数时embstr : 短字符串&#xff08;长度<…

【我的Android进阶之旅】Android Studio SDK Update Site 国内的腾讯云镜像配置指南

一、腾讯云的镜像 https://mirrors.cloud.tencent.com/AndroidSDK/ 二、 打开 Android Studio‌的SDK Manager 路径:Tools–>SDK Manager 在右侧找到 SDK Update Sites 列表‌‌,添加如下链接,像下面一样,一个一个添加 将下面几个链接都加上去 https:

C++知识整理day9——继承(基类与派生类之间的转换、派生类的默认成员函数、多继承问题)

文章目录 1.继承的概念和定义2.基类与派生类之间的转换3.继承中的作用域4.派生类的默认成员函数5.实现一个不能被继承的类6.继承与友元7.继承与静态成员8.多继承和菱形继承问题8.1 继承分类及菱形继承8.2 虚继承 1.继承的概念和定义 概念&#xff1a; 继承(inheritance)机制是⾯…

OpenCV计算摄影学(2)图像去噪函数denoise_TVL1()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 原始-对偶算法是用于解决特定类型变分问题&#xff08;即&#xff0c;寻找一个函数以最小化某个泛函&#xff09;的算法。特别地&#xff0c;图像…

【Kimi】自动生成PPT-并支持下载和在线编辑--全部免费

【Kimi】免费生成PPT并免费下载 用了好几个大模型&#xff0c;有些能生成PPT内容&#xff1b; 有些能生成PPT&#xff0c;但下载需要付费&#xff1b; 目前只有Kimi生成的PPT&#xff0c;能选择模板、能在线编辑、能下载&#xff0c;关键全部免费&#xff01; 一、用kimi生成PP…

SQL注入(order by,limit),seacms的报错注入以及系统库的绕过

1&#xff1a;如果information_schema被过滤了&#xff0c;该怎么绕过 1.1&#xff1a;介绍一下information_schema这个库 information_schema 是一个非常重要的系统数据库&#xff0c;它在SQL标准中定义&#xff0c;并且被许多关系型数据库管理系统&#xff08;RDBMS&#x…

猿大师播放器:交通水利、公安消防Web端Vue网页播放20路RTSP H.265 1080P监控视频流

随着互联网技术的飞速发展&#xff0c;视频监控已成为各行各业不可或缺的一部分。无论是交通物流、公安消防&#xff0c;还是水利农业、园区校园&#xff0c;视频监控都扮演着至关重要的角色。然而&#xff0c;传统的视频监控解决方案往往依赖于特定的客户端软件&#xff0c;这…

Vue3 + Spring WebMVC 验证码案例中的跨域问题与解决方法

最近在基于vue3 SpringWebMVC前后端分离的开发环境中实现一个验证码的案例&#xff0c;在开发过程中遇到了一些复杂的跨域问题&#xff0c;现已解决&#xff0c;故将解决方法分享&#xff0c;希望能帮到有需要的人。 出现的问题&#xff1a; 对于验证码的实现&#xff0c;我选…

Mac 版 本地部署deepseek ➕ RAGflow 知识库搭建流程分享(附问题解决方法)

安装&#xff1a; 1、首先按照此视频的流程一步一步进行安装&#xff1a;(macos版&#xff09;ragflowdeepseek 私域知识库搭建流程分享_哔哩哔哩_bilibili 2、RAGflow 官网文档指南&#xff1a;https://ragflow.io 3、RAGflow 下载地址&#xff1a;https://github.com/infi…

蛋白质研究常用数据库系列1

一系列常用的蛋白质研究数据库 一 蛋白综合数据库 1.1 Uniprot UniProt&#xff08;Universal Protein Resource&#xff0c;https://www.uniprot.org/&#xff09;是一个免费开放的综合性蛋白质数据库。该数据库蛋白信息来源于EMBL、GenBank、DDBJ等公共数据库&#xff08;非…

minio作为K8S后端存储

docker部署minio mkdir -p /minio/datadocker run -d \-p 9000:9000 \-p 9001:9001 \--name minio \-v /minio/data:/data \-e "MINIO_ROOT_USERjbk" \-e "MINIO_ROOT_PASSWORDjbjbjb123" \quay.io/minio/minio server /data --console-address ":90…

深圳南柯电子|医疗设备EMC测试整改检测:零到一,保障医疗安全

在当今医疗科技飞速发展的时代&#xff0c;医疗设备的电磁兼容性&#xff08;EMC&#xff09;已成为确保其安全、有效运行的关键要素之一。EMC测试整改检测不仅关乎设备的性能稳定性&#xff0c;更是保障患者安全、避免电磁干扰引发医疗事故的重要措施。 一、医疗设备EMC测试整…

安装TortoiseGit时,显示需要安装驱动?!

安装TortoiseGit时&#xff0c;显示需要安装驱动&#xff1f; 原因分析&#xff1a; 出现上述情况&#xff0c;单纯是被捆绑了&#xff0c;TortoiseGit是不需要任何插件 解决方案&#xff1a; 在电脑上选择应用Windows安装程序

高中数学基础-平面向量

文章目录 1、平面向量2、复数 高中数学-平面向量、复数 1、平面向量 向量&#xff1a;具有大小和方向的量称为向量&#xff1b;物理学中向量也称矢量&#xff0c;只有大小没有方向的量称为标量&#xff1b;向量的大小称为模&#xff0c;大小为1的是单位向量&#xff0c;长度为0…

springboot博客系统详解与实现(后端实现)

目录 前言&#xff1a; 项目介绍 一、项目的准备工作 1.1 数据准备 1.2 项目创建 1.3 前端页面的准备 1.4 配置配置文件 二、公共模块 2.1 根据需求完成公共层代码的编写 2.1.1 定义业务状态枚举 2.1.2 统一返回结果 2.1.3 定义项目异常 2.1.4 统一异常处理 三、业…

Visual Studio Code 远程开发方法

方法1 共享屏幕远程控制&#xff0c;如 to desk, 向日葵 &#xff0c;像素太差&#xff0c;放弃 方法2 内网穿透 ssh 第二个方法又很麻烦&#xff0c;尤其是对于 windows 电脑&#xff0c;要使用 ssh 还需要额外安装杂七杂八的东西&#xff1b;并且内网穿透服务提供商提供的…

清华大学deepseek文档下载地址,DeepSeek:从入门到精通(附下载包)104页全面详细介绍

文章目录 前言一、DeepSeek平台概述:二、推理模型与非推理模型对比:三、使用DeepSeek的提示语策略:四、任务需求与提示语设计:五、提示语设计的核心技能:六、常见陷阱与应对策略:七、AI幻觉与缺陷: 前言 这是一篇清华大学发的的关于DeepSeek人工智能平台的介绍性文章&#xff…

智能优化算法:雪橇犬优化算法(Sled Dog Optimizer,SDO)求解23个经典函数测试集,MATLAB

一、雪橇犬优化算法 算法简介&#xff1a;雪橇犬优化算法&#xff08;Sled Dog Optimizer&#xff0c;SDO&#xff09;是2024年10月发表于JCR1区、中科院1区SCI期刊《Advanced Engineering Informatics》的新型仿生元启发式算法。它模拟雪橇犬的拉雪橇、训练和退役行为构建模型…