CTF-PHP deserialization vulnerability 1-basic knowledge

Author: Eason_LYC
Pessimists predict failure, ten words nine out of ten. Optimists perform miracles, one at a time.
The value of a person lies in what he has. You can learn nothing, but you can’t have everything!
Technical field: WEB security, network attack and defense
Focus on WEB security, network attack and defense. The knowledge points of my column are comprehensive and detailed, the logic is clear, combined with actual combat, so that you can get twice the result with half the effort on the way of learning and avoid detours!
Personal Community: Elysium - Technology First
The pursuit of technology supremacy, this is our ideal paradise ~ (follow me to join the community)

In this column, the CTF Basics Introductory Series打破 has been in the past CTF crash or on-topic topic mode. adopted 系统讲解基础知识+入门题目练习+真题讲解方式. Let readers who are new to CTF truly grasp the various types of knowledge points in CTF, and lay a solid foundation for subsequent self-study or quick preparation for the competition~

At present, ctf competition generally chooses php as the preferred language. If the reader does not understand the basic grammar of php, please log on to the relevant website and learn the basic grammar by yourself. Generally, you can master the basics in 5-7 days.

1. What is PHP serialization and deserialization

1.1 Basic concepts

  • PHP serialization is converting a PHP object into a string for transfer and storage between different applications.
  • Deserialization is converting a serialized string back to a PHP object. Attackers can trigger code execution by constructing malicious serialized strings, which is the essence of PHP deserialization vulnerabilities.
  • Official documentation of PHP serialization function: https://www.php.net/manual/en/function.serialize.php
  • Official documentation of PHP deserialization function: https://www.php.net/manual/en/function.unserialize.php

1.2 Basic knowledge

Serialization is the process of converting PHP objects into strings that can be stored or transmitted. The serialized string can be saved to a file or transferred over the network to another computer, where it can be deserialized back to the original object when needed.

The basic principle of serialization is to convert a PHP object into a set of strings containing the object's properties and variables. The serialized string can be deserialized to the original object, thus recreating the object.

PHP serialization can be done using PHP's built-in serialize() function. For example, the following code serializes a PHP object to a string:

$object = new MyClass();
$string = serialize($object);

In the above code, $object is an instance of the MyClass class, and the serialize() function serializes it into a string, which is stored in the $string variable.

Deserialization can be done using PHP's built-in unserialize() function. For example, the following code deserializes a serialized string into a PHP object:

$string = 'O:7:"MyClass":2:{s:3:"foo";s:3:"bar";s:3:"baz";i:123;}';
$object = unserialize($string);

In the above code, $string is a serialized string, and the unserialize() function deserializes it into an instance of the MyClass class, which is stored in the $object variable.

It should be noted that PHP serialization can only serialize PHP objects, not other types of data such as resources and closures. In addition, since the serialized string contains the private properties and methods of the object, it is necessary to ensure that the class definition of the object has been loaded into memory during deserialization.

To put it simply, it is a process of converting a PHP object into a string and saving it (serialization), which is convenient for transmission to the remote end, and then restored to the object at the remote end (deserialization).

1.3 The harm of PHP deserialization vulnerability

The PHP deserialization vulnerability can lead to remote code execution, and the attacker can inject arbitrary code into the application by constructing a malicious serialized string, so as to achieve the purpose of controlling the server.

Simply put, it is to construct a malicious string (serialization), so that when the object is restored remotely (deserialization), the malicious object is restored and executed.

1.4 Defense measures against PHP deserialization vulnerabilities

There are many ways to defend against PHP deserialization vulnerabilities, the most important of which is to filter and validate user input. Also, you can use PHP's built-in serialization functions for serialization and deserialization instead of using third-party libraries.

2. Explanation of knowledge points

First, let's look at a complete PHP serialization and deserialization code

Codes are often given directly in CTF, and codes need to be analyzed to compile malicious strings

Please add a picture description

2.1 Access modifiers for classes

In the figure above, a class Tree is defined, and the first three lines in the class respectively appear public, private, and protected. What do they mean? Let's introduce it in detail~

  • Inside the class: refers to the inside of the class definition, that is, inside the braces { } after the class name.
  • Outside the class: refers to the external content of the class definition, that is, all places outside the braces {} after the class name.
  • The access control of class members is divided into: internal access (private private). Internal access (protected) and all access (public).

2.1.1 public public

A public property or function that can be accessed inside or outside the class
public $name='BMW'
public function XXX{}

2.1.2 protected protected

Protected properties or functions can only be accessed internally between the class and its subclasses and parent classes. If you want to access it externally, you need to set the reference method.
protected $color='blue'

2.1.3 private private

Private properties or functions can only be accessed inside the current class. If you want to access them externally, you need to set a reference method.

For example, the last three echo calls in the above figure, as can be seen in the figure below, public can be called normally, and the other two generate errors

insert image description here

2.2. Related functions and important knowledge points

2.2.1 Basic definition

The purpose of serialization is to facilitate the transmission and storage of objects.

  • Serialization

Refers to converting an instantiated object from an instance to a short serialized string, which is convenient for saving the object, and can store the serialized bytes in a database or text.

  • deserialization

It is to parse the serialized string through deserialization when needed, get the saved object, and call it directly without re-instantiation of a class

In PHP applications, serialization and deserialization are generally used as caches, such as session caches, cookies, etc.

2.2.2 Related functions and technical knowledge points

serialize(mixed $value)

The parameters are objects, arrays, strings, etc. that need to be serialized. The return value type is a string, that is, a serialized string.

unserialize(string $str): mixed

The parameter type is a string, that is, a serialized string. The return value is the deserialized object, array, string, etc.

<?php
class Car{
    
    
	public $name='BMW';
	protected $color='blue';
	private $size='large';
	private $price;

	function __construct(){
    
    
		echo '序列化时调用构造方法<br>';
	}

	function __destruct(){
    
    
		echo '反序列化时调用析构函数<br>';
	}

	function show(){
    
    
		echo $this->name.'<br>';
		echo $this->color.'<br>';
		echo $this->size.'<br>';
		echo 'price:"'.$this->price.'"<br>';
	}
}

$myCar = new Car();
$o = serialize($myCar);
print_r($o);
print_r("\n");
print_r(urlencode($o));
print_r("\n");

$un_o = unserialize(urlencode($o));
print_r($un_o);

?>
  
  
// 序列化时调用构造方法
// O:3:"Car":4:{s:4:"name";s:3:"BMW";s:8:"*color";s:4:"blue";s:9:"Carsize";s:5:"large";s:10:"Carprice";N;}
// O%3A3%3A%22Car%22%3A4%3A%7Bs%3A4%3A%22name%22%3Bs%3A3%3A%22BMW%22%3Bs%3A8%3A%22%00%2A%00color%22%3Bs%3A4%3A%22blue%22%3Bs%3A9%3A%22%00Car%00size%22%3Bs%3A5%3A%22large%22%3Bs%3A10%3A%22%00Car%00price%22%3BN%3B%7D

  
// 反序列化时调用析构函数

This code defines a private property named Car的类, which contains public properties $name, protected properties $color, private properties $size, and undefined initial values $price, and 构造函数__construct()and 析构函数__destruct()a public method show()for outputting the value of the property.

In the code, an instance of the Car class is first created $myCar, serialized into a string $o, and then printed out $oand the URL-encoded form of $o.

$o=O:3:"Car":4:{
    
    s:4:"name";s:3:"BMW";s:8:"*color";s:4:"blue";s:9:"Carsize";s:5:"large";s:10:"Carprice";N;}
urlencode($o) = O%3A3%3A%22Car%22%3A4%3A%7Bs%3A4%3A%22name%22%3Bs%3A3%3A%22BMW%22%3Bs%3A8%3A%22%00%2A%00color%22%3Bs%3A4%3A%22blue%22%3Bs%3A9%3A%22%00Car%00size%22%3Bs%3A5%3A%22large%22%3Bs%3A10%3A%22%00Car%00price%22%3BN%3B%7D

Next, deserialize the URL-encoded string $o into a new object $un_o, and print out $un_o.

During the output process, the constructor __construct() is called, the constructor is called when the output is serialized, and the destructor __destruct() is called when deserialized, and the destructor is called when the output is deserialized. When the show() method is called, only public properties $nameand protected properties $colorare output, and $sizethe values ​​of private properties cannot be output.

PHP序列化字符串的格式如下:
对象类型:长度:“类名”:类中变量的个数:{类型:长度:“值”;类型:长度:“值”;......}

The length here refers to the length of the string o represents an object, a represents an array, s represents a character, and i represents a number

2.2.3 [Technique] urlencode serialization result

  • %00 is a null character, occupying 1 bit. Normal browsers will not display it, but it will be displayed under urlencode
  • private will appear after serialization %00*%00(%00*%00color)
  • protected appears after serialization %00类名%00变量名(%00Car%00size)

In order to prevent the browser from not displaying empty fields, resulting in unsuccessful deserialization, use url encoding when using serialization
$o = urlencode(serialize($myCar))
insert image description here

2.2.4 [Technique] Serialization references R types to bypass comparison

During serialization, the reference (pointer) state of variables can be saved by R type value.

insert image description here

The above meaning is: the input value refers to the result of the correct value. keep key[correct] = key[input]

2.2.5 Features of PHP deserialization

When PHP serializes and saves the state of class objects, 只保存其中的变量和类名等it does not save the structure of the class at the time of serialization (the method is not saved). When deserializing, it is actually bringing the variables stored in the serialized string into the class found in the current context to re-instantiate the object.

3. Commonly used magic methods in PHP

3.1 Summary of magic functions

In object-oriented programming, PHP provides a series of magic methods, which provide a lot of convenience for programming, and their role in PHP is very important. Magic methods in PHP usually start with __ (two underscores), and do not need to be called explicitly but are called automatically under certain conditions. The constructor described above __construct()is called when the object is instantiated, and the destructor is __destruct()called automatically when the object is destroyed. Commonly used magic methods are as follows:

__construct()  // 构造函数,在实例化对象时调用
__destruct()   // 析构函数,在销毁对象时调用
__call(string $function_name, array $arguments)  // 在对象中调用一个不可访问或不存在的方法时被调用
__callStatic() // 用静态方式中调用一个不可访问方法时调用
__get($name)   // 获取对象不存在的属性或无法访问的属性时调用.$name表示要获取的属性名
__set($name, $value) // 设置对象不存在的属性或无法访问的属性时调用.$name表示要设置的属性名,$value表示要设置的值
__isset()     // 当对不可访问属性调用isset()或empty()时调用
__unset()     // 当对不可访问属性调用unset()时被调用
__sleep()     // 执行serialize()时,先会调用这个函数
__wakeup()    // 执行unserialize()时,先会调用这个函数
__toString()  // 类被当成字符串时的回应方法  echo $obj;
__invoke()    // 以调用函数的方式调用一个对象时的回应方法  $person();
__set_state() // 调用var_export()导出类时,此静态方法会被调用
__clone()     // 当对象复制完成时调用
__autoload()  // 尝试加载未定义的类
__debugInfo() // 打印所需调试信息

The methods that will be called by default when deserializing are:

  • __destruct()
  • __wakeup()

Magic function introduction Recommended article:
Sixteen magic methods of PHP Detailed introduction to
PHP magic methods/functions

3.2 Examples of using magic functions

The following piece of code may not be clear to beginners, but it actually has a very high gold content. In the follow-up questions, this table needs to be checked repeatedly~

<?php
# 设置⼀个类A
class A{
    
    
 private $name = "AS1def";
 function __construct()
 {
    
    
 echo "__construct() call\n";
 }
 function __destruct()
 {
    
    
 echo "\n__destruct() call\n";
 }
 function __toString()
 {
    
    
 return "__toString() call\n";
 }
 function __sleep()
 {
    
    
 echo "__sleep() call\n";
 return array("name");
 }
 function __wakeup()
 {
    
    
 echo "__wakeup() call\n";
 }
 function __get($a)
 {
    
    
 echo "__get() call\n";
 return $this->name;
 }
 function __set($property, $value)
 {
    
     echo "\n__set() call\n";
 $this->$property = $value;
 }
 function __invoke()
 {
    
    
 echo "__invoke() call\n";
 }
}
//调⽤ __construct()
$a = new A();
//调⽤ __toSting()
echo $a;
//调⽤ __sleep()
$b = serialize($a);
echo $b;
//调⽤ __wakeup()
$c = unserialize($b);
echo $c;
//不存在这个abcd属性,调⽤ __get()
echo $a->abcd;
//name是私有变量,不允许修改,调⽤ __set()
$a->name = "pro";
echo $a->name;
//将对象作为函数,调⽤ __invoke()
$a();
//程序结束,调⽤ __destruct() (会调⽤两次__destruct,因为中间有⼀次反序列化)

The output is as follows:

__construct() call
__toString() call
__sleep() call
O:1:"A":1:{
    
    s:7:"Aname";s:6:"AS1def";}__wakeup() call
__toString() call
__get() call
AS1def
__set() call
__get() call
pro__invoke() call

__destruct() call

__destruct() call

以上就是PHP反序列化的基础知识,下一篇文章就在这些基础知识上,开始题目的练习~

Guess you like

Origin blog.csdn.net/eason612/article/details/130050983