序列化
百度百科上关于序列化的定义是,
将对象的状态信息转换为可以存储或传输的形式的过程。在序列化
期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对
象的状态,重新创建该对象。
简单的说,序列化就是把一个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台、安
全的进行通信。
PHP中的序列化与反序列化
PHP反序列化漏洞也叫PHP对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一
旦利用成功就会造成非常危险的后果。漏洞的形成的根本原因是程序没有对用户输入的反序列化字
符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell等一系列不可控的
后果。反序列化漏洞并不是PHP特有,也存在于Java、Python等语言之中,但其原理基本相通。
PHP中的序列化与反序列化,基本都是围绕serialize()和unserialize()
两个函数展开的。在介绍这两个函数之前,我们来看一个简单的例子。
复习
class 类
obj 对象
对象(object)
对象就是具有一定功能和特征的事物.凡是能帮我们实现某种需求的事物的都是对象
a) 女朋友是对象.
b) 每一个学员都是讲师的教学对象.
类(class)
具有相同特征和功能的对象的抽象 就是类
很多个学生对象归纳为一个学生类.
很多个商品对象归纳为一个商品类.
对象和类之间的关系
对象参考类的结构,被创建出来.并且属性保存具体的数据.
它是具体的.
类是对所属对象的共有特性的描述, 可以说这是一个类型, 一个结构
它是抽象的
对象的抽象就是类
类的实体化(实例化)就是对象
对象和类的对比
马良 马良画的图 从画里走出来的事物
工程设计师 设计图 由设计图造出来的事物
程序员 类 对象
// 定义一个学生类
class Student
{
// 成员属性(类中的变量)
public $name;
public $sex;
public $age;
// 成员方法(类中的函数)
public function say()
{
echo '我爱写作业!<br>';
}
}
/*
a)成员属性
i.必须要加修饰符来修饰 public
ii.成员属性的初始值可有可无
iii.成员属性初始值的注意事项
iv.成员属性可以使用常量进行赋初始值
b)成员方法
i.成员方法可以不加修饰符修饰 public
ii.成员方法中 参数可有可无 代码体可有可无 方法的返回值也是可有可无的
iii.在成员方法(函数) 没有使用return手动返回一个值的话 它的默认返回值就是null
*/
// 根据类的结构,创建对象(术语:实例化对象)
$stu1 = new Student;
/*
1.new关键字不能省略
2.小括号可有可无
3.对象的实例化 可以放在类声明之前 对象的实例化还可以放到类的内部
*/
// 对象的成员访问
// 成员属性赋值
$stu1 -> name = 'kpkp';
$stu1 -> sex = '男';
$stu1 -> age = 18;
echo $stu1 -> name,'<br>';
$stu1 -> say();
/*
注意:
1.如果属性名是固定的话 前面不能加$
2.成员访问符的两侧可以有空白, 成员访问符的中间不能有空白
3.成员属性和成员方法的位置不是绝对固定的 一般来说都是将成员属性放置在上面,成员方法放置在下面.
4.在类中不能出现除了成员属性和成员方法之外的代码
*/
让对象表达自己($this)
php
class Student
{
public $name;
public function say()
{
echo '我叫'.$this->name;
}
}
$stu1 = new Student;
$stu1 -> name = '王建双';
$stu1 -> say(); // 我叫王建双
/*
1 $this代表当前这个对象,谁调用当前这个方法,那么$this就代表(等于)哪个对象
2.$this只能在类的内部使用 并且只能放置在成员方法中
3.$this不仅能访问成员属性 还能在成员方法中调用成员方法
json 格式化字符串
*简单的例子
我们可以用json格式数据的编码与解码,来理解序列化与反序列化的过程。虽然json
数据与反序列化漏洞没有什么关系,但是这个例子会帮助我们理解。
测试代码如下
echo 不能输出数值
json 格式编码 就可以echo 输入了
我们定义一个数组,数组属于抽象的数据结构,
为了方便跨平台传输数据,可以将其进行json
编码。json格式的数据是以键值对的形式出现的。结果如下
*序列化Demo
序列化会将一个抽象的对象转换为字符串。
我们可以写一个Dm0来说明序列化的过程,首先创建一个类,代码如下
类名是Stu,该类中有四个变量(关于变量的性质,我们这里不讨论。接下来,我们可以将这个类实例化
,也就是创建一个对象,并给对象中变量赋值。代码如下
<?php
class Student
{
// 成员属性(类中的变量)
public $name;
public $sex;
public $age;
// 成员方法(类中的函数)
public function say()
{
echo '我爱写作业!<br>';
}
}
$a = new Student();
echo serialize($a);
了解反序列化,必先了解其魔法函数
- __sleep() //在对象被序列化之前运行
- __wakeup() //将在反序列化之后立即调用(当反序列化时变量个数与实际不符是会绕过)
- __construct() //当对象被创建时,会触发进行初始化
- __destruct() //对象被销毁时触发
- __toString()://当一个对象被当作字符串使用时 触发
- __call() //在对象上下文中调用不可访问的方法时触发
- __callStatic() //在静态上下文中调用不可访问的方法时触发
- __get() //获得一个类的成员变量时调用,用于从不可访问的属性读取数据
- __set() //用于将数据写入不可访问的属性
- __isset() //在不可访问的属性上调用isset()或empty()触发
- __unset() //在不可访问的属性上使用unset()时触发
- __toString() //把类当作字符串使用时触发
- __invoke() //当脚本尝试将对象调用为函数时触发
强调一下
构造函数 __construct
析构函数 __destruct
__call 调用类中不存在或者无法调用的非静态方法
__callStatic 调用类中不存在或者无法调用的静态方法
__invoke 将类所衍生的对象当作是函数进行调用
__get 当访问对象中一个不存在或者无法访问的属性时
__set 当设置对象中一个不存在或者无法设置的属性时
__wakeup 当使用Unserialize等反序列化函数生成对象时
__sleep 当使用serialize等序列化函数将对象转为字符串时 返回一个数组 该数组中绝对对那些程序属性进行序列化
__toString 当将类所衍生的对象当作字符串处理时
然后了解其属性
序列化对象:
private变量会被序列化为:\x00类名\x00变量名
protected变量会被序列化为: \x00*\x00变量名
public变量会被序列化为:变量名
php反序列化漏洞,又叫php对象注入漏洞。
序列化与反序列化
php中有两个函数serialize() 和unserialize()。
serialize()
当在php中创建了一个对象后,可以通过serialize()把这个对象转变成一个字符串,保存对象的值方便之后的传递与使用。测试代码如下;
<?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),假如你给serialize()传入的是一个数组,那它会变成字母a。7表示对象的名称有7个字符。"chybeta"表示对象的名称。1表示有一个值。{s:4:“test”;s:3:“123”;}中,s表示字符串,4表示该字符串的长度,"test"为字符串的名称,之后的类似。
unserialize()
与 serialize() 对应的,unserialize()可以从已存储的表示中创建PHP的值,单就本次所关心的环境而言,可以从序列化后的结果中恢复对象(object)。
<?php
class chybeta{
var $test = '123';
}
$class2 = 'O:7:"chybeta":1:{s:4:"test";s:3:"123";}'; print_r($class2);
echo "</br>";
$class2_unser = unserialize($class2);
print_r($class2_ser);
?>
这里提醒一下,当使用 unserialize() 恢复对象时, 将调用 __wakeup() 成员函数。
反序列化漏洞
由前面可以看出,当传给 unserialize() 的参数可控时,我们可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数
利用构造函数等
php中有一类特殊的方法叫“Magic function”,魔术方法 这里我们着重关注一下几个:
构造函数__construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。
析构函数__destruct():当对象被销毁时会自动调用。
__wakeup() :如前所提,unserialize()时会自动调用。
测试如下:
<?php
class chybeta{
var $test = '123';
function __wakeup(){
echo "__wakeup";
echo "</br>";
}
function __construct(){
echo "__construct"