php反序列化漏洞

1.  首先讲什么是序列化和反序列化。

序列化是将对象的状态信息转换为可以存储或传输的形式的过程,在序列化期间,对象将当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象状态,重新创建该对象。

简单的来讲:

序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。

php中的序列化函数:

php中的反序列化函数:

2.  反序列化漏洞

反序列化漏洞是基于序列化和反序列化的操作,在反序列化——unserialize()时存在用户可控参数,而反序列化会自动调用一些魔术方法,如果魔术方法内存在一些敏感操作例如eval()函数,而且参数是通过反序列化产生的,那么用户就可以通过改变参数来执行敏感操作,这就是反序列化漏洞。

漏洞成因

在程序执行前,serialize() 函数会首先检查是否存在一个魔术方法 __sleep.如果存在,__sleep()方法会先被调用, 然后才执行串行化(序列化)操作。这个功能可以用于清理对象,并返回一个包含对象中所有变量名称的数组。如果该方法不返回任何内容,则NULL被序列化,导致 一个E_NOTICE错误。

与之相反,unserialize()会检查是否存在一个__wakeup方法。如果存在,则会先调用 __wakeup方法,预先准备对象数据。但是这个wakeup()是可以被绕过的

漏洞的根源在于unserialize()函数的参数可控。如果反序列化对象中存在魔术方法,而且魔术方法中的代码有能够被我们控制,漏洞就这样产生了,根据不同的代码可以导致各种攻击,如代码注入、SQL注入、目录遍历等等。

__wakeup 触发于 unserilize() 调用之前, 当反序列化时的字符串所对应的对象的数目被修改,__wake 的函数就不会被调用. 并且不会重建为对象, 但是会触发其他的魔术方法比如__destruct
————————————————
以上参考自:https://blog.csdn.net/weixin_45844670/article/details/108171963

所谓的魔术方法:

__construct() 当创建对象时触发,一般用于初始化对象,对变量赋初值
__sleep() 使用serialize()时自动触发 
__wakeup() 使用unserialize()时自动触发
__destruct() 当一个对象被销毁时触发
__toString() 当一个类被当成字符串使用时触发
__invoke() 当尝试以调用函数的方式调用一个对象时触发
__call() 在对象上下文中调用不可访问的方法时触发 
__callStatic() 在静态上下文中调用不可访问的方法时触发 
__get() 用于从不可访问的属性读取数据
__set() 用于将数据写入不可访问的属性
__isset() 在不可访问的属性上调用isset()或empty()触发
__unset() 在不可访问的属性上使用unset()时触发

一个实例:

<?php   

class test{

    var $id = 'Baize';

    function __wakeup(){
        eval($this->id);
    }

}

$test1 = $_GET['string'];

$test2 = unserialize($test1);

?>

这里通过get传参string,并且对string进行反序列化操作,反序列化操作后会首先调用_wakeup()魔术方法。执行eval(),所以如果讲想要执行的代码序列化后传入例如

O:4:"test":1:{s:2:"id";s:10:"phpinfo();"}

即可执行一些未预料的操作。

这里贴一个大佬的文章,里面有更加详细的反序列化漏洞详解

https://xz.aliyun.com/t/9234

原文地址:https://www.cnblogs.com/cmredkulaa/p/14552000.html