序列化
序列化是指将数据结构或对象转换为一串字节流的过程。使其可以在存储、传输或缓存时进行持久化。
反序列化
反序列化是指将序列化后的数据进行解码和还原,恢复为原始的数据结构或对象的过程。反序列化是序列化的逆过程。
在 PHP 中,使用 serialize() 函数可以将数据结构或对象进行序列化,得到一个表示序列化后数据的字符串。通过 unserialize() 函数可以将这个字符串进行反序列化,将其还原为原始的数据。
序列化格式
O:长度:“类名”:变量数:{变量类型:变量名长度:“变量名字”;变量的值;}
i | 表示整数类型(integer) |
d | 表示浮点数类型(double) |
b | 表示布尔类型(boolean) |
a | 表示数组类型(array) |
O | 表示对象类型(object) |
N | 表示 NULL 类型(null) |
private属性序列化属性名称格式是0x00类名0x00成员名。
0x00代表16进制编码的空格,%00代表url编码的空格
private $age=18; %00people%00age
protected属性序列化属性名称格式是0x000x2A0x00成员名
0x00代表16进制编码的空格,%00代表url编码的空格,0x2A代表16进制编码的 * 号
protected $height='156cm'; %00*%00height
数组和关联数组的序列化
$arr=array('lili','girl');
$arr[8]='18';
echo serialize($arr);
a:3:{i:0;s:4:"lili";i:1;s:4:"girl";i:8;s:2:"18";}
注意! 3是数组的有效值数量,不是最后一个下标,和对象序列化不一样。i:0代表下标为0
$person = array(
'name' => 'xiaoming',
'age' => 30,
'city' => 'beijing'
);
a:3:{s:4:"name";s:8:"xiaoming";s:3:"age";i:30;s:4:"city";s:7:"beijing";}
echo、print_r、var_dump输出信息
$lili=new people();
$lili->name='lili';
$lili->age=18;
$a=serialize($lili);
echo $a;
print_r(unserialize($a));
var_dump(unserialize($a));
O:6:"people":2:{s:4:"name";s:4:“oooo";s:3:"age";i:18;}
people Object ( [name] => lili [age] => 18 )
object(people)#2 (2) { ["name"]=> string(4) "lili" ["age"]=> int(18) }
不同方式输出的序列化信息也不同。
#2 :php的对象标识符,表示该对象在 PHP 程序执行期间的唯一标识符。每创建一个新的对象时,PHP 会自动为该对象分配一个唯一的标识符,以便在程序中引用和识别该对象。它的值本身没有特殊意义,只是为了唯一标识一个对象而存在。
简单序列化漏洞
class people{
public $name='lili';
private $age=18;
protected $height='160cm';
}
$lili=new people();
echo serialize($lili);
此时序列化的结果为:
O:6:"people":3:{s:4:"name";s:4:"oooo";s:11:"%00people%00age";i:18;s:9:"%00*%00height";s:5:"160cm";}
我们将这个序列化后的字符串修改:
//注意:age和height前的权限修饰符 %00
$a='O:6:"people":3:{s:4:"name";s:4:"lili";s:11:"%00people%00age";i:20;s:9:"%00*%00height";s:5:"150cm";}';
var_dump(unserialize(urldecode($a))); //因%00(0x00)代表空字符,直接写不出来,对其url解码再传入
此时反序列化输出的结果为:
object(people)#2 (3) { ["name"]=> string(4) "lili" ["age":"people":private]=> int(20) ["height":protected]=> string(5) "150cm" }
可以发现age和height属性值被修改,这说明 前一个对象只是为我们提供一个序列化的字符串,反序列化是根据当前传入的字符串。
简单演示
class User {
public $username='lili';
public $isAdmin=0;
}
$userData = $_GET['data'];
$user = unserialize($userData);
if($user->isAdmin===1 && $user->username==='admin'){
echo '欢迎你管理员~';
}
else{
echo '你是一个普通用户!';
}
这个漏洞代码通过get请求传入的参数进行反序列化,我们构造序列化字符串使isAdmin属性值为1并且 username属性值为admin。末尾的 ;} 不要忘记。
O:4:"User":2:{s:8:"username";s:5:"admin";s:7:"isAdmin";i:1;}
传入参数:
?data=O:4:"User":2:{s:8:"username";s:5:"admin";s:7:"isAdmin";i:1;}
网站输出结果:欢迎你管理员~