序列化格式

不同数据类型的缩写:
a - array
b - boolean
d - double
i - integer
o - common object
r - reference
s - string
C - custom object
O - class
N - null
R - pointer reference
U - unicode string
不同数据类型的数据格式:
String : s:size:value;
Integer : i:value;
Boolean : b:value;(保存1或0)
Null : N;
Array : a:size:{key definition;value definition;(repeated per element)}
Object : O:strlen(object name):object name:object size:{s:strlen(property name):property name:property definition;(repeated per property)}

实例

class hpdoger{
public $a = 'nice to meet u';
}

序列化得到的结果
O:7:"hpdoger":1:{s:1:"a";s:6:"nice to meet u";}

属性类型带来的结果变化

当属性为public时,序列化结果中的属性名没有变化
当属性为private时,属性名会附加类名以及空格
image.png
此处类名以及属性名前均有一个空格
当属性为protected时,会附加附加一个被空格包裹的*
image.png

绕过魔法函数的反序列化漏洞

魔法函数sleep() 和 wakeup()

当序列化对象时,PHP 将试图在序列动作之前调用该对象的成员函数 __sleep()。serialize()会检查是否存在一个魔术方法 __sleep().如果存在,__sleep()方法会先被调用,然后才执行序列化操作。这个功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组这样就允许对象在被序列化之前做任何清除操作。类似的,当使用 unserialize() 恢复对象时, 将调用__wakeup() 成员函数。
unserialize() 对单一的已序列化的变量进行操作,将其转换回 PHP 的值
unserialize() 执行时会检查是否存在一个 wakeup() 方法。如果存在,则会先调用 wakeup 方法,预先准备对象需要的资源。wakeup()经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。sleep()则相反,是用在序列化一个对象时被调用
PHP版本
PHP5 < 5.6.25
PHP7 < 7.0.10
序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行
利用这点可以执行payload

序列化漏洞常见的魔法函数

construct():当一个类被创建时自动调用
destruct():当一个类被销毁时自动调用
invoke():当把一个类当作函数使用时自动调用
tostring():当把一个类当作字符串使用时自动调用
wakeup():当调用unserialize()函数时自动调用
sleep():当调用serialize()函数时自动调用
__call():当要调用的方法不存在或权限不足时自动调用
7表示类名长度,1表示类中有一个属性

Session序列化机制

当session_start()被调用或者php.ini中session.auto_start为1时,PHP内部调用会话管理器,访问用户session被序列化以后,存储到指定目录(默认为/tmp)。

PHP处理器的三种序列化方式

php_binary:键名的长度对应的ASCII字符+键名+经过serialize() 函数反序列处理的值
php:键名+竖线+经过serialize()函数反序列处理的值
php_serialize:serialize()函数反序列处理数组方式
不同的序列化处理方式会导致漏洞产生
在使用php方式序列化的数据在使用php_serialize的页面反序列化时会
把竖线后的数据当做值来处理