序列化对象 - 在会话中存放对象
所有php里面的值都可以使用函数serialize()
来返回一个包含字节流的字符串来表示。unserialize()
函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
为了能够unserialize()
一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。 如果要想在另外一个文件中解序列化一个对象,这个对象的类必须在解序列化之前定义,可以通过包含一个定义该类的文件或使用函数spl_autoload_register()
来实现。
上面是官方文档中对序列化的解释。简单来说,序列化就是将一个类中的所有变量保存在一个字符串中。那么反序列化当然就是把这个字符串转化为类啦~(前提是这个类已经定义了: D)
一个小例子
网上随便找的例子:
<?php
class chybeta{
var $test = '123';
}
$class1 = new chybeta;
$class1_ser = serialize($class1);
print_r($class1_ser);
?>
上面的源码输出如下:
O:7:"chybeta":1:{s:4:"test";s:3:"123";}
下面就逐个解释这些都是什么意思吧。
O
代表储存的是一个对象(object)7
表示对象的名称有7个字符。"chybeta"
表示对象的名称。1
表示有一个值。{s:4:"test";s:3:"123";}
中:s
表示字符串4
表示该字符串的长度"test"
为字符串的名称,之后的类似。
这里提示一下:序列化的时候会调用
__sleep()
这个函数,反序列化的时候会调用__wakeup()
这个函数。(如果有的话)
<?php
class test
{
private $flag = "flag{233}";
public $a = "aaa";
static $b = "bbb";
}
$test = new test;
$data = serialize($test);
echo $data;
?>
O:4:"test":2:{s:10:"testflag";s:9:"flag{233}";s:1:"a";s:3:"aaa";}
可以看到 flag
成员的名称长度为 10 。转换成文件可以看到 test
两边有两个空字符。
补充
在一次内部赛的时候碰到的知识点:
漏洞有效的PHP版本未知。我本地环境用的是PHP5.4 。PHP在反序列化对象的时候,会先检测 O:
,然后再检测是否有 +
。如果是 +
的话就忽略 +
继续检测后面的数字。这就导致了可以绕过一些 waf 如 /O:\d/
之类的正则。
参考资料:http://sec-redclub.com/archives/962/