PHP反序列化深入理解

简单记录一下反序列化

0x00 什么是序列化

在PHP中右serialize()unserialize()两个函数,php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。


0x01 example

简单的一个例子

<?php
//序列化示例

//student类
class student{
    public $name = "DYBOY";
    public $sex = "boy";

    public function getInfo(){
        echo $this->$name;
    }
}

//实例化一个student对象
$person = new student();

//调用方法
$person->getInfo();

?>

访问得到如下结果:

这就是一个正常的例子
但是,在PHP中有一些魔术方法,会自动调用,比如常见的 __construct()__destruct(),__toString()等等,下面修改上面的example得到如下代码:

<?php
<?php
//序列化示例

class student{
    public $name = "DYBOY";
    public $sex = "boy";

    public function getInfo(){
        echo $this->name;
        echo "<br/>";
    }

    public function __construct(){
        echo "对象被建立<br/>";
    }

    public function __destruct(){
        echo "对象被销毁<br/>";
    }

    public function __toString(){
        return "当对象当作字符串输出时调用<br/>";
    }
}

$person = new student();

$person->getInfo();
echo $person; //对象当作字符串输出

?>

访问文件,得到如下:

总结几个常见魔术函数:

__wakeup() //使用unserialize时触发
__sleep() //使用serialize时触发
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发,返回值需要为字符串
__invoke() //当脚本尝试将对象调用为函数时触发
`

0x02 序列化

//接着上面的代码
echo serialize($person); 
//输出:O:7:"student":2:{s:4:"name";s:5:"DYBOY";s:3:"sex";s:3:"boy";}
echo unserialize($ser);
//输出:当对象当作字符串输出时调用 对象被销毁

字母类型解释:

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


0x03 漏洞利用

原因:当使用反序列化时,如果魔术函数当中的参数时可控的,那么就能够造成XSS或着其他的漏洞
漏洞CTF参考题目:神盾局的秘密

*参考文章:http://www.lmxspace.com/2018/05/03/php-unserialize-%E5%88%9D%E8%AF%86/

发表评论 / Comment

用心评论~