OkayCMS 2.3.4 反序列化漏洞(CVE-2019-16885)
2019-12-16 10:10:02 Author: xz.aliyun.com(查看原文) 阅读量:195 收藏

漏洞概述

OKAYCMS是一款来自俄罗斯的功能强大的在线商店管理系统。OKAYCMS易于定制的多种语言自适应模板可用于销售任何商品:从服装、建筑材料、手机到音乐曲目,视频课程,有声读物和海报等。

在OKAYCMS v2.3.4中存在着一处反序列化漏洞。未经身份验证的攻击者可以通过此处漏洞进行进一步的攻击利用。

漏洞细节

漏洞位置存在于view/ProductsView.php与api/Comparison.php代码中,可以通过Cookie传入序列化代码进行利用

首先来看下第一处,即位于view/ProductsView.php 516行处代码

可见位于上图代码中存在一处unserialize方法,此处unserialize位于ProductsView.php中fetch方法中,此处代码将cookie中传入的price_filter参数未经过滤,直接反序列化,从而产生了漏洞

更加严重的是:由于ProductsView.php并未对fetch方法进行身份校验,未经身份验证的用户可以将恶意的cookie传递到此处执行

我们构造如下get请求,将恶意字符串”test”通过cookie中price_filter参数传递给反序列化漏洞点

后台断点处,可见unserialize函数成功接收到我们在cookie中传递的字符串”test”

再来看下api/Comparison.php文件

api/Comparison.php文件中多次利用unserialize函数将cookie中传入的comparison参数进行反序列化操作,具体如下:

用于选择比较产品清单的get_comparison接口处

用于将产品添加到比较列表的add_item接口处

用于从比较列表中删除项目的delete_item接口处

以上这些存在反序列化漏洞的接口,同样也是不需要身份验证就可以访问

在ajax/comparison.php中,get_comparison、add_item与delete_item是可以直接被调用而不需要身份验证的,代码如下:

上图代码可见,只要通过get请求中的action参数即可控制所要使用的接口,但是程序并未进行身份校验

我们以get_comparison接口举例

我们构造如下get请求,将恶意字符串”test”通过cookie中comparison参数传递给反序列化漏洞点

可见我们将构造的cookie中的comparison参数值“test”成功传递给了unserialize函数

此时,反序列化利用点已经找到了,但是仍需要利用链才能进行利用

任意文件删除利用链

经过分析可以发现,OKAYCMS是一款使用Smarty模板引擎进行开发的cms。因此可以使用Smarty中的利用链进行利用

在Smarty模板引擎中存在smarty_internal_cacheresource_file.php文件,该文件定义了一个名为Smarty_Internal_CacheResource_File的类。在Smarty_Internal_CacheResource_File类中存在一处releaseLock方法,如下图

可见上图releaseLock方法中,存在一处unlink方法,利用该方法,可以进行文件删除操作

注意看下图这里两处红框

方法releaseLock接收两个参数,分别是Smarty $smarty与 Smarty_Template_Cached $cached

Smarty 与 Smarty_Template_Cached分别是Smarty模板引擎中两个类的名称

Smarty类

Smarty_Template_Cached类

这里类名+参数名的用法是什么呢?

在php中,这种用法叫做类型约束,详细的解释如下:

PHP5以及以上版本可以使用类型约束。函数的参数可以指定必须为对象(在函数原型里面指定类的名字),接口,数组(PHP5.1 起)或者 callable(PHP 5.4 起)。不过如果使用 NULL作为参数的默认值,那么在调用函数的时候依然可以使用 NULL 作为实参。

如果一个类或接口指定了类型约束,则其所有的子类或实现也都如此。类型约束不能用于标量类型如 int 或 string,Traits 也不允许。

下面举个例子说明一下类型约束用法:

有名为MyClass与OtherClass的两个类,MyClass类中的test方法接收OtherClass类的一个对象作为参数,并打印出该对象的var属性值

当传入$myclass->test值为字符串hello时

报出上图错误:传递给MyClass :: test()的参数1必须是OtherClass的实例

当传入$myclass->test值为$otherclass即OtherClass类的实例时

程序打印出Hello World

在弄清楚php类型约束概念之后,回到正文:

可见如果我们想构造反序列化利用链,使用这个releaseLock方法进行任意文件删除,那传入releaseLock方法中的两个参数必须为Smarty类与Smarty_Template_Cached类的实例

在了解到releaseLock方法如何使用后,我们继续查找releaseLock方法是否在某个类的魔术方法中被调用,以便在反序列化操作时被调用

经过搜索发现,在smarty_internal_template.php文件中定义了Smarty_Internal_Template类,该类的destruct方法见下图

在Smarty_Internal_Template类destruct方法中,调用了releaseLock方法

在Smarty_Internal_Template类destruct方法中,可见只要满足了if分支,就可以执行releaseLock方法

destruct方法中的releaseLock方法接收的两个参数$this->smarty与$this->cached,根据上文分析,$this->smarty与$this->cached需要为Smarty类与Smarty_Template_Cached类的实例,因此我们需要进行如下构造:

为了顺利进入if分支,还需要使得

$this->smarty->cache_locking / isset($this->cached) / $this->cached->is_locked三者为真

$this->cached已经设置为Smarty_Template_Cached类的实例,因此$this->cached已经为真

$this->smarty是Smarty类的实例,要使得$this->smarty->cache_locking为真可见下图设置

$this->cached是Smarty_Template_Cached类的实例,要使得$this->cached->is_locked为真可见下图设置

在成功进入if分支后,需要控制$this->cached->lock_id,这个变量用来进行文件删除

$this->cached是Smarty_Template_Cached类的实例,要设置$this->cached->lock_id的值可见下图设置

最后完整的利用链如下

当将构造好的序列化字符串通过cookie传入系统后,在反序列化时,将会将指定路径的文件进行删除,从而造成了任意文件删除漏洞


文章来源: http://xz.aliyun.com/t/6929
如有侵权请联系:admin#unsafe.sh