__construct()
// 触发条件,构造函数,当构造一个对象时调用。
// 对象创建时销毁

__destruct()
// 触发条件,析构函数,对象销毁时被调用。
// 序列化时会销毁一次,对象销毁时执行

__sleep()
// 在对象被序列化之前运行,序列化输出前运行,但不影响序列化内容

__wakeup()
// 在对象被反序列化之后被调用
// 其功能是为反序列化的对象初始化变量

__unserialize()
// 触发条件,7.4版本以上,反序列化时触发,且可以绕过__wakeup

__invoke()
// 当对象被调用时执行
// 函数形式调用对象时,触发的方法

__tostring()
// 将一个对象作为字符串操作时自动调用,其返回值即为输出。

__call()
// 调用无法调用的函数时,转为调用该方法。

__get()
// 当非公有变量、未定义的属性或没有权限访问的属性被访问时该方法会被调用

__set()
// 给私有变量和未定义的属性赋值时调用该方法
// 写法为set($a,$b);,其执行方式为object->$a = $b; $a是赋值的目标,$b是赋值的来源

首先要从php的魔法函数说起 在特定操作时 会去调用出发其中的某个魔法函数

其中 serialize 是将对象的序列化函数 是把对象按照特定的规定顺序保存为一个字符串去使用
反序列化就是把这个字符串再次转化为一个对象
反序列化后生成的对象的行为逻辑,要遵循对其进行反序列化的命名空间的内部构造(类、方法、魔术方法),对于不存在的逻辑,是不能进行操作的。因此解题要基于服务器端的脚本包含的类。

反序列化
反序列化字符串是严格顺序解析的,从其每个变量名和值都要携带相应的长度可以看出,

__wakeup()原理:将在序列化之后立即被调用。
漏洞原理:当反序列化字符串中,表示属性个数的值大于其真实值,则跳过__wakeup()执行。

用途:当Wakeup方法当中包含的逻辑会影响到我们构造的POC执行的时候,需要对其绕过.

真实的序列化:O:4:”xctf”:1:{s:4:”flag”;s:3:”111″;}
伪造的序列化:O:4:”xctf”:2:{s:4:”flag”;s:3:”111″;}

调整属性数后不能成功的构建一个对象,以此绕过exit(),但是会正常调用__destruct()函数。

private属性序列化的时候格式是 %00类名%00成员名  如testname  (test->类名name->成员名)

protected属性序列化的时候格式是 %00*%00成员名    如*name   (name->成员名)

一般为了保证他们的正常输出,转为URL编码
urlencode(serialize(new test()))

序列化只序列化属性,不序列化方法,因此反序列化的时候要保证在当前的作用域环境下有该类存在,类属性就是唯一的攻击突破口