Object-oriented foundation of PHP deserialization vulnerability

1. PHP object-oriented foundation

To talk about PHP deserialization, you have to involve object-oriented, because most of the deserialization exploits involve the deserialization of "objects". So you need to understand the object-oriented basics.

Object-oriented is a kind of "object"-centered programming idea, which decomposes the problem to be solved into various "objects". The object is a whole composed of information and the description of information processing. abstract.

1. Basic concepts

  • Objects
    Objects are abstract representations of things. In object-oriented terminology, everything is an object, and an object represents a specific functional operation. We don't need to know how this object implements a certain operation, we only need to know what operations the object can complete.

  • Abstract
    Abstraction ( Abstract) is to ignore the non-essential features in things that have nothing to do with the current goal, and pay more attention to the essential features related to the current goal, so as to find out the commonality of things, and classify the things with commonality into one category to obtain an abstract the concept of.

  • Encapsulation
    Encapsulation ( Encapsulation) refers to combining the properties and behavior of an object into an independent unit, and hiding the internal details of the object as much as possible.

    Generally speaking, encapsulation has two meanings:

    • Combine all the properties and behaviors of the object to form an indivisible independent unit. The property values ​​of the object (except the public property values) can only be read and modified by the behavior of this object;
    • Hide the internal details of the object as much as possible, forming a barrier to the outside world, and the connection with the outside can only be realized through the external interface
  • Inheritance
    Inheritance ( Inheritance) is a hierarchical model that connects classes to classes. Inheritance means that objects of a particular class possess the attributes and behaviors of their general class. Inheritance means "automatic possession", that is, the special class does not need to redefine the properties and behaviors that have been defined in the general class, but automatically and implicitly owns the properties and behaviors of its general class. When this special class is inherited by its lower-level special class, its inherited and self-defined attributes and behaviors are inherited by the next-level special class. Inheritance is thus transitive, embodying the relationship of the particular and the general in nature.

    Parent class: A class is inherited by other classes, which can be called parent class, or base class, super class Subclass
    : A class that integrates other classes is called a subclass, also known as a derived class

The above concepts may be abstract and obscure for beginners. There are many concepts in object orientation, such as class, object, inheritance, polymorphism, etc. The cultivation of object-oriented programming ideas needs to be continuously accumulated in the learning process. For the learning of PHP deserialization vulnerability knowledge, first understand the basic knowledge of "class", "object", "instantiation" and other basic knowledge, and then follow The deepening of relevant knowledge can deepen the object-oriented programming.

2. Classes and Objects

A class is an abstract feature that defines a thing. It encapsulates the form of data and the operations on these data. The interior of a class consists of member variables (attributes) and member functions (methods),

  • Member variable: A variable defined inside the class. The value of the variable is invisible to the outside world, but it can be accessed through member functions. After the class is instantiated as an object, the variable can become an attribute of the object
  • Member functions: Define functions that are associated with a particular object inside a class. Member functions are also known as methods, which are used to perform specific operations, and can access and manipulate attributes of the class, by using keywords functionto define member functions.
// 定义类的语法格式
class class_name
{
    
    
    //类中定义的属性和方法
}
// 定义一个Person类
class Person
{
    
    
    //类中定义的属性和方法
    // 属性
    public $name;        // 姓名
    public $age;         // 年龄
    // 成员函数
    public function tell(){
    
    
        print($this->name."今年".$this->age."岁!");                        
    } 
}

Objects are the result of class instantiation. After defining a class in PHP, you can use newthe keyword to instantiate an object of a class. Its syntax format is as follows:

$object_name = new class_name();
<?php
    class Person
    {
    
    
        public $name;        // 姓名
        public $age;         // 年龄
        // 成员函数
        public function tell(){
    
    
            print($this->name."今年".$this->age."岁!");                        
        } 
    }
    $p = new Person();		  // 创建 Person 类的实例,即对象,名为$p
    $p -> name = "张三";	  // 给对象的 name 属性赋值
    $p -> age = 18;			  //
    echo $p -> tell();		  // 张三今年18岁!
?>

3. Introduction to common modifiers of classes

  • private
    privateIndicates private privatefields and methods modified by keywords 只能在类的内部使用, which cannot be called by the instantiated object of the class, nor can it be called by the subclass of the class.
  • protected
    protected means protected, 只能在类本身和子类中使用.
  • public
    publicA field or method modified by a keyword indicates that it is public, that is, the field and method can be accessed through the object name anywhere in PHP. At the same time, publicit is also the default modifier for fields and methods.

4. Constructor and destructor

The constructor is automatically executed when the object of the class is instantiated, where members can be initialized or some special operations can be performed. Corresponding to it is a destructor, which is automatically executed when the instantiated object is destroyed. It is usually used to perform some work to clean up resources, such as freeing memory, deleting variables and closing database connections, etc.

1), constructor

In PHP, the name of the constructor is named uniformly __construct(). That is to say, if a function named is declared in a class __construct(), the function will be treated as a constructor and executed when an object instance is created. The syntax format of the constructor is as follows:

function __construct([参数列表]){
    
    
    // 构造函数体
}
<?php
    class Student{
    
    
        private $name;
        private $age;
        function __construct()
        {
    
    
            $this->name = "zhangsan";
            $this->age = 18;
        }
        public function toString(){
    
    
            echo $this->name."今年".$this->age."岁。";
        }
    }
    $s = new Student();		// 实例化对象的时候,自动去调用构造函数__construct,对属性进行初始化
    $s->toString();
?>

2), destructor

The destructor also has a uniform naming, ie __destruct(). Destructors allow arbitrary code to be executed after an object is used to clean up memory. By default, only the memory occupied by the object properties is released and the resources related to the object are deleted. Unlike constructors, destructors do not accept any parameters.

<?php
    class Counter{
    
    
        private static $count = 0;
        function __construct()
        {
    
    
            self::$count++;
        } 
        function __destruct()
        {
    
    
            self::$count--;
        }
        function getCount()
        {
    
    
            return self::$count;
        }
    }
    $num1 = new Counter();				// 实例化对象,触发构造方法,count的值+1,变为1
    echo $num1->getCount()."<br>";		// 1
    $num2 = new Counter();				// 实例化对象,count的值+1,变为2
    echo $num2->getCount()."<br>";      // 2
    $num2 = NULL;                   	// 销毁对象$num2,count的值-1,变为1
    echo $num1->getCount()."<br>";      // 1
?>

2. Basic knowledge of serialization

1. The role of serialization

Serialization is the process of converting an object's state information (attributes) into a string that can be stored or transmitted. Convert objects or arrays to strings that can be stored/transmitted

Use functions in php serialize()to serialize objects or arrays and return a string containing byte streams to represent

2. Expression after serialization

// 所有序列化之后的格式第一位都是数据类型的英文字母的简写
<?php
	echo serialize(null);            // N;
	echo serialize(666);             // i:666;
	echo serialize(66.6);            // d:66.599999999999994315658113919198513031005859375;
	echo serialize(true);            // b:1;
	echo serialize(false);           // b:0;
	echo serialize("benben");        // s:6(长度):"benben";(如果字符串中有双引号“"”,序列化之后,被双引号闭合,正因为有前面字符串的长度,所以才可以区分哪个是字符串内容中的双引号)
	echo serialize(array('benben','dazhuang','laoliu'))        //  a:3:{i:0;s:6:"benben";i:1;s:8:"dazhuang";i:2;s:6:"laoliu";}
?>

Common data types after serialization:

  • a: arrayarray type
  • b: booleanBoolean
  • d: doublefloat
  • i: integerInteger type
  • r: objec referenceobject reference
  • s: non-escaped binary stringunescaped binary string
  • S: escaped binary stringescaped binary string
  • C: custom objectcustom object
  • O: classobject
  • N: nullempty
  • R: pointer referencepointer reference
  • U: unicode string Unicodeencoded string

3. Object serialization

  • "Class" cannot be serialized, "object" can be serialized; only member variables are serialized, member functions are not serialized

    <?php
    class test{
          
          
        public $pub='benben';
        function jineng(){
          
          
            echo $this->pub;
        }
    }
    $a = new test();
    echo serialize($a);        // O:4:"test":1:{s:3:"pub";s:6:"benben";}
    ?>
    

    Explanation after "object" serialization:

    • OObject
    • 4: class name length
    • "test": Indicates the class name
    • 1: number of member attributes
    • s: The type of the variable name pub is a string
    • 3: the length of the variable name
    • "pub":variable name
    • s: The type of the variable value is a string
    • 6: the length of the variable value
    • "benben":variable
  • After privatethe private property decorated with the modifier is serialized, add " %00类名%00" before the private property name (here %00is the URL encoding of the null character ( Null), which is actually invisible).

    <?php
    	class test{
          
          
        private $pub='benben';
        function jineng(){
          
          
            echo $this->pub;
        }
    	}
    	$a = new test();
    	echo serialize($a);               // O:4:"test":1:{s:9:"testpub";s:6:"benben";}
    	echo urlencode(serialize($a));    // O%3A4%3A%22test%22%3A1%3A%7Bs%3A9%3A%22%00test%00pub%22%3Bs%3A6%3A%22benben%22%3B%7D
    ?>
    

    When the attribute $pubis privatemodified by modifiers, after the "object" is serialized, the difference from the previous example is: , s:9:"testpub"if you use URL encoding to output, you will see that testthere will be before and after %00, so the length of the member attribute name is9

  • After protectedserialization, the member attributes decorated with modifiers will add " %00*%00" before the variable name (here %00is the URL encoding of the null character ( Null), which is actually invisible).

    <?php
    class test{
          
          
        protected $pub='benben';
        function jineng(){
          
          
            echo $this->pub;
        }
    }
    $a = new test();
    echo serialize($a);        // O:4:"test":1:{s:6:"*pub";s:6:"benben";}
    ?>
    
  • When we serialize an object, the value of the member variable of the object is another object after instantiation, after serialization, the value of the variable is the serialized value of another object.

    <?php
    class test1{
          
          
        var $pub='benben';
        function jineng(){
          
          
            echo $this->pub;
        }
    }
    class test2{
          
          
        var $ben;
        function __construct(){
          
          
            $this->ben=new test1();
        }
    }
    $a = new test2();
    echo serialize($a);           // O:5:"test2":1:{s:3:"ben";O:5:"test1":1:{s:3:"pub";s:6:"benben";}}
    ?>
    

3. Deserialization

1. The role of deserialization

Restore the serialized string to an instantiated object
insert image description here

2. The characteristics of deserialization

  • The content after deserialization is an object

    <?php
    class test {
          
          
        public  $a = 'benben';
        protected  $b = 666;
        private  $c = false;
        public function displayVar() {
          
          
            echo $this->a;
        }
    }
    $d = serialize(new test());
    echo $d;                     // "对象"序列化:O:4:"test":3:{s:1:"a";s:6:"benben";s:4:"*b";i:666;s:7:"testc";b:0;}
    var_dump(unserialize($d));   // object(test)#1 (3) {  ["a"]=>  string(6) "benben"  ["b":protected]=>  int(666)  ["c":"test":private]=>  bool(false)}
    ?>
    
  • The value in the object generated by deserialization is provided by the value in deserialization; it has nothing to do with the predefined value of the original class

    <?php
    class test {
          
          
        public  $a = 'benben';
        protected  $b = 666;
        private  $c = false;
        public function displayVar() {
          
          
            echo $this->a;
        }
    }
    // 将序列化之后的字符串中变量a的值,改为dazhang,将私有属性c的值改为true
    $d = 'O:4:"test":3:{s:1:"a";s:8:"dazhuang";s:4:"%00*%00b";i:666;s:7:"%00test%00c";b:1;}';
    $d = urldecode($d);
    // 反序列化之后对象的值与原有类中的值无关,而只与反序列化中的值有关
    var_dump(unserialize($d));  // object(test)#1 (3) {  ["a"]=>  string(8) "dazhuang"  ["b":protected]=>  int(666)  ["c":"test":private]=>  bool(true)}
    ?>
    
  • Deserialization does not trigger the member methods of the class (except the magic method); it needs to call the method before it can be triggered (the original class must exist)

    <?php
    class test {
          
          
        public  $a = 'benben';
        protected  $b = 666;
        private  $c = false;
        public function displayVar() {
          
          
            echo $this->a;
        }
    }
    $d = 'O:4:"test":3:{s:1:"a";s:8:"dazhuang";s:4:"%00*%00b";i:666;s:7:"%00test%00c";b:1;}';
    $e = urldecode($d);
    $f = unserialize($e);
    $f->displayVar();        // 反序列化后,生成对象,调用displayVar(),输出:dazhuang
    ?>
    

The above knowledge summary comes from Orange Technology’s php deserialization vulnerability learning , combined with my own understanding.

Guess you like

Origin blog.csdn.net/weixin_45954730/article/details/131852957