PHP反序列化漏洞学习总结

来源:互联网 发布:js object 数组去重 编辑:程序博客网 时间:2024/06/10 03:57
  一直以来总是觉得对PHP反序列化漏洞的理解比较模糊,今天抽时间深入学习下PHP反序列化漏洞的成因以及利用方式,在此做一个总结。


   参考链接:

      

      http://bobao.360.cn/learning/detail/3193.html

      http://blog.csdn.net/qq_32400847/article/details/53873275?readlog




  PHP反序列化漏洞,也叫php对象注入(PHP Object Injection)。


  1. 序列化与反序列化


   说到反序列化,就要提到序列化。序列化和反序列化的目的是使得程序间传输对象更加方便。序列化是将对象转换为字符串以便存储和传输的一种方式。而反序列化就是序列化的逆过程,它会将字符串重新转换为对象供程序使用。


   在PHP中序列化和反序列化对应的函数分别为serialize()和unserialize()。反序列化本身并不危险,但是如果反序列化时传入反序列化函数的参数是用户可控的,反序列化漏洞就产生了。


   PHP手册中关于对象序列化的描述:


    所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示,unserialize()函数能够重新把字符串变回php原来的值。反序列化一个对象将会保存对象的所有变量。但是不会保存对象的方法,只会保存类的名字。  为了能够unserialize()一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。如果要想在另外一个文件中解序列化一个对象,这个对象的类必须在解序列化之前定义,可以通过包含一个该类的文件或使用函数spl_autoload_register()来实现。




  PHP中的magic方法(函数):


   魔术方法就是在某些条件下自动执行的函数。


  为什么会有魔术方法:


   魔术方法是在需要实现一些功能,但是一般代码做不到或很难做到的时候才能用。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。


   php类可能会包含一些特殊的函数叫magic方法,magic方法命名是以符号__开头的,比如__construct()、__destruct()、__toString()、__sleep()、__wakeup()等等,这些函数在某些情况下会自动调用。一些magic函数及其用途如下:


  
     __construct()         当一个对象创建时触发


     __destruct()          当一个对象被销毁时触发


     __toString()          把类当作字符串使用时触发


     __call()              在对象上下文中调用不可访问的方法时触发


     __callStatic()        在静态上下文中调用不可访问的方法时触发


     __get()               用于从不可访问的属性读取数据时


     __set()               用于将数据写入不可访问的属性


     __wakeup()            使用unserialize时触发


     __sleep()             使用serialize时触发


     __isset()             在不可访问的属性上调用isset()或empty()触发


     __unset()             在不可访问的属性上使用unset()时触发


     __invoke()            当脚本尝试将对象调用为函数时触发


     __autoload()          尝试加载未定义的类时触发


     __clone()             当对象复制完成时触发






   配合代码讲解,更容易理解魔术方法怎么调用的:




  <?php


 class Brucetg{


  public $test = "This is just a test";


  public function PrintTest()
  {
  echo $this->test.'<br/>';
  }


  public function __construct()
  {
  echo '__construct</br>';
  }


  public function __destruct()
  {
  echo '__destruct<br />';


  }


  public function __toString()
  {
  return '__toString<br />';


  }
 }


  $object = new Brucetg();


  $object->PrintTest();


  echo $object;
 ?>







  为什么会有序列化和反序列化:




   php允许保存一个对象方便以后使用,这个过程被称为序列化。为什么要有序列化这种机制呢?在传递变量的过程中,有可能遇到变量值要跨脚本文件传递的过程。试想,如果另一个脚本想要调用之前一个脚本的变量,但是前一个脚本已经执行完毕,所有的变量和内容已经释放掉了,我们要如何操作呢?难道要一个脚本不断地循环,等待后面脚本调用?这肯定是不现实的。serialize和unserialize就是用来解决这一问题的。serialize可以将变量转换为字符串并且在转换中可以保存当前变量的值;unserialize则可以将serialize生成的字符串转换为变量。


  // 1.php




   <?php


  class User
  {
  public $name = '';
  public $age = 0;
  public $sex = '';


  public function PrintUser()
  {
  echo 'User '.$this->name.' is ' . $this->age .' years old, sex is '.$this->sex.'.<br/>';
  }
  }


  //创建一个对象
  
  $user = new User();


  $user->name = 'Test';
  $user->age = 20;
  $user->sex = 'male';


  $user->PrintUser();


  echo serialize($user);


  ?>






  

为了使用这个对象,在2.php中用unserialize重建对象。


    //2.php


   <?php


  class User{
  public $age = 0;


  public $name = '';


  public $sex = '';


  public function PrintUser()
  {
  echo 'User ' .$this->name.' is '.$this->age.' years old, sex is '.$this->sex.'. ';
  }
  }


  $user = unserialize('O:4:"User":3:{s:4:"name";s:4:"Test";s:3:"age";i:20;s:3:"sex";s:4:"male";}');


  $user->PrintUser();
  
  ?>







  反序列化漏洞的利用思路:


 
   在反序列化中,我们所能控制的数据就是对象中的各个属性值,所以在PHP的反序列化有一种漏洞利用方法叫做“面向属性编程”,即POP(Property Oriented Programming)。和二进制漏洞中常用的ROP技术类似。在ROP技术中我们往往需要一段初始化gadgets来开始我们整个的利用过程,然后继续调用其他的gadgets。在PHP反序列化漏洞利用技术POP中,对应的初始化gadgets就是__wakeup()或者是__destruct()方法。在最理想的情况下能够实现漏洞利用的点就在这两个函数中,但往往我们需要从这个函数开始,逐步的跟进在这个函数中调用到的所有函数,直到找出可以利用的点为止。以下为跟进其函数调用过程中需要关注的一些很有价值的函数:




   Command Execution:


                   exec()
 
                   passthru()

                   popen()

                   system()




   File Access:


               file_put_contents()


              file_get_contents()


              unlink()




  当然并不只有这些函数才会导致漏洞的产生,比如前几天typecho反序列化漏洞最终利用的是call_user_function(),漏洞分析中也提到了array_map()函数,该函数在传递给它的参数是用户可控时也会导致漏洞的产生。


  POP: 简单来说就是关注整个函数的调用过程中参数的传递情况,找到可利用的点,这和一般的Web漏洞没什么区别,只是可控制的值由直接传递给程序的参数转变为了对象中的值。


  

   反序列化漏洞挖掘:




  PHP的unserialize()函数只能反序列化在当前程序上下文中已经被定义过的类。在传统的PHP中你需要通过使用一大串的include()或者require()来包含所需的类定义文件。于是后来出现了autoloading技术,它可以自动导入需要使用的类。这种技术同时也方便了我们的漏洞利用。因为在我们找到一个反序列化点的时候我们所有使用的类就多了,那么实现漏洞利用的可能性也就更高。


  还有一个东西要提一下,那就是Composer,这是一个php的包管理工具,同时他还能自动导入所依赖库中定义的类,这样一来unserialize()函数也就能使用所有依赖库中的类了,攻击面又增大不少。




原创粉丝点击