[2023蓝帽杯] lovePHP
题目
<?php
class Saferman{
public $check = True;
public function __destruct(){
if($this->check === True){
file($_GET['secret']);
}
}
public function __wakeup(){
$this->check=False;
echo $this->check;
}
}
if(isset($_GET['my_secret.flag'])){
unserialize($_GET['my_secret.flag']);
}else{
highlight_file(__FILE__);
}
解题流程
PHP变量解析
由于PHP的机制,直接传入参数my_secret.flag,其中.这种特殊字符会被转化为_。经过测试输入my[secret.flag只有第一个[会被转化,而之后的.会保留。

反序列化wakeup绕过
所用的方法是C代替OC:8:"Saferman":0:{},虽然这种方法无法添加属性的内容,不过$check 初始就是True,所以也无所无所谓就是。
php://filter 无回显读文件
太复杂了就看个大概。
关键点:
- 长字符串使PHP报错:
convert.iconv.L1.UCS-4LE过滤器会将字符串长度扩大4倍,对一个非空字符串多次应用这个过滤器,它会快速达到 PHP 的内存限制,并引发一个 500 错误。 - dechunk 过滤器:
dechunk过滤器在处理没有新行的字符串时,会根据字符串的开始字符进行操作。如果字符串以A-Fa-f0-9中的任何字符开头,它会清空整个字符串;否则,它会保持字符串不变。
开头不在此范围,正常输出

开头字符为a,输出空


结合这两个特点可以根据服务器响应的状态码判断字符具体的值,整个工作有三步:
- 使用
convert.base64-encode转化flag,使字符串只有a-zA-Z0-9 convert.iconv.CSUNICODE.UCS-2BE反转字符串每两个字符,convert.iconv.UCS-4LE.10646-1:1993反转字符串每四个字符。用这两个过滤器来将每一位反转到字符串的开头逐步猜解。- 然后就是判断每一位具体的值,使用
string.rot13和各种过滤器组合,以dechunk的A-Fa-f0-9这个判断区间移动字符,根据状态码判断出具体的字符。