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();"}
即可执行一些未预料的操作。
这里贴一个大佬的文章,里面有更加详细的反序列化漏洞详解