序列化
搞懂反序列化漏洞的前提,先搞懂什么是序列化:
序列化说通俗点就是把一个对象变成可以传输的字符串。
序列化实际是为了传输的方便,以整个对象为单位进行传输, 而序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。如果了解底层的同学可以知道,类中的方法本就不在类中。
而在php中,使用函数serialize()来返回一个包含字节流的字符串来表示
比如:
class S{
public $test="sd";
}
$s=new S(); //创建一个对象
serialize($s); //把这个对象进行序列化
序列化的结果是:
O:1:"S":1:{s:4:"test";s:2:"sd";}
代表的含义依次是:
- O:代表object
- 1:代表对象名字长度为一个字符
- S:对象的名称
- 1:代表对象里面有一个变量
- s:数据类型(string)
- 4:变量名称的长度
- test:变量名称
- s:数据类型
- 2:变量值的长度
- sd:变量值
顺便说一下PHP 对不同类型的数据用不同的字母进行标示
- a - array
- b - boolean
- d - double
- i - integer
- o - common object
- r - reference
- s - string
- C - custom object
- O - class
- N - null
- R - pointer reference
- U - unicode string
反序列化
就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。
使用unserialize()函数
$u=unserialize("O:1:"S":1:{s:4:"test";s:2:"sd";}");
echo $u->test; //得到的结果为sd
反序列化安全
序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题
有哪些php常见的魔法函数:
- __construct() 当一个对象创建时被调用
- __destruct() 当一个对象销毁前被调用
- __sleep() 在对象被序列化前被调用
- __wakeup 将在反序列化之后立即被调用
- __toString 当一个对象被当做字符串使用时被调用
- __get(),__set() 当调用或设置一个类及其父类方法中未定义的属性时
- __invoke() 调用函数的方式调用一个对象时的回应方法
- __call 和 __callStatic前者是调用类不存在的方法时执行,而后者是调用类不存在的静态方式方法时执行。
有面向对象编程基础的同学应该很多都能看懂,比如__contruct():c 中的构造函数,java中的构造器;__destruct():c 中的析构函数.java的自动回收机制:finalize()
靶场实战
了解了序列化、反序列化、php魔法函数,先来看一个靶场,尝试反序列化构造payload
payload
看一下题目,已知反序列化入口
先随便输点东西看看
这里既然是反序列化接口,就需要输入我们序列化的字符串,比如插入我们刚刚的payload
O:1:"S":1:{s:4:"test";s:2:"sd";}
不仅于此,构造xss
O:1:"S":1:{s:4:"test";s:28:"<script>alert('sd')</script>";}