前言
总结一下序列化和反序列化的入门知识主要介绍__sleep与__wakeup
简单介绍
1、序列化
将一个对象转换为字符串
2、反序列化
将一个字符串恢复成对象
3、常见魔术方法
__construct: 在创建对象时候初始化对象,一般用于对变量赋初值。
__destruct: 和构造函数相反,当对象所在函数调用完毕后执行。
__toString:当对象被当做一个字符串使用时调用。
__sleep:序列化对象之前就调用此方法(其返回需要一个数组)
__wakeup:反序列化恢复对象之前调用该方法
__call:当调用对象中不存在的方法会自动调用该方法。
__get:在调用私有属性的时候会自动执行
__isset():在不可访问的属性上调用isset()或empty()触发
__unset():在不可访问的属性上使用unset()时触发
PHP序列化
php序列化的函数为serialize()
例:
<?php
class peak{
public $name = "1stPeak";
protected $sex = "man";
private $age = "18";
}
$a = new peak;
echo serialize($a);
?>
序列化后的结果为:
O:4:"peak":3:{s:4:"name";s:7:"1stPeak";s:6:"*sex";s:3:"man";s:9:"peakage";s:2:"18";}
解释一下上面所代表的的是什么:
O
:表示对象(object)
7
:对象名称的长度
peak
:对象名称
3
:表示对象里属性的个数,这里的属性为warn
s
:属性名类型
4
:属性名长度
name
:属性的名称
s
:属性值的类型
7
:属性值的长度
1stPeak
:属性值
s
:属性名类型
6
:属性名长度
*sex
:属性的名称
s
:属性值的类型
3
:属性值的长度
man
:属性值
s
:属性名类型
9
:属性名长度
peakage
:属性的名称
s
:属性值的类型
2
:属性值的长度
18
:属性值
注:这个属性的值可有可无,没有赋值,那么序列化后就没有该值
这里可能不理解序列化后的sex和age,这个是由访问控制修饰符导致的(访问修饰符的不同,序列化后的属性名的长度和属性名会有所不同)
例:
public(公有)
protected(受保护)
private(私有)
各访问修饰符序列化后的区别:
public:属性被序列化的时候属性名还是原来的属性名,没有任何改变
protected:属性被序列化的时候属性名会变成%00*%00属性名,长度跟随属性名长度而改变
private:属性被序列化的时候属性名会变成%00类名%00属性名,长度跟随属性名长度而改变
注:这里的%00也就是表示空字符,在url中用%00表示,在hex中表示\x00
Tip:%00和\x00也就是我们常说的00截断
Tip:
serialize()函数有个规定,在序列化对象时,如果对象存在有__sleep魔术方法,那么,在序列化对象时__sleep魔术方法会优先调用,然后再继续执行序列化操作
例:
<?php
class peak{
public $name = "1stPeak";
public $sex = "man";
public $age = "18";
public function __sleep(){
return array('age');
}
}
$a = new peak;
echo serialize($a);
?>
结果:O:4:"peak":1:{s:3:"age";s:2:"18";}
如上所示:只要序列化时执行了__sleep,就只会序列化__sleep中的属性
PHP反序列化
反序列化,顾名思义,就是将序列化后的字符串还原
unserialize()也有和serialize()相对应的魔术方法__wakeup,反序列化时,会优先检查是否存在__wakeup魔术方法,如果存在,就会优先调用__wakeup方法
例如:
<?php
class Demo
{
public $flag = 'flag{aaaaaa}';
public function __wakeup()
{
$this->flag = "bbbbbb";
echo $this->flag;
}
}
$a = new Demo();
$b = serialize($a);
echo $b."\n";
echo unserialize($b);
?>
输出:
O:4:"Demo":1:{s:4:"flag";s:12:"flag{aaaaaa}";}
bbbbbb
一般做CTF题目时绕过的方法就是:先序列化字符串,然后使序列化后字符串中属性的个数大于真实对象中属性的个数,即可绕过,例如XCTF的那道题:
题目为:
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=
我们对其进行序列化:
<?php
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
}
$a = new xctf;
echo serialize($a);
?>
结果为:O:4:"xctf":1:{s:4:"flag";s:3:"111";}
,然后将序列化后字符串中属性的个数由1改为2,大于真实属性个数1,即可绕过__wakeup
注:修改s(属性类型)或属性名长度也可绕过执行__wakeup,因为你构造的属性和真实的属性不符;但修改属性值是不会绕过__wakeup的,所以综述:只有改变属性个数、属性类型、属性名才可以绕过!
总结:这只是简单的php序列化和反序列化中__sleep和__wakeup简单的入门,后面的还有很多其它知识点,学完了再写blog记录一下。
参考:
https://www.freebuf.com/articles/web/221213.html
https://www.cnblogs.com/tr1ple/p/11156279.html