php反序列化漏洞

序列化与反序列化
php中有两个函数serialize() 和unserialize()。

一、serialize()
当在php中创建了一个对象后,可以通过serialize()把这个对象转变成一个字符串,保存对象的值方便之后的传递与使用。测试代码如下;



这里的O代表存储的是对象(object),假如你给serialize()传入的是一个数组,那它会变成字母a。7表示对象的名称有7个字符。"chybeta"表示对象的名称。1表示有一个值。{s:4:"test";s:3:"123";}中,s表示字符串,4表示该字符串的长度,"test"为字符串的名称,之后的类似。

二、unserialize()
与 serialize() 对应的,unserialize()可以从已存储的表示中创建PHP的值,单就本次所关心的环境而言,可以从序列化后的结果中恢复对象(object)。当使用 unserialize() 恢复对象时, 将调用 __wakeup() 成员函数。

反序列化漏洞
由前面可以看出,当传给 unserialize() 的参数可控时,我们可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数。
一、利用构造函数
php中有一类特殊的方法叫“Magic function”

1.构造函数__construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。
2.析构函数__destruct():当对象被销毁时会自动调用。
3.__wakeup() :unserialize()时会自动调用。


二、利用场景
__wakeup() 或__destruct()
由前可以看到,unserialize()后会导致__wakeup() 或__destruct()的直接调用,中间无需其他过程。因此最理想的情况就是一些漏洞/危害代码在__wakeup() 或__destruct()中,从而当我们控制序列化字符串时可以去直接触发它们。这里针对 __wakeup() 场景做个实验。

基本的思路是,本地搭建好环境,通过 serialize() 得到我们要的序列化字符串,之后再传进去。通过源代码知,把对象中的test值赋为 “”,再调用unserialize()时会通过__wakeup()把test的写入到shell.php中。

三、利用普通成员方法

前面谈到的利用都是基于“自动调用”的magic function。但当漏洞/危险代码存在类的普通方法中,就不能指望通过“自动调用”来达到目的了。这时的利用方法,寻找相同的函数名,把敏感函数和类联系在一起。

利用过程,构造序列化


传给index.php的test参数,利用成功:

posted @ 2020-11-30 15:33  paidx0  阅读(77)  评论(0编辑  收藏  举报