这篇文章写的是 php-bugs-72663 问题。问题起源于小组成员出的一道 CTF 题目,当中考察到这个 bug ,这里做个简单记录。

这个 bug 的原理是:当反序列化字符串中,表示属性个数的值大于真实属性个数时,会跳过 __wakeup 函数的执行。我们看如下案例:

1

题目很简单,反序列化的字符串用户可控,但是反序列化后会先执行 __wakeup 函数,该函数会将 $this->file 变量设成固定值,导致我们无法进行任意文件读取。现在我们利用这个 bug 尝试绕过 __wakeup 函数。可以看到 ReadFile 类的属性中,只有一个 $file 私有属性,那么正常反序列化出来应该是下面这个样子:

2

而如果我们将数值个数值 1 改成大于 1 的任何数字,在反序列化时就不会调用 __wakeup 函数。观察上图,我们还会发现反序列化字符串中存在 \x00 字符,这个其实是类的私有属性反序列化后的格式,protected 属性也有自己的反序列化格式,不妨来看看:

3

回到题目上,我们最终可以用如下 payload ,实现绕过 __wakeup 函数读取任意文件:

4