php技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > PHP编程 > php技巧 > PHP反序列化漏洞

详解PHP反序列化漏洞示例与原理

作者:icewolf00

PHP反序列化漏洞也叫PHP对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一旦利用成功就会造成非常危险的后果。本文将详细讲讲PHP反序列化漏洞的原理及示例,感兴趣的可以了解一下

预备知识

PHP序列化与反序列化

序列化:将一个复杂的数据类型(如对象、数组、变量等)转换为字符串表示,以便于在网络中传输和在数据库中存储。在PHP语言中使用serialize()函数实现。

反序列化:将一个序列化的字符串重新转换为一个具体的数据类型。在PHP语言中使用unserialize()函数实现。 PHP对象中只有数据会被序列化,方法不会被序列化。

序列化字符串格式

PHP中经过序列化的字符串格式如下:

类型:类名长度:“类名”:类属性数量:{属性类型:属性长度:“属性内容”}

序列化字符串中的属性命名规则:如果变量为public,则值保持不变;如果变量为private,则在值开头加上类名前缀;如果变量为protected,则在值开头加*符号。

下面给出序列化字符串中的属性类型:

类型解释
s:length:“value”字符串
i:value整数值
d:value浮点数值
b:value布尔值
a:length:{…}数组
O:length:“name”:number:{…}对象
NNULL

PHP魔术方法

简介:魔术方法是一种以2个下划线开头的特殊方法,对一个对象执行魔术方法时会覆盖PHP默认的操作。

常见的PHP魔术方法如下:

方法调用时间
__construct(构造函数)创建新对象时
__destruct (析构函数)销毁对象时
__call在对象中调用不可用方法时
__callStatic在上下文中调用不可用方法时
__get读不可用值时
__set写不可用值时
__isset对不可用值调用isset()empty()
__unset对不可用值调用unset()
__sleep序列化对象时
__wakeup反序列化对象时
__toString对象被作为字符串使用时
__invoke尝试以调用函数方式调用对象时

示例

<?php
    class Test{
        public $a="aaa";
        private $b="bbb";
        protected $c=123;
        function __construct($a,$b,$c)
        {
            $this->a=$a;
            $this->b=$b;
            $this->c=$c;
            echo("Constructor called.<br>");
        }
        function __destruct()
        {
            echo("Destructor called.<br>");
        }
        function show()
        {
            echo($this->a."\n".$this->b."\n".$this->c."<br>");
        }
    }
    $data=new Test("a",1,1.1);
    $data_str=serialize($data);
    echo($data_str."\n");
    $data_new=unserialize($data_str);
    echo("<br>");
    $data_new->show();
?>

反序列化漏洞

反序列化漏洞指网站未对被用户所控制的序列化字符串做检查,攻击者提交了精心构造的有害序列化字符串,导致恶意代码被执行。常见于PHP、Python、Java等允许对象序列化功能的编程语言中。

在PHP中,导致反序列化漏洞的原因大多是魔术方法的不规范使用。(如输出变量内容、写文件操作、写数据库操作等参数用户可控)

构造函数&析构函数

假设网站页面部分代码编写如下:

<?php
    class Test
    {
        var $a="aaa";
        function __construct($a)
        {
            $this->a=$a;
            echo("Info:<br>".$a);
        }
    }
    $data_new=unserialize($_GET['data']);
    var_dump($data_new);
?>

当对象创建(或销毁)时,程序会输出对象中三个成员变量的值;程序还从API接口读取了一个序列化字符串并试图将其反序列化。此时如果将序列化字符串中的值修改为恶意代码,类名修改为Test,会导致反序列化漏洞攻击。

EXP:O:4:“Test”:1:{s:4:“test”;s:29:“<script>alert(‘xss’)</script>”;}

CVE-2016-7124

PHP5 <5.6.25PHP7 <7.0.10的环境中,如果类中存在__wakeup魔术方法,则在反序列化之前会先调用该方法。但当序列化字符串中属性数量大于真实属性数量时,该方法不会执行。

<?php
    class Test
    {
        var $mess="111";
        function __wakeup()
        {
            $this->mess="failed";
            echo("Please try again.<br>");
        }
    }
    $new_data=unserialize($_GET['ins']);
    var_dump($new_data);
?>

代码中,当反序列化一个字符串时,程序会执行__wakeup方法,将$mess设置为字符串,并显示失败信息。此时把序列化字符串中的属性数量值改大,__wakeup方法会失效。

EXP:http://127.0.0.1/serialize.php?ins=O:4:“Test”:2:{s:4:“mess”;s:25:"

<script>alert(1)</script>";}

到此这篇关于详解PHP反序列化漏洞示例与原理的文章就介绍到这了,更多相关PHP反序列化漏洞内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文