美文网首页
[MRCTF2020]Ezpop

[MRCTF2020]Ezpop

作者: 天水麒麟儿_ | 来源:发表于2020-06-12 08:59 被阅读0次

今日重拾web,在BUUCTF上选个简单的题目[MRCTF2020]Ezpop做一下,

题目非常直接,

 整个思路还是比较好想的,在找思路之前我们需要先明确先验知识,

1.

参考链接

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

__construct()//当一个对象创建时被调用

__destruct() //当一个对象销毁时被调用

__toString() //当一个对象被当作一个字符串使用

__sleep()//在对象在被序列化之前运行

__wakeup()//将在反序列化之后立即被调用(通过序列化对象元素个数不符来绕过)

__get()//获得一个类的成员变量时调用

__set()//设置一个类的成员变量时调用

__invoke()//调用函数的方式调用一个对象时的回应方法

__call()//当调用一个对象中的不能用的方法的时候就会执行这个函数

此处用到的主要是__toString(),__wakeup(),__get(),__invoke(),

2.

参考链接

https://blog.csdn.net/nzjdsds/article/details/104011576

类中,private变量与protected变量序列化后,变量名会有些异常,

private变量经反序列化后为\x00 + 类名 + \x00 + 变量名;

protected变量经反序列化后为,\x00 + * + \x00 + 变量名;

3.

参考链接

忘记是自己总结的还是从哪里抄的了

类成员由属性和方法构成,类属性存在于数据段,类方法存在于代码段,对于一个类来说,类的方法不占用类的空间,占空间的只有类的属性。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。因此,序列化操作只是保存对象(不是类)的变量,不保存对象的方法,其实反序列化的主要危害在于我们可以控制对象的变量来改变程序执行流程从而达到我们最终的目的。我们无法控制对象的方法来调用,因此我们这里只能去找一些可以自动调用的一些魔术方法。

举例如下,

捋一下思路,题目中说了flag在flag.php里。

我们首先注意到Modifier类的append()方法中有include,结合题意,此处应该是用来包含flag.php的,当然此处我们需要使用php://filter来读取编码后的,否则直接include相当于执行而已,看不到结果,

可以想象,Modifier类是触发漏洞的最后一环,我们再看看,可以看到其还有一个魔术方法__invoke(),可以在作为函数被调用时触发,

正常情况下,我们只能进行这么一步反序列化操作,应该是无法直接调用Modifier的__invoke()的,

这就要求我们去找能调用__invoke()的地方,

顺着这个线索,我们找到Test类的__get()魔术方法,

这里Test类的__construct函数是假的,不用管,关注__get()函数 ,其中直接将$this->p作为函数来调用,正好对应Modifier的__invoke(),不妨将$this->p 设为一个构造好的Modifier对象,

如果这个题目比较友好的话(确实比较友好),这里应该是倒数第二环,接下来我们需要找触发Test的__get()方法的地方,

要想到的一点是只能通过源代码里已有的代码来触发,__get()在获得一个类的成员变量时调用,而且一定是$xxx -> 构造好的Test对象 ->xxx的这样一个形式(因为无法直接$test->xxx),

由此找到Show类的__toString()魔术方法,

 __toString()在一个对象被当作一个字符串使用时调用,第一反应就是反序列化之后,echo,这样就直接触发了,但我们上面提到了,这里只给了一步反序列化,没有echo、print之类的操作,还需要继续寻找,

本题的最后一个触发点隐藏的比较深,在Show类的__wakeup()方法里,

 老实讲,我看到__wakeup()第一反应(包括第二反应第三反应)是去绕过,而不是利用,但这个题的__wakeup()过滤的是gopher|http一类的内容,对我们构造的pop链应该来讲没有影响,毕竟我们只需要找到能一处把Show类的对象当成字符串的地方使用就可以,这里的本意可能是防止我们通过Show类直接读取(猜的)?

这里的preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source),会将$this->source进行字符串的正则匹配,所以这里自然有一个隐式的“类型转换”,学过C语言,我们知道$this->source是不能指向对象自身的,但可以指向同类的另一个对象,差不多就是这个意思:$show1->source = $show。

此时$show1->source进行正则匹配,就会将$show当成字符串,进而触发$show的__toString(),只要让$show的str对象是$test,$test的p为一个Modifier对象,就和上面我们所想连起来了,

 (不知道有没有画错)

简陋exp:

<?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 = "php://filter/read=convert.base64-encode/resource=flag.php";

}

class Show{

public $source;

public $str;

}

class Test{

public $p;

}

$modifier = new Modifier();

$test = new Test();

$test -> p = $modifier;

$show = new Show();

$show->str = $test;

$show1 = new Show();

$show1->source = $show;

echo urlencode(serialize($show1));

这里有一个细节,就是echo

urlencode(serialize($show1)),因为protected变量经反序列化后,变量名为,\x00 + * + \x00 +

变量名,直接echo payload将其打印到网页上的话是看不到\00的,复制为参数达不到效果,

此处一种做法是直接将最终的payload拼接到url里访问靶机,另一种方法是输出url编码后的payload,GET请求的参数在服务端会自动解码一次,故也可以达到效果。

成功,

相关文章

  • [MRCTF2020]Ezpop

    今日重拾web,在BUUCTF上选个简单的题目[MRCTF2020]Ezpop做一下, 题目非常直接, 整个思路还...

  • [EIS 2019]EzPOP

    接着上一篇简单的pop题目,做一下[EIS 2019]EzPOP, 总的来看代码量确实是大了,相对应的一些琐碎的东...

网友评论

      本文标题:[MRCTF2020]Ezpop

      本文链接:https://www.haomeiwen.com/subject/nxawtktx.html