PHP序列化的时候private和protected变量会引入不可见字符\x00,输出和复制的时候可能会遗失这些信息,导致反序列化的时候出错。

private属性序列化的时候会引入两个\x00,注意这两个\x00就是ascii码为0的字符。这个字符显示和输出可能看不到,甚至导致截断,如图,url编码后就可以看得很清楚了:

同理,protected属性会引入\x00*\x00

此时,为了更加方便进行反序列化Payload的传输与显示,我们可以在序列化内容中用大写S表示字符串,此时这个字符串就支持将后面的字符串用16进制表示。比如s:5:"A<null_byte>B<cr><lf>";̀ -> S:5:"A\00B\09\0D";

phpggc这个工具就支持这个选项:https://github.com/ambionics/phpggc#ascii-strings

此时生成的Payload更加可读,也方便传输。

今年网鼎杯出了一道PHP反序列化的题,需要绕过限制,限制是不允许传入一些控制字符等:

其中一种思路就是使用这种技巧,在序列化内容中用大写S表示字符串,此时这个字符串就支持将后面的字符串用16进制表示。在测试绕过一些WAF的时候可以用到了这个方法。

其他的解法可参考: