|
稍稍记录一下,简单的反序列化。
何为序列化?
序列化对象 - 在会话中存放对象 ¶
所有 php 里面的值都可以使用函数 serialize() 来返回一个包含字节流的字符串来表示。unserialize() 函数能够重新把字符串变回 php 原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
为了能够unserialize()一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。 如果要想在另外一个文件中解序列化一个对象,这个对象的类必须在解序列化之前定义,可以通过包含一个定义该类的文件或使用函数spl_autoload_register()来实现。
序列化字符串格式:变量类型:变量长度:变量内容
例如序列化对象字符串:
变量类型:类名长度:类名:属性数量:{属性类型:属性名长度:属性名;属性值类型:属性值长度:属性值内容}
PHP 中的魔术方法(Magic methods)
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), |
这里我们着重关注几个:
__construct()
:当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。__destruct()
:当对象被销毁时会自动调用。__sleep()
:serialize() 会检查类中是否存在一个魔术方法 __sleep()。若存在,该方法会先被调用,再执行序列化操作__wakeup()
:unserialize() 会检查是否存在一个 __wakeup() 方法。若存在,则先调用 __wakeup 方法,预先准备对象需要的资源。__toString()
:用于一个类被当成字符串时应怎样回应。例如echo $obj;
应该显示些什么。
PHP 有个 Bug,该漏洞可以概括为:
当序列化字符串中表示对象个数的值大于真实的属性个数时会跳过 __wakeup 函数的执行
rua=O:4:"Time":3:{ |
注意上面的 3 ,是属性数量,本来2个就够了。
16进制 0x
开头在强制转换中出现问题,导致转换成0
payload 如下:
rua=O:4:%22Time%22:4:{s:4:%22time%22;s:10:%220x4c06f350%22;s:8:%22password%22;a:2:{i:0;s:1:%22a%22;i:1;s:1:%22b%22;}} |
还有一种办法:科学计数法绕过 sleep()
rua=O:4:"Time":3:{s:4:"time";s:5:"1.3e9"; |