iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > PHP编程 >PHP序列化和反序列化
  • 518
分享到

PHP序列化和反序列化

php开发语言 2023-08-31 15:08:23 518人浏览 薄情痞子
摘要

一.什么是序列化和反序列化 PHP类与对象 类是定义一系列属性和操作的模板,而对象,就是把属性进行实例化,完事交给类里面的方法,进行处理。 `。尝试构造payload:

一.什么是序列化和反序列化

PHP类与对象

类是定义一系列属性和操作的模板,而对象,就是把属性进行实例化,完事交给类里面的方法,进行处理。

phpclass people{   //定义类属性(类似变量),public 代表可见性(公有)    public $name = 'joker';   //定义类方法(类似函数)   public function smile(){        echo $this->name." is smile...\n";   }}$psycho = new people(); //根据people类实例化对象$psycho->smile();?>

在这里插入图片描述
上述代码定义了一个people类,并在在类中定义了一个public类型的变量 n a m e 和类方法 s m i l e 。然后实例化一个对象 name和类方法smile。然后实例化一个对象 name和类方法smile。然后实例化一个对象psycho,去调用people类里面的smile方法,打印出结果。

含义

php序列化(serialize):是将变量转换为可保存或传输的字符串的过程
php反序列化(unserialize):就是在适当的时候把这个字符串再转化成原来的变量使用
这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。
对象序列化成的字节序列会包含对象的类型信息、对象的数据等,说白了就是包含了描述这个对象的所有信息,能根据这些信息“复刻”出一个和原来一模一样的对象。
常见的php系列化和反系列化方式主要有:serialize,unserialize;json_encode,json_decode。
示例

class object{    public $team = 'joker';    private $team_name = 'hahaha';    protected $team_group = 'biubiu';    function hahaha(){        $this->$team_members = '奥力给';    }}$object = new object();echo serialize($object);?>

在这里插入图片描述
O 表示object,一个对象
6 表示对象名长度为6
object 对象名称
3 表示有3个属性
后面花括号里的是类属性的内容,s表示的是类属性team的类型,4表示类属性team的长度,后面的以此类推。
对象类型:对象长度:“对象名称”:类中变量的个数:{变量类型:长度:“名称”;类型:长度:“值”;…}

序列化

序列化格式中的字母含义:
a - array
b - boolean
d - double
i - integer
o - common object
r - reference
s - string
C - custom object
O - class
N - null
R - pointer reference
U - unicode string
类方法并不会参与到实例化里面
需要注意的是变量受到不同修饰符(public,private,protected)修饰进行序列化时,序列化后变量的长度和名称会发生变化
使用public修饰进行序列化后,变量$team的长度为4,正常输出。
使用private修饰进行序列化后,会在变量$team_name前面加上类的名称,在这里是object,并且长度会比正常大小多2个字节,也就是9+6+2=17。
使用protected修饰进行序列化后,会在变量$team_group前面加上*,并且长度会比正常大小多3个字节,也就是10+3=13。
通过对比发现,在受保护的成员前都多了两个字节,受保护的成员在序列化时规则:
1.受Private修饰的私有成员,序列化时: \x00 + [私有成员所在类名] + \x00 [变量名]
2. 受Protected修饰的成员,序列化时:\x00 + * + \x00 + [变量名]
其中,“\x00"代表ASCII为0的值,即空字节,” * " 必不可少。

反序列化

依次根据规则进行反向复原。
这边定义一个字符串,然后使用反序列化函数unserialize进行反序列化处理,最后使用var_dump进行输出:

    $ser = 'O:6:"object":3:{s:1:"a";i:1;s:4:"team";s:6:"hahaha";}';    $ser = unserialize($ser);    var_dump($ser);?>

在这里插入图片描述

二.魔术方法

方法名作用
__construct构造函数,在创建对象时候初始化对象,一般用于对变量赋初值
__destruct析构函数,和构造函数相反,在对象不再被使用时(将所有该对象的引用设为null)或者程序退出时自动调用
__toString当一个对象被当作一个字符串被调用,把类当作字符串使用时触发,返回值需要为字符串,例如echo打印出对象就会调用此方法
__wakeup()使用unserialize时触发,反序列化恢复对象之前调用该方法
__sleep()使用serialize时触发 ,在对象被序列化前自动调用,该函数需要返回以类成员变量名作为元素的数组(该数组里的元素会影响类成员变量是否被序列化。只有出现在该数组元素里的类成员变量才会被序列化)
__destruct()对象被销毁时触发
__call()在对象中调用不可访问的方法时触发,即当调用对象中不存在的方法会自动调用该方法
__callStatic()在静态上下文中调用不可访问的方法时触发
__get()读取不可访问的属性的值时会被调用(不可访问包括私有属性,或者没有初始化的属性)
__set()在给不可访问属性赋值时,即在调用私有属性的时候会自动执行
__isset()当对不可访问属性调用isset()或empty()时触发
__unset()当对不可访问属性调用unset()时触发
__invoke()当脚本尝试将对象调用为函数时触发

__tostring的具体触发场景:

(1) echo( o b j ) / p r i n t ( obj) / print( obj)/print(obj) 打印时会触发
(2) 反序列化对象与字符串连接时
(3) 反序列化对象参与格式化字符串时
(4) 反序列化对象与字符串进行比较时(PHP进行比较的时候会转换参数类型) (5) 反序列化对象参与格式化sql语句,绑定参数时
(6) 反序列化对象在经过php字符串函数,如 strlen()、addslashes()时
(7) 在in_array()方法中,第一个参数是反序列化对象,第二个参数的数组中有toString返回的字符串的时候toString会被调用
(8) 反序列化的对象作为 class_exists() 的参数的时候

三.php反序列化漏洞(对象注入)

在反序列化过程中,其功能就类似于创建了一个新的对象(复原一个对象可能更恰当),并赋予其相应的属性值。如果让攻击者操纵任意反序列数据, 那么攻击者就可以实现任意类对象的创建,如果一些类存在一些自动触发的方法(魔术方法),那么就有可能以此为跳板进而攻击系统应用。
挖掘反序列化漏洞的条件是:
1.代码中有可利用的类,并且类中有__wakeup(),__sleep(),__destruct()这类特殊条件下可以自己调用的魔术方法。
2. unserialize()函数的参数可控。

php对象注入示例一:

class A{    var $test = "demo";    function __destruct(){        @eval($this->test);    }}$test = $_POST['test'];$len = strlen($test)+1;$p = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$test.";\";}"; // 构造序列化对象$test_unser = unserialize($p); // 反序列化同时触发_destruct函数?>

最终的目的是通过调用__destruct()这个析构函数,将恶意的payload注入,导致代码执行。根据上面的魔术方法的介绍,当程序跑到unserialize()反序列化的时候,会触发__destruct()方法,同时也可以触发__wakeup()方法。但是如果想注入恶意payload,还需要对$test的值进行覆盖,题目中已经给出了序列化链,很明显是对类A的$test变量进行覆盖。
在这里插入图片描述
首先这里要传入$test,而test就是phpinfo();$p = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$test.";\";}"; 这里重新定义了A,把test变成了我们传递的值,这句话的功能就相当于var $test = "$_POST=['test']";,而在php中这句话就把前面的var $test = "demo";覆盖掉了,从而执行了__destruct()这个析构函数,eval也就执行了我们提交的phpinfo

php对象注入示例二:

class test{    var $test = '123';    function __wakeup(){        $fp = fopen("flag.php","w");        fwrite($fp,$this->test);        fclose($fp);    }}$a = $_GET['id'];print_r($a);echo "
"
;$a_unser = unserialize($a);require "flag.php";?>

这里主要通过调用魔术方法__wakeup将KaTeX parse error: Expected group after '_' at position 47: …ize()反序列化操作时会触发_̲_wakeup魔术方法,接下来…test变量的值,将php探针写入flag.php文件中,并通过下面的require引用,导致命令执行。

php反序列化利用—POP链构造

上面的例子都是基于 " 自动调用 " 的magic function。但当漏洞/危险代码存在类的普通方法中,就不能指望通过 " 自动调用 " 来达到目的了。这时我们需要去寻找相同的函数名,把敏感函数和类联系在一起。一般来说在代码审计的时候我们都要盯紧这些敏感函数的,层层递进,最终去构造出一个有杀伤力的payload。

POP链简介

1.POP 面向属性编程(Property-Oriented Programing)

常用于上层语言构造特定调用链的方法,与二进制利用中的面向返回编程(Return-Oriented Programing)的原理相似,都是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链,最终达到攻击者邪恶的目的。类似于PWN中的ROP,有时候反序列化一个对象时,由它调用的__wakeup()中又去调用了其他的对象,由此可以溯源而上,利用一次次的 " gadget " 找到漏洞点。

2. POP CHaiN

把魔术方法作为最开始的小组件,然后在魔术方法中调用其他函数(小组件),通过寻找相同名字的函数,再与类中的敏感函数和属性相关联,就是POP CHAIN 。此时类中所有的敏感属性都属于可控的。当unserialize()传入的参数可控,便可以通过反序列化漏洞控制POP CHAIN达到利用特定漏洞的效果。

POP链利用技巧

1 一些有用的POP链中出现的方法:

命令执行:exec()、passthru()、popen()、system()
文件操作:file_put_contents()、file_get_contents()、unlink()
代码执行:eval()、assert()、call_user_func()

2. 反序列化中为了避免信息丢失,使用大写S支持字符串的编码。

PHP 为了更加方便进行反序列化 Payload 的 传输与显示(避免丢失某些控制字符等信息),我们可以在序列化内容中用大写S表示字符串,此时这个字符串就支持将后面的字符串用16进制表示,使用如下形式即可绕过,即:s:4:"user"; -> S:4:"use\72";

3. 深浅copy

在php中如果我们使用 & 对变量A的值指向变量B,这个时候是属于浅拷贝,当变量B改变时,变量A也会跟着改变。在被反序列化的对象的某些变量被过滤了,但是其他变量可控的情况下,就可以利用浅拷贝来绕过过滤。 $A = &$B;

4. 利用PHP伪协议

配合PHP伪协议实现文件包含、命令执行等漏洞。如glob:// 伪协议查找匹配的文件路径模式。

POP链构造案例

class main {    protected $ClassObj;    function __construct() {        $this->ClassObj = new nORMal();    }    function __destruct() {        $this->ClassObj->action();    }}class normal {    function action() {        echo "hello bmjoker";    }}class evil {    private $data;    function action() {        eval($this->data);    }}//$a = new main();unserialize($_GET['a']);?>

如上代码,危险的命令执行方法eval不在魔术方法中,在evil类中。但是魔术方法__construct()是调用normal类,__destruct()在程序结束时会去调用normal类中的action()方法。而我们最终的目的是去调用evil类中的action()方法,并伪造evil类中的变量KaTeX parse error: Expected group after '_' at position 41: …去构造POP利用链,让魔术方法_̲_construct()去调用…data赋予恶意代码,比如php探针phpinfo(),这样就相当于执行`。尝试构造payload:

class main {    protected $ClassObj;    function __construct() {        $this->ClassObj = new evil();    }}class evil {    private $data = "phpinfo();";}$a = new main();echo serialize($a);?>

编写我们想要执行的效果,然后进行序列化。
但是由于$ClassObj是protected类型修饰,$data是private类型修饰,在序列化的时候,多出来的字节都被\x00填充,需要进行在代码中使用urlencode对序列化后字符串进行编码,否则无法复制解析。运行得到O:4:"main":1:{s:11:"*ClassObj";O:4:"evil":1:{s:10:"evildata";s:10:"phpinfo();";}}

在这里插入图片描述
这里报错是因为这个的空字符串被当作空格变成%20,而空格在ASCII码中为32,所以要把%20改为%00127.0.0.1/1/1.php?a=O:4:"main":1:{s:11:"%00*%00ClassObj";O:4:"evil":1:{s:10:"%00evil%00data";s:10:"phpinfo();";}}
在这里插入图片描述

PHP Session反序列化

session请求过程

当第一次访问网站时,Seesion_start()函数就会创建一个唯一的Session ID,并自动通过Http的响应头,将这个Session ID保存到客户端Cookie中。同时,也在服务器端创建一个以Session ID命名的文件,用于保存这个用户的会话信息。当同一个用户再次访问这个网站时,也会自动通过HTTP的请求头将Cookie中保存的Seesion ID再携带过来,这时Session_start()函数就不会再去分配一个新的Session ID,而是在服务器的硬盘中去寻找和这个Session ID同名的Session文件,将这之前为这个用户保存的会话信息读出,在当前脚本中应用,达到跟踪这个用户的目的。

session_start的作用

当会话自动开始或者通过 session_start() 手动开始的时候, PHP 内部会依据客户端传来的PHPSESSID来获取现有的对应的会话数据(即session文件), PHP 会自动反序列化session文件的内容,并将之填充到 $_SESSION 超级全局变量中。如果不存在对应的会话数据,则创建名为sess_PHPSESSID(客户端传来的)的文件。如果客户端未发送PHPSESSID,则创建一个由32个字母组成的PHPSESSID,并返回set-cookie。

Session存储机制

PHP中的Session中的内容并不是放在内存中的,而是以文件的方式来存储的,存储方式就是由配置项session.save_handler来进行确定的,默认是以文件的方式存储。存储的文件是以sess_sessionid来进行命名的,文件的内容就是Session值的序列化之后的内容。
PHP Session在php.ini中主要存在以下配置项:

Directive*含义
session.save_handler设定用户自定义session存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)。默认为files
session.save_path设置session的存储路径,默认在/tmp
session.serialize_handler定义用来序列化/反序列化的处理器名字。默认使用php。
session.auto_start指定会话模块是否在请求开始时启动一个会话,默认为0不启动
session.upload_progress.enabed将上传文件的进度信息存储在session中。默认开启
session.upload_progress.cleanup一旦读取了所有的POST数据,立即清除进度信息。默认开启

在这里插入图片描述
注意:这里修改session.save.path在php.ini中修改,三个都要改而且要去掉前面的冒号,重启才可以生效

在PHP中Session有三种序列化的方式,分别是php,php_serialize,php_binary,不同的引擎所对应的Session的存储的方式不同

存储引擎存储方式
php_binary键名的长度对应的 ASCII 字符 + 键名 + 经过 serialize() 函数序列化处理的值
php键名 + 竖线 + 经过 serialize() 函数序列处理的值
php_serialize(PHP>5.5.4) 经过 serialize() 函数序列化处理的数组

Session反序列化漏洞

PHP在session存储和读取时,都会有一个序列化和反序列化的过程,PHP内置了多种处理器用于存取 $_SESSION 数据,都会对数据进行序列化和反序列化,PHP中的Session的实现是没有的问题的,漏洞主要是由于使用不同的引擎来处理session文件造成的
存在对$_SESSION变量赋值
php引擎存储Session的格式为

php键名 + 竖线 + 经过 serialize() 函数序列处理的值
php_serialize(PHP>5.5.4) 经过 serialize() 函数序列化处理的数组

如果程序使用两个引擎来分别处理的话就会出现问题。比如下面的例子,先使用php_serialize引擎来存储
session 1:

error_reporting(0);ini_set('session.serialize_handler','php_serialize');session_start();$_SESSION['username'] = $_GET['user'];echo "
";var_dump($_SESSION);echo "
"
;?>

接下来使用php引擎来读取Session文件
session 2:

error_reporting(0);ini_set('session.serialize_handler','php');session_start();class user{    var $name;    var $age;    function __wakeup(){        echo "hello ".$this->name." !"    }}?>

漏洞的主要原因在于不同的引擎对于竖杠’ | ‘的解析产生歧义。
对于php_serialize引擎来说’ | ‘可能只是一个正常的字符;但对于php引擎来说’ | ‘就是分隔符,前面是$_SESSION['username']的键名 ,后面是GET参数经过serialize序列化后的值。从而在解析的时候造成了歧义,导致其在解析Session文件时直接对’ | ‘后的值进行反序列化处理。
可能有的人看到这里会有疑问,在使用php引擎读取Session文件时,为什么会自动对’ | '后面的内容进行反序列化呢?也没看到反序列化unserialize函数。
这是因为使用了session_start()这个函数 ,PHP会自动反序列化数据并填充$_session超级全局变量。PHP能自动反序列化数据的前提是,现有的会话数据是以特殊的序列化格式存储。
构造payload:

    class user{        var $name;        var $age;    }    $a = new user();    $a->name = "bmjoker";    $a->age = "888";    echo serialize($a);?>

运行得到O:4:"user":2:{s:4:"name";s:7:"bmjoker";s:3:"age";s:3:"888";},生成的payload如果想利用php引擎读取Session文件时对’ | ‘解析产生的反序列化漏洞,需要在payload前加个’ | ',这个时候经过php_serialize引擎存储就会变成:
在这里插入图片描述

在这里插入图片描述

当使用php引擎的时候,php引擎会以|作为key和value的分隔符;左边部分是session的key,右边部分为session的vale
直接运行session 2
在这里插入图片描述

来源地址:https://blog.csdn.net/qq_31088019/article/details/126519989

--结束END--

本文标题: PHP序列化和反序列化

本文链接: https://www.lsjlt.com/news/386119.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • PHP序列化和反序列化
    一.什么是序列化和反序列化 php类与对象 类是定义一系列属性和操作的模板,而对象,就是把属性进行实例化,完事交给类里面的方法,进行处理。 `。尝试构造payload: ...
    99+
    2023-08-31
    php 开发语言
  • PHP的序列化和反序列化入门
    什么是PHP序列化 serialize() //将一个对象转换成一个字符串unserialize() //将字符串还原成一个对象 通过序列化与反序列化我们可以很方便的在PHP中进行对象的传递。本质上反序列化是没有危害的。但是如果...
    99+
    2023-10-27
    android
  • 序列化与反序列化
    序列化(pickling)   把变量从内存中变成可存储或传输的过程 反序列化(unpickling)   把变量内容从序列化的对象重新读到内存里的过程 序列化&反序列化的意义  在程序运行过程中,对象可在内存中被自由的修改  一...
    99+
    2023-01-31
    序列 化与 序列化
  • PHP反序列化
    文章目录 简介POP链构造和Phar://题目[CISCN2019 华北赛区 Day1 Web1]Dropbox 字符串逃逸 简介 php序列化的过程就是把数据转化成一种可逆的数...
    99+
    2023-09-01
    php 开发语言
  • PHP中的序列化和反序列化是什么
    这篇“PHP中的序列化和反序列化是什么”文章,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要参考一下,对于“PHP中的序列化和反序列化是什么”,小编整理了以下知识点,请大家跟着小编的步伐一步一步的慢慢理解,接下来就让...
    99+
    2023-06-06
  • Java序列化和反序列化(详解)
    一、理解Java序列化和反序列化 Serialization(序列化):将java对象以一连串的字节保存在磁盘文件中的过程,也可以说是保存java对象状态的过程。序列化可以将数据永久保存在磁盘上(通常保存在文件中)。 deserializa...
    99+
    2023-09-11
    java 开发语言
  • 【反序列化漏洞-01】序列化与反序列化概述
    为什么要序列化 百度百科上关于序列化的定义是,将对象的状态信息转换为可以存储或传输的形式(字符串)的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区(非关系型键值对形式的数据库Redis,与数组类似)。以后,可以通过从存储区中...
    99+
    2023-09-06
    web安全 安全 反序列化 序列化 PHP反序列化漏洞 Powered by 金山文档
  • [Java反序列化]—Shiro反序列化(一)
    环境配置:  IDEA搭建shiro550复现环境_普通网友的博客-CSDN博客 漏洞原理: Apache Shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie。在服务端对remem...
    99+
    2023-09-03
    java 开发语言
  • Java序列化与反序列化
    目录Java 序列化与反序列化序列化APIObjectOutputStreamObjectInputStreamserialVersionUIDTransient (瞬态变量)实例理...
    99+
    2023-05-14
    Java序列化 Java反序列化
  • PHP的序列化和反序列化详情
    目录一、PHP 为什么要反序列化?二、PHP如何反序列化?三、PHP反序列化漏洞1、常用 的魔术方法2、漏洞产生条件3、题目一、PHP 为什么要反序列化? PHP程序执行结束以后会将...
    99+
    2022-11-13
  • CTF-PHP反序列化
    CTFSHOW-关卡254到258-原生类&POP构造 CTF-254-对象引用执行逻辑 username=xxxxxx&password=xxxxxx 解题思路:触发vipOneKeyGetFlag这个方法,同时让方法中的判断为真才能获...
    99+
    2023-09-22
    php java 开发语言
  • 协议,序列化,反序列化,Json
    文章目录 协议序列化和反序列化网络计算器protocol.hppServer.hppServer.ccClient.hppClient.cclog.txt通过结果再次理解通信过程 Json...
    99+
    2023-09-01
    json 网络 服务器
  • Java之对象的序列化和反序列化
    对象的序列化和反序列化1)对象序列化,就是将Object对象转换成byte序列,反之叫对象的反序列化。2)序列化流(ObjectOutputStream),是字节的过滤流—— writeObject()方法 反序列化流(Object...
    99+
    2019-09-29
    Java IO流 对象 序列化 反序列化
  • 图文浅析Java序列化和反序列化
    序列化 序列化:将对象转换为二进制序列在网络中传输或保存到磁盘 反序列化:从网络或磁盘中将二进制序列转换为对象 注意: 对象必须实现Serializable接口 对象的所有属性都要...
    99+
    2022-11-12
  • Java序列化和反序列化示例介绍
    以前用序列化都是一些方法需要才实现的,后来业务需求要深拷贝才去研究。参阅了别人博客得出一些总结。 序列化是为了把Java对象转化为字节序列(字节流)的过程。然后深拷贝是通过对流的操作...
    99+
    2022-11-12
  • TCP定制协议,序列化和反序列化
    目录 前言 1.理解协议 2.网络版本计算器 2.1设计思路 2.2接口设计 2.3代码实现: 2.4编译测试 总结 前言         在之前的文章中,我们说TCP是面向字节流的,但是可能对于面向字节流这个概念,其实并不理解的,今...
    99+
    2023-08-31
    tcp/ip 网络 java
  • Java序列化和反序列化示例分析
    这期内容当中小编将会给大家带来有关Java序列化和反序列化示例分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。序列化是为了把Java对象转化为字节序列(字节流)的过程。然后深拷贝是通过对流的操作来实现的...
    99+
    2023-06-26
  • C#对Json进行序列化和反序列化
    一、Json简介 Json(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于JS的一个子集。 Json采用完全独立于语言的文本格式。这使得J...
    99+
    2022-11-13
  • C#如何实现序列化和反序列化
    这篇文章给大家分享的是有关C#如何实现序列化和反序列化的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。.net下有一种技术叫做对象序列化,说得通俗一点,C#序列化就是把一个对象保存到一个文件或数据库字段中去,C#反...
    99+
    2023-06-17
  • springboot序列化和反序列化怎么定义
    在Spring Boot中,序列化和反序列化可以通过以下方式进行定义:1. 实现Serializable接口:在需要进行序列化和反序...
    99+
    2023-08-14
    springboot
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作