浅谈PHP序列化,反序列化

1.序列化是什么意思呢?

序列化就是把本来不能直接存储的数据转换成可存储的数据,并且不会丢掉数据格式  serialize(); 

2.反序列化是什么意思呢?

其实就是字面的意思,把序列化的数据,转换成我们需要的格式      unserialize();

那么什么是序列化呢,序列化说通俗点就是把一个对象变成可以传输的字符串。举个例子,不知道大家知不知道json格式,这就是一种序列化,有可能就是通过array序列化而来的。而反序列化就是把那串可以传输的字符串再变回对象。

相关网站

https://www.cnblogs.com/junyi-bk/p/11631685.html

直接上例子便于理解:

我们先讲一讲比较简单的序列化,我们就用序列化json来举例子吧。虽然序列化Json和我们讲PHP反序列化的漏洞没有什么关系。但是在理解序列化这个概念和之后的内容会有所帮助

json_encode()

json_decode()

json_decode( )    ---- json 转 对象/数组

当第二个参数为true返回 array ,默认是false返回object。

json_encode( )    ---- 对象/数组 转 json

成功返回 json 编码的 string ,失败返回 false 。

相应网站

https://www.runoob.com/php/php-json.html

上代码

<?php

$book = array('book1'=>'1','book2'=>'2','Book3'=>'3','Book4'=>'4');

$json = json_encode($book);

var_dump($book);

echo $json;

?>

这边有一个book的数组

‘book1′=>’1’,

‘book2′=>’2’,

‘Book3′=>’3’,

‘Book4′=>’4’

  如果我们想传输这个数组怎么办呢,我们就可以请json_encode()这个函数帮助我们将这个数组序列化成一串字符串

 
 

  所以在这里,我们将数组序列化成json格式的字串的目的就是为了方便传输。我们可以看见,这里json格式来保存数据主要是使用键值对的形式。

好啦,接下来我们要开始深入一步,来讲讲如何把一个对象序列化成一串字符串。

假设,我们写了一个class,这个class里面存有一些变量。当这个class被实例化了之后,在使用过程中里面的一些变量值发生了改变。以后在某些时候还会用到这个变量,如果我们让这个class一直不销毁,等着下一次要用它的时候再一次被调用的话,浪费系统资源。当我们写一个小型的项目可能没有太大的影响,但是随着项目的壮大,一些小问题被放大了之后就会产生很多麻烦。这个时候PHP就和我们说,你可以把这个对象序列化了,存成一个字符串,当你要用的时候再放他出来就好了。

那么,怎么才能把一个对象序列化呢?

<?php

class DemoClass

{

public $name = "";

public $sex = "";

public $age = "";

}

$example = new DemoClass();

$example ->name ="111";

$example ->sex ="woman";

$example ->age ="18";

echo(一:);

var_dump($example);

$val = serialize($example);

echo(二:);

echo($val);

echo(三:);

var_dump($val);

$Newex = unserialize($val);

echo(四:);

var_dump($Newex);

echo(五:);

echo $Newex ->age;

?>

这里,我们先创了个DemoClass,里面存了点信息,后来我们new了一个实例$example的时候,将这个class里的一些信息给改变了。

如果我们之后还要用到这个实例怎么办呢,我们就先将他序列化存起来,到时候用的时候再放出来就好啦。

只要用serialize()这个函数就行了,反之利用unserialize()就可以将其进行反序列化回来。

serialize() 函数用于序列化对象或数组,并返回一个字符串。

serialize() 函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变。

如果想要将已序列化的字符串变回 PHP 的值,可使用 unserialize()

 
 

相应网站

https://www.runoob.com/php/php-serialize-function.html

这个时候,我们发现这次序列化出来的格式,和我们上一个序列化json的格式有点不同呢,解释一波:

 
 

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

private 的属性序列化后变成 <0x00>对象<0x00>属性名

public 没有任何变化

protected 的属性序列化后变成 <0x00>*<0x00>属性名

特殊十六进制<0x00>表示一个坏字节,就是空字节

3. 为什么会产生这个漏洞?

那么,问题来了,这么序列化一下然后反序列化,为什么就能产生漏洞了呢?

这个时候,我们就要了解一下PHP里面的魔术方法了,魔法函数一般是以__开头,通常会因为某些条件而触发不用我们手动调用:

在研究反序列化漏洞的时候,碰见这几个魔法函数就要仔细研究研究了:

__construct()  // 当一个对象创建时被调用,

__destruct()    // 当一个对象销毁时被调用,

__toString()    // 当一个对象被当作一个字符串被调用。

__wakeup()      // 使用unserialize()会检查是否存在__wakeup()方法,如果存在则会先调用,预先准备对象需要的资源

__sleep()      // 使用serialize()会检查是否存在__wakeup()方法,如果存在则会先调用,预先准备对象需要的资源

__destruct()    // 对象被销毁时触发

__call()        // 在对象上下文中调用不可访问的方法时触发

__callStatic()  // 在静态上下文中调用不可访问的方法时触发

__get()        // 用于从不可访问的属性读取数据

__set()        // 用于将数据写入不可访问的属性

__isset()      // 在不可访问的属性上调用isset()或empty()触发

__unset()      // 在不可访问的属性上使用unset()时触发

__toString()    // 把类当作字符串使用时触发,返回值需要为字符串

__invoke()      // 当脚本尝试将对象调用为函数时触发

相关网站

https://www.php.net/manual/zh/language.oop5.magic.php

如果服务器能够接收我们反序列化过的字符串、并且未经过滤的把其中的变量直接放进这些魔术方法里面的话,就容易造成很严重的漏洞了。

举个别人的例子:

<?php

class A{

    var $test = "demo";

    function __destruct(){

            echo $this->test;

    }

}

$a = $_GET['test'];

$a_unser = unserialize($a);

?>

这里我们只要构造payload:

test=O:9:"DemoClass":3:{s:4:"name";s:5:"Harry";s:3:"sex";s:5:"woman";s:3:"age";s:2:"18";}

就能控制echo出的变量,比如你能拿这个来进行反射型xss。(听你扯了半天你就给我看这个,别打我!)

参考网站:http://www.manongjc.com/detail/12-lbohplauhhknatd.html#!/h

https://www.cnblogs.com/xiaoqiyue/articles/10951836.html

注:本博客所引用的博客仅用与学术交流。

猜你喜欢

转载自blog.csdn.net/weixin_43553654/article/details/107686899