反序列化漏洞
序列化
百度百科
序列化就是将对象的状态信息转化为可以存储或者传输的形式的过程。在序列化期间,对象可以将当前状态写入到临时或者持久性存储区。之后可以通过存储区来读取或者反序列化对象的状态,重新创建对象。
那么其中的对象是什么?
这里的对象肯定不是男女朋友那种“对象”。我们可以从自身出发,我们知道这个世界上存在着各种不同种类的动物,猫科类、鱼类、猿类、犬类等,我们当然就是人类。每种动物又都拥有着许许多多的“属性”和“方法”。
“属性”是什么?拿你自己来说就是,身高、体重、腰围、有没有口臭等。
“方法”是什么?就是自己会做的事情啊,睡觉、干饭就是。
那么了解了这些,对象究竟是什么?就是一个个具体的人了,你我都是能看这篇博客的人类,但不同的是我们两一个叫张三,一个叫王五;我一米八,你一米五;我有哥哥,你没有。。。。
这就是两个不同的对象了嘛。我们在拥有着人类共有的属性和方法的同时,也会有自己不同的方法,那么这就牵扯到了类的继承,这里不多赘述。
知道了对象,那么我们再看这段话。
序列化是什么?
拿现实里那就是将这一条时间线上的你的所有信息完完整整的刻录下来的这个过程。
可以存储或者传输的形式我想到那就是一串串的代码,当然这里的序列化可以传输的形式就是可以作为字节顺序流发送和接收。
在序列化期间,对象可以将当前状态写入到临时或者持久性存储区。之后可以通过存储区来读取,重新创建对象。
那么再来读这句话,瞬间就能感觉到序列化的强大。存储对象的所有信息,那么只要存储区没事儿,好家伙理论上不死。。
咱存储区一读,满血复活。
序列化和反序列化的目的
使得数据能够持久性的保存,程序之间传输对象也会更加的方便
反序列化
百度百科没有特意收录,但我们通过序列化的含义可以很容易弄清楚。反序列化
那就是将可以存储或者传输的形式转化为对象的状态信息的过程嘛
通过存储区来读取或者反序列化对象的状态,重新创建对象。
反序列化对象的状态,那么如果你反序列化的时候加了些不一样的东西,对象也会跟着改变。这也就是反序列化漏洞的关键所在。
序列化和反序列化存在于基于对象的诸多编程语言之中,本文选举php来作为参考。
php反序列化漏洞
对于php来讲,序列化就是将一个对象转化成字符串。反序列化就是将字符串转化为对象。
涉及的主要函数
- serialize()
用于序列化一个对象或者数组,并返回一个字符串
- unserialize()
将已序列化的字符串变回PHP的值
里面核心的其实就是字符串和变量的相互转换
执行serialize()函数后得到的字符串的含义
当我们拿到一组这样的字符串,我们需要理解每个字母和数字表示的各个不同的含义。
O:5:“human”:3{s:3:“eat”;s:4:“food”;s:4:“age”;s:2:“15”;s:4:“high”;s:3:“180”;}
从左至右的顺序依次说明:
O 指的是对象,序列化的对象。如果是A则表示序列化的是数组
5 指类的名字有5个字符
human 是类名
3 指这个类具有3个属性
s 指这个属性的数据类型是字符串,布尔型就是用b表示
3 指字符串的长度为3
eat 属性名
food 一般为前面属性的值,这里是eat属性的值
后面也是如此,不多赘述。
php反序列化用到的魔术方法
__wakeup() //使用unserialize()时触发
__sleep() //使用serialize时触发
__destruct() //对象被销毁时触发
__construct() //对象被创建的时候自动调用,但在unserialize()时是不会自动调用的
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当脚本尝试将对象调用为函数时触发
php序列化和反序列化漏洞的原理
如果一个PHP代码中使用了unserialize函数去调用某一个类,该类会自动执行一些自定义的魔法函数
如__wakeup函数,如果该函数中执行的操作是我们可以注入数据的,那么很可能会造成注入攻击
我们依旧拿之前的字符串作为例子
O:5:"human":3{s:3:"eat";s:4:"food";s:4:"age";s:2:"15";s:4:"high";s:3:"180";}
魔法方法只要满足某些特定的条件就会自动调用。也就是说我们需要看看human这个类中有没有自定义的一些魔法函数,然后在魔法函数中查找是否存在某些操作可以让我们注入数据。
比方说存在一个自定义__destruct()魔法函数:
<?php
highlight_file(_FILE_);
class human
{
public $eat='food';
public $age='15';
public $high='180';
function __destruct() {
eval($this->high);
}
}
unserialize($_GET['a']);
?>
我们尝试传参,将high变量的值改成phpinfo()
a=O:5:"human":3:{s:3:"eat";s:4:"food";s:3:"age";s:2:"15";s:4:"high";s:10:"phpinfo();";}
成功爆出php版本信息
工具链
有些类包含这些用于反序列化魔术方法,用于发动更复杂的攻击,涉及到多种方法的调用,这就是“工具链”。
往往一两个魔术方法的调用不会涉及到反序列化漏洞,但是一系列魔术方法的调用和协同可能会使攻击者能够获取到参数传递从而反序列化重新创建对象达到攻击的目的。
防御方案
我们所能做的就是不要将用户的输入或者是用户可控的参数放入反序列化的操作中。