xe小于1.1.5 preauth rce

XE全名xpress engine,是根据LGPL许可的韩国开发的CMS软件,自2009年开始发布,至今一共被下载了2192249次以上。xe可以开发网页、博客等服务,韩国国内多数购物网站、社区网站都是用XE制作的。

1.漏洞分析:

该rce漏洞主要分为3个步骤,目录创建,文件写入,模版包含rce。

首先我们分析最后rce的点,触发rce的请求为:http://10.22.6.206:9097/xe/act=dispWidgetInfo&selected_widget=../widgets/content&0=phpinfo();

跟进dispWidgetInfo()方法,在/modules/widget/widget.view.php line21,
upload successful

其中,get传入的参数selected_widget会进入到$oWidgetModel->getWidgetInfo()方法中,跟进该方法,在/modules/widget/widget.model.php line123,首先会通过$this->getWidgetPath()获得$widget_path,值为./widgets/../widgets/content/,接下来给$xml_file变量赋值,值为./widgets/../widgets/content/conf/info.xml,给$cache_file变量赋值,值为/Applications/MAMP/htdocs/xe/files/cache/widget/../widgets/content.zh-CN.cache.php。
然后进入一层if判断,如果$cache_file存在并且$cache_file的修改时间晚于$xml_file的修改时间,就会调用include函数对$cache_file进行包含,然后返回包含的内容,造成rce。
upload successful

如果$cache_file不存在就会自动解析之前的$xml_file文件,然后写入内容到$cache_file。
upload successful

看一下写入$cache_file的内容寻找我们可能可控的点,定位到$widget和$widget_path,因为这两个变量的值是由我们传入的参数控制的,流程上会先将$widget和$widget_path格式化成写入到$cache_file的php代码赋值给$buff,然后继续调用writeFile将$buff写入到$cache_file里面。这样就达成了$cache_file内容可控的目的(虽然写入到$cache_file里面的代码有exit(),但是if条件不成立,所以在包含时会继续执行里面的php代码)。
upload successful

通常根据正常的漏洞而言,能写入文件并且文件的内容可控一般就可以getshell了,但对于这个漏洞而言,会在获取到$widget_path后,判断widget_path这个路径是否存在,如果不存在将直接跳过下面所有的执行流程然后return。所以我们还需要寻找可控目录的点,来达到让这个if条件不满足的目的,继续走下面的文件写入流程。
upload successful

全局搜索,找到一个目录创建的点,接下来我们来跟进这个创建目录的点,在/modules/rss/rss.controller.php triggerRssUrlInsert()方法line43
upload successful

$current_module_srl是由我们传入的module_srl参数控制的,所以这个变量是我们可控的,跟进$oRssModel->getRssModuleConfig()方法,在/modules/rss/rss.model.php line37:
upload successful

跟进$oModuleModel->getModulePartConfig,在/modules/module/module.model.php line1408
upload successful

由可控的参数$module_srl和其他参数组合成的$object_key会进入到$oCacheHandler->getGroupKey()方法中,跟进该方法,在/classes/cache/CacheHandler.class.php line256
upload successful

当流程走到这里,$this->keyGroupVersions[$keyGroupName]值为1,不会进入if循环,直接返回一个值cache_group_1:site_and_module:module_part_config:rss_/(可控参数)。回到$oModuleModel->getModulePartConfig方法中,所以$cache_key为cache_group_1:site_and_module:module_part_config:rss_/(可控参数)。继续往下执行,进入if循环,$cache_key会进入$oCacheHandler->put()方法,跟进该方法,在/classes/cache/CacheHandler.class.php line175
upload successful

再跟进$this->handler->put()方法,在/classes/cache/CacheFile.class.php line73,会将可控的$key传递进$this->getCacheFileName()来获取文件的完整缓存路径,然后会调用FileHandler::writeFile()写入php代码到文件内容,那么如果我们传入的参数中本身就包含../或者/这种用来区分文件夹的符号,那么可不可以通过下面的FileHandler::writeFile()成功创建写入文件的同时去创建目录呢?
upload successful

跟进FileHandler::writeFile(),在classes/file/FileHandler.class.php line145
upload successful

$cache_file会先进入getRealPath获取完整路径的文件名,在line149 有个makeDir函数,在/classes/file/FileHandler.class.php line282
upload successful

在这里就会调用系统的mkdir函数(所以在windows下不可行)去创建文件目录,从而达到通过调用FileHandler::writeFile()创建目录的目的。
整个创建文件目录的调用栈为:
upload successful

但是,在利用过程中,还有一个非常坑的坑点,这个程序默认会有一个filter对所有传入的参数进行过滤,这个filter在/classes/context/Context.class.php line1401,假设我们传入的
upload successful

我们来动态跟进看看过滤结果,
upload successful

可以看到,$current_module_srl被过滤成了0,所以后面不会去创建目录,也不会去写入文件,更不会去执行rce。究其原因,是因为进入到如下过滤的代码时。会将返回的result数组置为0。
upload successful

但是我们可以去利用上面的一层判断来跳过这个if循环,当传入的参数值里含有<script或者lt;script或者%3cscript时,会通过escape函数对值进行html实体化然后赋值给$result[$k],并且不对值做任何其他的过滤,从而continue直接return result数组。所以我们传入的payload必须包含<script或者lt;script或者%3cscript,才能跳过下面的if循环,达到参数继续可控的目的。
upload successful

综上所示,我们rce的流程就是创建目录->缓存文件写入->rce。

2.漏洞利用:

upload successful

know it then enjoy it~

打赏
  • © 2020 sommous

老板,来杯卡布奇诺~

支付宝
微信