EmpireCMS文件上传漏洞CVE-2018-18086深度剖析与安全加固
1. 项目概述一次对经典CMS漏洞的深度“解剖”EmpireCMS也就是我们常说的帝国CMS在国内内容管理系统领域算得上是“老炮儿”级别的存在了很多早期的企业站、资讯站都基于它搭建。CVE-2018-18086这个漏洞虽然编号是2018年的但直到今天依然有不少未及时更新的老旧站点受其影响甚至成为攻击者批量“拿站”的入口。这个漏洞的本质是一个后台文件上传功能处的安全校验绕过攻击者利用它可以直接上传WebShell从而完全控制服务器。今天我们不只讲怎么复现这个漏洞更重要的是我会以一个安全从业者和开发者的双重身份带大家完整地走一遍漏洞的成因分析、实战利用、影响评估以及最终的修复加固方案。整个过程我会结合我这些年做渗透测试和代码审计的经验把那些官方文档里不会写的“坑”和“技巧”都掰开揉碎了讲清楚。无论你是想了解漏洞原理的安全爱好者还是负责维护EmpireCMS站点的运维或开发人员这篇文章都能给你提供从理论到实战的完整视角。2. 漏洞环境搭建与核心原理深度解析2.1 靶场环境快速部署要点要分析一个漏洞第一步就是把它“养”起来。对于CVE-2018-18086我们需要一个EmpireCMS 7.5的环境。这里我推荐两种方式各有优劣。第一种是使用现成的漏洞靶场集成环境比如Vulhub或DVWA的变种。这种方式最快一条Docker命令就能跑起来适合快速验证漏洞是否存在。但缺点是环境过于“干净”和真实的生产环境差异较大不利于我们理解漏洞在复杂条件下的利用方式。第二种也是我强烈推荐的方式手动搭建一个原版的EmpireCMS 7.5。你可以从官网或一些开源镜像站找到历史版本。安装过程就是标准的PHPMySQL环境配置。这里有个关键细节数据库的字符集建议选择utf8mb4而非老旧的utf8。因为在实际利用过程中某些特殊的Payload可能会因为字符集问题导致执行异常utf8mb4的兼容性更好。安装完成后记得进入后台熟悉一下栏目管理、信息发布、模板管理这几个核心模块的布局因为漏洞点就藏在这些日常操作背后。注意所有漏洞实验务必在隔离的虚拟机或专属的VPS中进行严禁在任何生产环境或未授权的网络中进行测试。这是红线也是职业操守。2.2 漏洞触发路径与代码层根源剖析这个漏洞的入口在后台的“栏目管理”或“信息发布”等相关功能的上传附件处。表面上看系统对上传的文件有后缀名检查比如只允许.jpg,.gif,.png等图片格式。问题出在它的检查逻辑上。我们直接定位到漏洞的核心文件/e/admin/ecmseditor/upload.php具体路径可能因版本微调而异。关键代码段简化后是这样的$file_ext strtolower(substr($_FILES[file][name], strrpos($_FILES[file][name], .) 1)); $allow_ext array(jpg, gif, png, bmp, jpeg); if (!in_array($file_ext, $allow_ext)) { // 拒绝上传 exit(文件类型不允许); } // 生成最终存储文件名 $save_file_name time() . rand(100, 999) . . . $file_ext; move_uploaded_file($_FILES[file][tmp_name], $save_path . $save_file_name);看起来没问题对吧黑名单检查只允许特定后缀。但漏洞的魔咒就藏在strrpos和substr这个组合里。strrpos函数用于查找字符串中指定字符最后一次出现的位置。攻击者可以构造一个特殊的文件名例如shell.php.jpg。此时strrpos($_FILES[file][name], .)找到的是最后一个点号的位置substr截取出来的是jpg顺利通过了in_array检查。然而在后续保存文件时系统直接使用了$_FILES[‘file’][‘name’]的原始文件名或者在某些逻辑分支下拼接文件名时逻辑有误导致最终保存在服务器上的文件依然是shell.php.jpg。这里就出现了安全检查检查后缀与最终执行保存文件的不一致。更致命的一点是Apache等Web服务器在默认配置下对于文件路径的解析存在一个特性当遇到类似/path/to/shell.php.jpg的请求时如果.php是一个已注册的处理器如PHP而.jpg不是服务器会尝试将shell.php.jpg交给PHP解析器去执行。但实际上更常见的情况是EmpireCMS自身的某些路由或包含逻辑在接收到包含.php.的路径参数时未能正确过滤导致文件被当作PHP执行。这就使得shell.php.jpg这样一个看起来是图片的文件实际上可以被服务器解析为PHP脚本。我画一个简单的流程图来展示攻击者的思路攻击者准备一个包含恶意代码的文本文件将其重命名为shell.php.jpg。通过后台合法上传接口提交该文件。服务器端代码检查后缀.jpg通过。文件被保存到服务器可访问的目录名称为shell.php.jpg。攻击者直接访问http://target.com/uploads/shell.php.jpg在某些配置或逻辑下该文件被当作PHP执行WebShell上线。这个漏洞的根源在于校验逻辑与存储逻辑的脱节以及对文件名解析的信任过度。开发者在编写上传功能时只考虑了“检查什么”而没有贯彻“最终存储什么”的一致性安全原则。3. 漏洞实战利用与渗透测试全流程3.1 手工利用与Payload构造艺术理解了原理我们开始实战。首先你需要一个后台权限。这可能是通过弱口令、社会工程学或者其他漏洞获得的。这里我们假设已进入后台。第一步制作WebShell。最简单的一句话PHP木马?php eval($_POST[‘cmd’]);?。将其保存为一个文本文件。第二步关键操作重命名文件。不要直接叫shell.php那肯定被拦。根据我们分析的漏洞命名为shell.php.jpg。这里有个技巧在Windows系统下你可以直接重命名在Linux下可能需要用mv shell.txt ‘shell.php.jpg’命令。确保文件名中的点号是你手动输入的而不是文件扩展名自动隐藏导致的。第三步找到上传点。通常位于“栏目管理” - 选择某个栏目 - “修改” - “栏目选项” - “栏目图片”或相关设置项的上传按钮。“信息发布” - 编辑具体内容 - 编辑器附件上传。 你需要寻找那种允许上传“图片”、“附件”且前端提示支持.jpg/.gif的表单。第四步上传并获取路径。选择shell.php.jpg文件上传。成功后会返回一个文件路径可能直接显示也可能在HTML源码或JSON响应里。仔细查看浏览器开发者工具F12中的“网络”选项卡查看上传请求的响应内容。路径可能类似于/d/file/202501/xxxxxx.php.jpg。第五步连接WebShell。使用中国菜刀、蚁剑、Cknife等WebShell管理工具或者直接用curl命令测试。在工具地址栏填入完整的URL如http://target.com/d/file/202501/xxxxxx.php.jpg密码填cmd对应我们POST的参数名。如果漏洞存在且环境配置允许你将成功获得一个交互式Shell。实操心得在实际渗透测试中返回的路径可能不是绝对路径而是相对路径。你需要结合网站的域名和目录结构进行拼接。另外上传后立即访问如果返回空白页、404或直接下载并不一定代表失败。可能是路径错了也可能是环境配置如mod_security、特定PHP配置阻止了执行。需要结合服务器响应头、错误日志进行综合判断。3.2 自动化工具利用与流量特征分析手工复现有助于理解但实战中效率更高的是工具。对于这类已知CVE漏洞Metasploit框架中有对应的利用模块。使用msfconsole搜索empirecms或CVE-2018-18086即可找到。使用自动化工具时我们更要关注流量特征这对于防御方构建检测规则至关重要。我们抓包分析一次典型的Metasploit攻击流量认证阶段工具会先尝试登录后台。POST请求体中包含username和password字段可能还有enews等action参数。密码可能是弱口令字典爆破。上传阶段这是核心。会向/e/admin/ecmseditor/upload.php或类似路径发送一个multipart/form-data格式的POST请求。其中filename字段的值就是精心构造的shell.php.jpg。文件内容部分即WebShell代码会被编码在请求体中。连接阶段工具解析服务器返回的响应提取出文件存储路径然后向该路径发起一个新的GET或POST请求POST请求体中包含执行命令的参数如cmdwhoami。防御视角安全设备或WAF可以针对这些特征进行检测请求路径中包含/e/admin/等后台目录但User-Agent或IP行为异常如频繁扫描。上传请求中文件名包含非常规的嵌套后缀如.php.jpg,.php.png,.php.gif。HTTP响应中返回的文件路径包含可疑的后缀组合。短时间内同一会话先访问后台登录页再访问上传接口最后访问一个刚上传的、带奇怪后缀的文件。4. 漏洞修复方案与安全加固实践4.1 官方补丁分析与临时缓解措施漏洞曝光后EmpireCMS官方发布了补丁。补丁的核心是修复了/e/admin/ecmseditor/upload.php等文件中的后缀检查逻辑。通常补丁会做两件事白名单校验强化不仅检查最后一个点号之后的后缀还会检查文件名中是否包含多个点号或者对文件名进行更严格的过滤例如使用pathinfo($filename, PATHINFO_EXTENSION)结合白名单这种方式更可靠。重命名存储不再使用用户上传的文件名而是使用系统生成的随机文件名如md5(time() . rand()) . ‘.jpg’并强制赋予一个安全的、从白名单中取出的后缀。临时缓解措施如果无法立即升级最直接在存在漏洞的上传处理脚本如upload.php开头手动添加一段强校验代码。例如$filename $_FILES[file][name]; $ext strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $allow_ext array(jpg, gif, png, bmp, jpeg); // 检查后缀是否在白名单 if (!in_array($ext, $allow_ext)) { die(Invalid file type.); } // 检查文件名中是否包含‘.php’等危险字符可选但建议 if (stripos($filename, .php) ! false) { die(Invalid file name.); } // 使用系统生成的新文件名 $new_filename md5(uniqid() . mt_rand()) . . . $ext;修改服务器配置在Web服务器如Nginx配置中为上传目录添加规则禁止执行PHP脚本。location ~* ^/uploads/.*\.(php|php5|php7|phtml)$ { deny all; }注意这只是一种缓解如果攻击者通过其他文件包含漏洞引用了上传目录中的文件此规则可能失效。4.2 根本性修复与安全开发规范打补丁是治标建立规范才是治本。对于文件上传功能必须遵循以下安全开发规范前端后端双重校验但以后端为准前端可以做格式提示但后端必须进行完全、严格的校验。前端校验可以被轻松绕过。使用白名单而非黑名单只允许明确安全的文件类型。名单要尽可能小。文件内容检查对于图片使用getimagesize()函数检查文件头确保是真实的图片格式而不仅仅是后缀伪装。对于其他类型可以考虑进行病毒扫描或格式解析。重命名存储永远不要使用用户上传时的原始文件名。应使用随机生成的文件名如UUID并强制附加白名单中的安全后缀。控制存储路径和权限将上传文件存储在Web根目录之外通过脚本程序来读取和分发。这样即使文件是恶意脚本也无法直接通过URL访问执行。如果必须存储在Web可访问目录务必确保该目录没有执行脚本的权限通过服务器配置实现。文件系统权限应设置为最小必要权限例如只允许Web服务器用户读写禁止执行。记录与监控记录所有上传操作包括时间、IP、用户、原始文件名、存储路径。对上传目录进行文件完整性监控或异常扫描。对于EmpireCMS这类老系统除了修复这个具体漏洞还应进行全面的安全审计检查其他模块是否存在类似的问题例如用户头像上传、模板文件上传等。5. 漏洞衍生风险与高级利用场景探讨5.1 结合其他漏洞的链式攻击在真实的攻击中攻击者很少只用一个漏洞。CVE-2018-18086常被作为攻击链的一环。场景一权限提升。攻击者可能先通过一个SQL注入漏洞获取后台管理员密码的哈希值然后破解或利用密码重置漏洞进入后台再利用本漏洞上传WebShell。这样一个前台的注入漏洞就演变成了完全的服务器沦陷。场景二绕过WAF/防火墙。一些WAF规则可能只检测.php后缀。攻击者利用本漏洞上传shell.php.jpg后可能会再寻找一个本地文件包含LFI漏洞。通过LFI漏洞去包含这个shell.php.jpg文件由于包含操作是由PHP解释器执行的它会忽略文件后缀直接解析文件中的PHP代码从而完美绕过基于后缀的WAF规则。场景三持久化后门。获得WebShell后攻击者通常不会满足于一个容易被发现的一句话木马。他们会尝试向系统更深层植入后门例如在/etc/crontab或Web目录的user.iniPHP中写入定时任务或自动加载脚本。修改现有的.php文件在不起眼的位置插入后门代码。创建隐藏的、具有特殊名称的目录和WebShell。5.2 漏洞修复后的残留风险排查即使按照上述方案修复了上传漏洞网站依然可能不安全因为攻击可能已经发生。你需要进行彻底的排查WebShell排查使用专业的WebShell扫描工具如D盾、河马查杀对网站目录进行全面扫描。但要注意对于shell.php.jpg这种非标准后缀的WebShell工具可能漏报。需要手动结合文件时间戳查找最近被修改的、异常的文件、文件大小、文件内容搜索eval,assert,system,shell_exec等危险函数进行辅助排查。日志分析重点检查Apache/Nginx的访问日志和错误日志在漏洞曝光时间点前后寻找对/e/admin/ecmseditor/upload.php的异常访问记录以及后续对疑似WebShell文件如.php.jpg的访问记录。查看是否有大量扫描器如Acunetix, AWVS或特定工具如中国菜刀默认的User-Agent的访问特征。服务器入侵迹象排查检查是否有新增的陌生系统用户。检查/etc/passwd和/etc/shadow文件的修改时间。检查crontab -l和/etc/cron.*目录下是否有异常任务。使用netstat -antp查看是否有异常的对外网络连接。检查~/.ssh/authorized_keys是否被添加了陌生公钥。数据库审计检查EmpireCMS管理员表如phome_enewsuser中是否有管理员密码被篡改或者是否有新增的、权限异常的管理员账户。6. 从漏洞分析到安全运维的体系化思考CVE-2018-18086是一个典型的功能点安全漏洞。它给我们的启示远不止于如何修复这一个点。首先安全需要“一致性”思维。这个漏洞的根源是校验逻辑和存储逻辑的不一致。在开发中任何安全策略都必须在数据流的每一个环节得到贯彻从输入、处理到输出任何一个环节的松懈都可能成为突破口。在设计系统时应该建立清晰的数据流和安全边界图。其次漏洞管理是一个持续的过程。对于EmpireCMS这样的老系统一个CVE的修复不代表高枕无忧。需要建立软件成分清单SBOM持续关注其漏洞动态制定定期升级和补丁计划。对于不再维护的旧系统迁移到更现代、更活跃维护的开源或商业CMS是更安全的选择。再者防御需要纵深。不能只依赖应用层代码的修复。应该在网络层WAF、防火墙、主机层文件权限、入侵检测系统HIDS、应用层安全编码、漏洞扫描共同布防。即使文件上传漏洞被利用严格的目录权限和服务器配置也能阻止WebShell执行即使WebShell被执行HIDS也能及时发现异常进程和网络连接。最后渗透测试与代码审计应成为常态。对于重要的业务系统定期进行黑盒渗透测试和白盒代码审计是发现潜在风险的有效手段。测试不应只针对新功能对历史遗留代码尤其是像文件上传、用户登录、数据库查询这样的高危功能点要进行重点审计。在我处理过的众多应急响应事件中由老旧CMS漏洞引发的入侵占了很大比例。很多管理员认为网站内容多年未变就很安全却忽略了运行它的软件本身在不断暴露出新的弱点。维护一个网站的安全就像维护一栋老房子的结构需要定期检查、加固而不是等到漏水了才想起修补。对于EmpireCMS如果你还在使用7.5或更早的受影响的版本那么立即行动按照本文的方案进行修复和加固是你当下最应该做的事情。