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

    什么是序列化

    为了储存对象,serialize产生一个可存储的值的表示(字符串),并且可以通过unserialize对字符串进行解析。

    由于PHP本身对数据类型不敏感,不同类型对数据可以对变量进行赋值,反序列化过程由序列化字符串提供对象数量、对象数据类型、对象长度等信息,因此存在利用。

    <?php
    
        class foo{
            public $a = 1;
            protected $b = 1;
            private $c = 3;
        }
        $tmp = new foo();
        echo serialize($tmp);
    // O:3:"foo":3:{s:1:"a";i:1;s:4:"�*�b";i:1;s:6:"�foo�c";i:3;}
    
    访问类型 变量名 序列化后变量长度 备注
    public a 1
    protected b 1 + 3
    private c 1 + 5

    不同访问类型的序列化结果是不同的,但PHP7.1版本对数据访问类型不敏感,可使用public代替其他类型数据

    魔术方法及绕过

    方法 触发 用途 绕过方式 备注
    __sleep() serialize() 过滤不必要的对象存储,只存储数组中的变量名
    __wakeup() unserialize() 用于反序列化调用之前初始化参数 修改序列化字符串中类含有的对象个数,当个数与类不匹配则不触发
    __tostring() echo
    <?php
    
        class foo{
            public $a;
            protected $b;
            private $c;
            public function __construct()
            {
                $this->a = 1;
                $this->b = 1;
                $this->c = 3;
                echo "__construct
    ";
            }
            public function __destruct()
            {
                var_dump($this);
                echo "__destruct
    ";
            }
    
            public function __wakeup()
            {
                echo "__wakeup()
    ";
            }
            public function __sleep()
            {
                echo "__sleep()
    ";
                return array('a','b');
            }
            public function __toString()
            {
                echo "__toString()
    ";
                return "";
            }
        }
        $tmp = new foo();
        echo $tmp;
        echo "serialize start:
    ";
        $tmp = serialize($tmp);
        echo "unserialize start:
    ";
        unserialize($tmp);
    
    /*
    __construct
    __toString()
    serialize start:
    __sleep()
    object(foo)#1 (3) {
      ["a"]=>
      int(1)
      ["b":protected]=>
      int(1)
      ["c":"foo":private]=>
      int(3)
    }
    __destruct
    unserialize start:
    __wakeup()
    object(foo)#1 (3) {
      ["a"]=>
      int(1)
      ["b":protected]=>
      int(1)
      ["c":"foo":private]=>
      NULL
    }
    __destruct
    */
    

    注意反序列化是不会调用构造函数的

    修改类型

    <?php
        class test1{
    
        }
    
        class test2{
              public function __wakeup(){
               // echo "flag";
              }
        }
        class foo{
            public $a;
            protected $b;
            private $c;
            public function __construct()
            {
                $this->a = 1;
                $this->b = 1;
                $this->c = new test1();
            }
        }
        $tmp = new foo();
        var_dump($tmp);
        echo "serialize start:
    ";
        $tmp = serialize($tmp);
        echo $tmp . "
    ";
        echo "unserialize start:
    ";
        $tmp = unserialize('O:3:"foo":3:{s:1:"a";i:1;s:4:"�*�b";i:1;s:6:"�foo�c";O:5:"test2":0:{}}');
        var_dump($tmp);
    
    /*
    object(foo)#1 (3) {
      ["a"]=>
      int(1)
      ["b":protected]=>
      int(1)
      ["c":"foo":private]=>
      object(test1)#2 (0) {
      }
    }
    serialize start:
    O:3:"foo":3:{s:1:"a";i:1;s:4:"�*�b";i:1;s:6:"�foo�c";O:5:"test1":0:{}}
    unserialize start:
    object(foo)#1 (3) {
      ["a"]=>
      int(1)
      ["b":protected]=>
      int(1)
      ["c":"foo":private]=>
      object(test2)#2 (0) {
      }
    }
    */
    

    实验中,变量类test1,可以替换为类test2,并与类test2中的魔术方法一起配合达到攻击的目的

    逃逸覆盖

    反序列化过程字符串的截取长度是由序列中给出的长度决定的,利用这一点可以伪造

    <?php
        class foo{
            public $a = "aaaaa";
            public $b = "bbbbb";
            public $c = "ccccc";
        }
        $tmp = new foo();
        $tmp = serialize($tmp);
        echo  $tmp;
        // O:3:"foo":3:{s:1:"a";s:5:"aaaaa";s:1:"b";s:5:"bbbbb";s:1:"c";s:5:"ccccc";}
    
        $payload  = 'bbbbb";s:1:"c";s:5:"ddddd";}';
        $ser = 'O:3:"foo":3:{s:1:"a";s:5:"aaaaa";s:1:"b";s:5:"'.$payload.'";s:1:"c";s:5:"ccccc";}';
        var_dump(unserialize($ser));
    /*
    {
      ["a"]=>
      string(5) "aaaaa"
      ["b"]=>
      string(5) "bbbbb"
      ["c"]=>
      string(5) "ddddd"
    }
    */
    
    1. 使字符串长度s变小
    2. 使字符串本身经过replace后变长
  • 相关阅读:
    Web Browser使用技巧
    Excel 函数
    删除文件夹, 解决源文件名长度大于文件系统支持的长度问题
    Send Mail using C# code
    动态规划——最长回文子串
    字符串处理总结
    打印日期
    A+B
    对称矩阵
    最小年龄的3个职工
  • 原文地址:https://www.cnblogs.com/chir/p/13431522.html
Copyright © 2011-2022 走看看