当在php中创建了一个对象后,可以通过 serialize() 函数把这个对象转变成一个字符串,保存对象的值方便之后的传递与使用。
image.png与 serialize() 对应的就是反序列化函数 unserialize() ,它可以将一个字符串转变为相对应的php对象。
image.png其实本质上来说,serialize() 和 unserialize() 在 PHP内部实现上是没有漏洞的,之所以会产生反序列化漏洞是因为应用程序在处理对象、魔术函数以及序列化相关问题的时候导致的。
当传给 unserialize() 的参数可控时,那么用户就可以注入精心构造的 payload。当进行反序列化的时候就有可能会触发对象中的一些魔术方法,造成意想不到的危害。
这里简单说一下魔术方法。"Magic Function" 是 php 中一类特殊的方法。这里我们着重关注以下几个:
- __construct():当对象创建(new)时会自动调用。但在 unserialize() 时是不会自动调用的。(构造函数)
- __destruct():当对象被销毁时会自动调用。(析构函数)
- __wakeup():unserialize() 时会自动调用。
下面结合代码可以更好的理解:
image.png image.png下面来看一下很简单的存在反序列化漏洞的例子:
image.png由于 unserialize() 的参数可控,我们就,且chybeta类的对象在被销毁时,会执行 $this->test->action 方法,它的 $this->test 我们也可以控制。所以我们可以构造如下代码来生成经过序列化后的 poc:
image.png于是,我们就成功构造了一句话木马:
image.png知道了漏洞的原理和利用方式之后,下面就来实战一把。
访问靶场地址:
image.png填点东西,提交表单:
image.png点击超链接“Check Code”,页面上打印出了 index.php 的源码:
image.png来分析下代码。首先看HTML的部分,其中会通过php的foreach循环来遍历$todos遍历的内容,并以无序列表的形式显示在页面上。
然后看一下表单处理的部分,首先获取textarea提交的文本,存储到数组变量 $todos 中,然后对 $todos 进行序列化并存入变量 $m中,
再对 $m进行md5加密,加密后的内容存到变量 $h中,最后将 $h和$m拼接起来作为 Cookie todos的值,然后重定向到当前页面。
接着,获取Cookie中 todos的值,分别取出$h和 $m的值,比较两者是否相等,如果相等,则将$m的值进行反序列化,并将结果存到变量$todos,最终在下面的foreach循环中显示在页面上。
再往上看,有一个叫 readme的类,该类中重写了魔术方法 __toString(),如果用echo 打印该类的对象,则内容就是Readme.txt 和 成员变量 $this->source 的内容的拼接。
image.png而且可以看到,成员变量可以控制。因此可以按照上面代码中对Cookie的处理逻辑,构造好包含着能反序列化为 readme 对象的字符串,然后放到Cookie中去访问http://120.203.13.75:8123/uns/index.php ,就能讲 flag.php的内容打印到页面上。
于是,在本地构造php程序,sez.php 如下:
image.png访问结果如下:
image.png再次访问 http://120.203.13.75:8123/uns/index.php, 然后利用Firefox的Cookie Quick Manager 插件,修改Cookie中todos的值为上面得到的结果:
image.png保存设置后的值,然后刷新页面,flag.php的内容就显示在了页面上:
image.png
网友评论