PHP 反序列化漏洞

序列化与反序列化
在维基百科中是这样定义的:

序列化是(serialization)在计算机科学的数据处理中,是指将数据结构或对象状态转换为可取用格式(例如存成文件,存于缓存,或经由网络中发送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。

概念其实很容易理解,就是将数据转换为一种可逆的存储格式,正向存储为序列化,反向存储就为反序列化。

按照王sir的理解,设想这样一种场景:在双十一的时候会有定时抢购的活动,很多用户会提前登陆等待抢购时间的到来,长时间不进行操作,这时候用户登陆的session会长时间驻留在内存当中,这样的session可能有几百万个服务器的内存肯定会吃紧,这时候开发人员会把session对象持久化操作,让其离开内存保存在硬盘,等到需要用的时候,再从硬盘中唤醒这个session加载进内存,这样就能大大的减轻内存的负荷。

这就是序列化与反序列化!!

在PHP应用中,序列化和反序列化一般用做缓存,比如session(会话)缓存,cookie缓存等。

常见的序列化格式:

  • 二进制格式
  • 字节数组
  • json字符串
  • xml字符串
PHP序列化与反序列化

php中的序列化的函数为Serialize,将对象转换为字符串保存对象中的变量及变量值。

php中的反序列化函数为unserialize,将序列化后的字符串转换为对象

简单示例:

//demo.php
<?php
class Test{
   
		public $name;
		public $blog;
}
$test = new Test();
$test->name="ZHOUXIONGXIONG";
$test->blog="https://mp.csdn.net";
echo "创建对象并给其属性赋值:</br>";
foreach($test as key =>$value){
   
echo $key."=>".$value."</br>";
}
$str= serialize($test);
echo "<br>对象序列化后的字符串:".$str;
$f = fopen('test.txt','w');
fwrite($f,$str);
fclose($f);
?>

运行后,可以看出创建的对象序列化后的字符串:
在这里插入图片描述
可知,创建的对象序列化后的内容为:

O:4:"Test":2:{
   s:4:"name";s:14:"ZHOUXIONGXIONG";s:4:"blog";s:19:"https://mp.csdn.net";}

思考分析后:

"O"即为Object对象,"4"为对象名的长度,"Test"即为对象名,"2"为对象的属性名个数;大括号内即为属性的内容:"s"即string字符串类型,"4"即该属性名的长度,“name"即该属性名,”;"间隔键值对的键与值以及不同的属性,后面的同理分析。

简单示例2

//demo2.php
<?php
$f = fopen("test.txt","r");
$str = fread($f, filesize("test.txt"));
echo "读取序列化的字符串:".$str;
echo "<br><br>经过反序列化后的结果如下:<br>";
$test = unserialize($str);
foreach ($test as $key => $value) {
   
	echo $key."=>".$value."<br>";
}

?>

运行后,可以看出反序列化后的得到的对象实例:
在这里插入图片描述

反序列化漏洞
基本函数
  • serialize() 序列化函数 ,php序列化一个对象时会保存类名,对象的所有变量及变量值,但是不会保存方法。
  • unserialize() 序列化函数 ,php反序列化函数把一个对象序列化后的字符串转换为对象。
PHP魔法函数

php中有一些函数可以在脚本的任何地方不需要声明就可以使用,因为某些条件触发不用手动调用。即不需要echo

下边是与php序列化有关系的魔法函数,俩个下滑线开头。

  • __construct():构造函数,当一个对象创建时被调用。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
  • __destruct():析构函数,当一个对象销毁时被调用。会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
  • __toString():当一个对象被当作一个字符串使用。此方法必须返回一个字符串,否则将发出一条E_RECOVERABLE_ERROR级别的致命错误。
  • __sleep():常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。serialize()函数会检查类中是否存在一个魔术方法__sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个E_NOTICE级别的错误。
  • __wakeup():经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。unserialize()会检查是否存在一个__wakeup()方法。如果存在,则会先调用__wakeup(),预先准备对象需要的资源。
基本概念

PHP在进行反序列化操作时,若存在相应的魔法函数、unserialize()函数的参数可控且可以传递到魔法函数中执行相应的敏感操作,则会造成PHP反序列化漏洞的风险。

利用前提
  • unserialize()函数的参数可控;
  • 代码中存在一个构造函数、析构函数、__wakeup()函数中有向PHP文件写数据的操作或执行PHP代码或命令执行的类;
  • 所写的内容需要有对象中的成员变量的值。

一个简单的测试demo

<?php
class demo{
   
	public $name;
	public $blog;
	function __construct(){
   
		echo "[^_^]调用__construct()<br>";
	}
	function __destruct(){
   
		echo "[^_^]调用__destruct()<br>";
	}
	function __wakeup(){
   
		echo "[^_^]调用__wakeup()<br>";
	}
	function __sleep(){
   
		echo "[^_^]调用__sleep()<br>";
		return array('name','blog');
	}
	function __toString(){
   
		echo "[^_^]调用__toString()<br>";
		return $this->name.":".$this->blog."<br>";
	}

}
echo "开始初始化对象。。。<br>";
$test = new demo();
$test->name="zhouxiongxiong";
$test->blog="https://mp.csdn.net";
echo "创建对象并给其属性赋值:<br>";
foreach ($test as $key => $value) {
   
	echo $key."=>".$value.
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值