企业级Java Web应用路径遍历漏洞复现与防护实践
1. 项目概述一次典型的企业级应用安全漏洞复现之旅最近在梳理企业应用安全审计的案例库金蝶EAS系统的一个历史文件读取漏洞编号13引起了我的注意。这个漏洞本身并不复杂但它的出现和利用场景非常典型几乎涵盖了企业级Java Web应用安全测试中“信息收集”和“初步渗透”阶段的所有关键动作。对于从事企业安全服务、渗透测试或者想了解大型商业软件安全风险的朋友来说复现和分析这类漏洞其价值远不止于拿到一个“漏洞证明”。它更像是一次解剖麻雀的过程能让你深刻理解一个庞大、复杂的商业系统是如何在细微之处“失守”的以及攻击者是如何利用这些缝隙一步步撬开企业核心数据大门的。简单来说这个漏洞允许攻击者在未授权或低权限的情况下通过构造特定的HTTP请求读取金蝶EAS服务器上的任意文件。别小看“读取文件”这四个字在实战中它往往是打开潘多拉魔盒的第一把钥匙。通过读取配置文件攻击者可以获取数据库连接字符串、加密密钥、内部接口地址通过读取日志文件可以分析系统运行状态、寻找其他漏洞线索甚至能读取到包含敏感信息的业务文件。今天我就带大家完整地走一遍这个漏洞的复现、分析与思考过程不仅会给出可操作的复现步骤更重要的是拆解背后的原理、分享在复现过程中容易踩的坑以及从这个漏洞延伸出去的企业安全防护思路。2. 漏洞原理与影响范围深度解析2.1 漏洞核心路径遍历与未授权访问的“组合拳”这个漏洞的本质是Web应用程序中经典的“路径遍历”Path Traversal或“目录穿越”漏洞在金蝶EAS系统的某个特定接口或功能点上未得到有效控制。用大白话讲就是系统提供了一个“读取文件”的功能比如用来加载某个模板、查看某个日志但在处理用户传入的“文件名”参数时没有进行严格的过滤和校验。攻击者可以在这个参数中注入“../”这样的目录跳转符。在Unix/Linux系统中“../”代表上一级目录在Windows系统中也可以用“..\”实现类似效果。当程序拼接用户输入的参数和基础路径时如果未做净化就可能形成类似/app/webroot/../../etc/passwd这样的最终路径。经过系统解析/webroot/../会抵消路径就变成了/app/etc/passwd从而成功跳出了程序设定的安全目录范围访问到系统上的任意文件。在金蝶EAS这个具体案例中问题通常出现在一些用于文件下载、图片预览、日志查看的Servlet、JSP页面或WebService接口上。这些功能本意是好的是为了方便用户或管理员但因为对输入参数如fileName、filePath、path等的信任度过高缺乏足够的合法性校验如检查是否包含“..”跳转符、是否以预期扩展名结尾、是否在白名单目录内导致了漏洞的产生。2.2 影响范围不止于数据泄露理解这个漏洞的影响不能只停留在“能读文件”本身。我们需要从攻击链的角度来评估敏感信息泄露这是最直接的危害。攻击者可以读取WEB-INF/web.xml文件分析应用结构读取/WEB-INF/classes/目录下的配置文件如jdbc.properties直接获取数据库的IP、端口、用户名和密码尽管密码可能是加密的但为后续破解提供了可能读取系统日志寻找错误信息中暴露的敏感数据或其他漏洞线索。权限提升的跳板获取的数据库密码可能被用于直接连接后台数据库进行更深入的数据窃取或篡改。读取到的系统配置文件可能包含其他中间件、SSO系统的配置信息为横向移动打开突破口。应用逻辑漏洞的探针通过读取Java类文件.class或配置文件攻击者可以反编译或分析应用的业务逻辑寻找更隐蔽的逻辑漏洞比如业务流程绕过、权限校验缺陷等。对金蝶EAS特定版本的影响该漏洞通常影响金蝶EAS的某些历史版本。由于EAS系统广泛应用于大型集团企业涉及财务、供应链、人力资源等核心模块一旦被利用可能导致企业核心财务数据、员工信息、客户资料等严重泄露造成重大的商业损失和法律风险。注意本文所有复现和讨论均在合法授权的测试环境或专为安全研究搭建的隔离环境中进行。任何未经授权的测试行为都是非法的务必遵守法律法规。3. 复现环境搭建与核心工具准备3.1 靶场环境构建思路要复现一个历史漏洞第一步就是搭建一个与之匹配的环境。对于金蝶EAS这样的商业软件我们通常有几个选择官方历史版本安装包如果可能寻找漏洞影响版本的金蝶EAS安装包。这通常是最佳复现环境但商业软件的旧版本安装包不易公开获取。漏洞环境集成靶场感谢安全社区一些常见的漏洞已经被集成到诸如Vulhub、VulApps等开源漏洞靶场项目中。我们可以直接使用Docker一键搭建这是最方便、最安全的研究方式。从已公开的漏洞详情中逆向如果以上都没有就需要根据漏洞披露中的细节如受影响的URL、参数、版本号去尝试搭建一个近似环境或者直接分析漏洞原理。本次复现我们假设采用第二种最便捷的方式。你需要准备以下基础环境一台测试用服务器或PC配置无需太高4核CPU、8GB内存、50GB硬盘足够。操作系统推荐Ubuntu 20.04/22.04 LTS或CentOS 7/8。Docker与Docker Compose这是运行漏洞靶场的关键。Docker负责容器化运行应用Docker Compose用于编排多容器服务。# 在Ubuntu上安装Docker sudo apt-get update sudo apt-get install docker.io docker-compose -y # 启动Docker服务并设置开机自启 sudo systemctl start docker sudo systemctl enable docker # 将当前用户加入docker组避免每次使用sudo sudo usermod -aG docker $USER # 退出终端重新登录使组生效靶场项目从GitHub等平台获取包含金蝶EAS漏洞的靶场项目。例如你可能需要搜索类似“kingdee-eas-vuln”或“vulhub kingdee”的关键词。3.2 核心测试工具链工欲善其事必先利其器。除了环境我们还需要一套趁手的测试工具。浏览器与开发者工具任何现代浏览器Chrome/Firefox都是基础。开发者工具F12中的“网络”Network选项卡至关重要用于捕获和分析HTTP请求与响应。Burp SuiteWeb安全测试的“瑞士军刀”。社区版足以完成本次复现。它用于拦截、重放、修改HTTP请求是构造漏洞利用Payload的核心工具。使用要点配置浏览器代理通常为127.0.0.1:8080并安装Burp签发的CA证书以便拦截HTTPS流量。在复现时我们主要使用Proxy代理和Repeater重放器模块。cURL命令行下的HTTP客户端用于快速发送请求、验证漏洞。它的优势在于可以轻松集成到脚本中。# 一个简单的cURL示例用于测试一个GET请求 curl -v http://target-ip:port/path?fileName../../../../etc/passwd目录扫描工具如dirsearch、gobuster或ffuf。用于辅助发现可能存在漏洞的接口路径。因为漏洞可能存在于不为人知的端点。# 使用dirsearch进行简单目录扫描 python3 dirsearch.py -u http://target-ip:port -e jsp,do,action3.3 环境启动与初步识别假设我们已经从Vulhub项目中找到了对应的环境/vulhub/kingdee/eas-file-read-13。# 进入靶场目录 cd /path/to/vulhub/kingdee/eas-file-read-13 # 使用docker-compose启动环境 docker-compose up -d # 查看容器运行状态 docker-compose ps环境启动后通常可以通过http://your-test-ip:8080访问到金蝶EAS的登录界面或默认页面。我们的第一步不是盲目测试而是观察页面特征确认是金蝶EAS系统。尝试默认弱口令如admin/admin登录仅限授权测试环境有时拥有一个低权限账户能帮助发现更多接口。使用浏览器开发者工具查看页面加载了哪些JS、CSS、API接口留意任何与“file”、“download”、“image”、“load”、“resource”等关键词相关的请求。4. 漏洞复现实操与利用过程详解4.1 漏洞接口的发现与定位根据历史漏洞披露的信息此类文件读取漏洞常出现在以下类型的接口中文件下载接口如/portal/fileDownload.do、/appmonitor/protected/selector/download.do等。图片/附件查看接口如/image、/attachment、/showImage等Servlet。报表或文档预览接口如/report/、/document/下的某些功能。日志查看功能一些管理端的日志查看页面。在本次复现中我们假设漏洞存在于一个名为/portal/commonauth/fileDownload.jsp的接口此为示例路径实际路径需根据靶场或情报确定。这个接口可能接收一个path或fileName参数来指定要下载的文件。第一步使用Burp Suite拦截请求打开Burp Suite确保代理监听开启。浏览器配置好代理访问靶场环境进行任意一次需要触发文件下载的操作如果有的话或者直接尝试访问可疑的URL。在Burp的Proxy - Intercept标签页你会看到拦截到的HTTP请求。第二步定位与修改参数假设我们拦截到一个如下请求GET /portal/commonauth/fileDownload.jsp?fileNamedefault_style.css HTTP/1.1 Host: target-ip:8080 User-Agent: Mozilla/5.0...这个请求看起来是在下载一个名为default_style.css的样式表。fileName参数很可能就是存在漏洞的参数。4.2 构造并发送恶意Payload我们将请求发送到Burp的Repeater模块以便反复修改和测试。基础Payload测试 在Repeater中我们将fileName参数的值修改为经典的路径遍历Payload尝试读取系统根目录下的/etc/passwd文件Linux系统或C:\windows\win.ini文件Windows系统需注意路径分隔符。Linux环境Payload:fileName../../../../../../etc/passwd为什么是多个../因为我们需要从Web应用的工作目录如/usr/local/tomcat/webapps/ROOT回溯到根目录。多写几个是为了确保能“跳”出去这是一个经验性的尝试。Windows环境Payload(如果靶场是Windows)fileName..\..\..\..\..\..\windows\win.ini注意Java应用在Windows上运行时有时仍能识别“/”作为路径分隔符因此../../../../windows/win.ini也可能生效。..\是Windows原生格式。发送请求并观察响应 点击“Send”按钮。重点关注响应状态码和响应体。成功迹象状态码为200 OK响应体内容显示为/etc/passwd文件的内容包含root:x:0:0...等用户信息或win.ini的内容。响应头中的Content-Type可能为text/plain或保持不变。失败迹象状态码可能是404未找到、403禁止访问、500服务器内部错误。响应体可能包含错误信息如“文件不存在”、“路径非法”等。这需要进一步分析。4.3 进阶利用读取Web应用配置文件读取系统文件证明了漏洞存在但对我们理解应用和进一步利用更有价值的是读取Web应用自身的配置文件。关键目标文件WEB-INF/web.xml这是Java Web应用的核心部署描述文件。它可能暴露Servlet映射、过滤器、上下文参数是分析应用结构的“地图”。Payload尝试由于WEB-INF目录受容器保护无法通过Web直接访问。我们需要利用路径遍历从其他可访问目录“跳”进去。通常漏洞JSP文件本身可能就在某个子目录下。我们可以尝试fileName../../WEB-INF/web.xml或者结合已知路径进行更多层级的跳转。数据库配置文件通常位于WEB-INF/classes/目录下文件名可能是jdbc.properties、application.properties、config.properties等。Payload尝试fileName../../WEB-INF/classes/jdbc.properties价值该文件极有可能明文或加密存储着数据库的连接字符串、用户名和密码。这是通往核心数据库的钥匙。Java类文件.class虽然读出来是二进制但可以保存后使用反编译工具如JD-GUI、CFR进行分析寻找业务逻辑漏洞。实操示例 在Repeater中我们修改Payload为fileName../../WEB-INF/web.xml并发送。如果成功响应内容将是XML格式的配置文件文本。我们可以从中搜索servlet、filter、context-param等标签寻找其他可能有用的接口或配置项。如果返回404或空可能是路径计算不对。我们需要调整../的数量。一个技巧是先尝试读取一个已知存在的Web资源比如fileName./images/logo.png确认基础路径。然后基于此计算到WEB-INF的相对路径。4.4 编码与绕过技巧有时应用程序会进行简单的防御比如过滤了../字符串。这时就需要一些绕过技巧。URL编码将特殊字符进行URL编码。../可以编码为%2e%2e%2f或..%2f..\可以编码为%2e%2e%5c在Burp Repeater中你可以直接输入编码后的字符或者使用Burp的“CtrlU”快捷键对选中部分进行URL编码。双重编码如果应用解码了一次可以尝试双重编码。%2e%2e%2f再次编码后变成%252e%252e%252f%被编码为%25。使用绝对路径极少数情况下程序可能直接拼接用户输入和基础路径如果校验不严直接输入绝对路径也可能成功。fileName/etc/passwd(Linux)fileNameC:\windows\win.ini(Windows)注意在HTTP参数中\有时需要转义或编码。空字节截断这是一个较老的技巧在某些特定场景下如Java旧版本、某些文件处理函数在文件名后添加空字节%00可以截断后续的扩展名校验。fileName../../../etc/passwd%00.jpg这试图欺骗程序让它以为请求的是一个.jpg文件但系统在读取时遇到%00就停止了最终读取的是/etc/passwd。实操心得在测试时我习惯在Burp中建立一个“Payload列表”包含各种常见的路径遍历变形编码、双重编码、绝对路径、空字节等然后使用Burp的Intruder模块进行模糊测试效率会高很多。但手动在Repeater中逐个尝试对于理解漏洞原理更有帮助。5. 漏洞根因分析与安全开发启示5.1 为什么会出现这个漏洞从开发角度看这个漏洞的产生几乎是“教科书式”的安全失误过度信任用户输入开发者默认用户只会传入一个预期的、相对路径的文件名如default_style.css或2024_report.pdf没有对输入做“不信任”处理。错误的路径拼接方式直接使用字符串拼接来生成最终文件路径例如// 危险示例 String basePath /opt/eas/webapps/portal/; String userFileName request.getParameter(fileName); String fullPath basePath userFileName; // 如果userFileName是../../../etc/passwd就完了 File file new File(fullPath);缺乏规范化与校验没有对拼接后的路径进行“规范化”canonicalize并检查其是否仍在预期的安全目录如Web应用的静态资源目录内。Java中可以使用File.getCanonicalPath()方法获取标准路径然后检查这个标准路径是否以安全目录的路径开头。缺失最小权限原则运行Web服务的操作系统账户权限过高导致Web进程可以读取系统关键文件。5.2 如何修复给开发者的安全建议修复此类漏洞核心原则是“白名单校验”和“路径隔离”。白名单机制如果业务上只允许下载固定的一些文件最好的方式是维护一个允许的文件名或文件ID的白名单。用户传入参数如文件ID后端根据ID映射到真实的、安全的文件路径。MapString, String fileWhitelist new HashMap(); fileWhitelist.put(style1, /safe/path/default_style.css); fileWhitelist.put(report1, /safe/path/template.pdf); String fileId request.getParameter(fileId); String safeFilePath fileWhitelist.get(fileId); if (safeFilePath null) { // 返回错误请求的文件不在允许范围内 return; } File file new File(safeFilePath);安全路径拼接与校验如果必须允许一定动态性必须进行严格校验。String baseDir /opt/eas/webapps/portal/uploads/; // 安全的基础目录 String userFileName request.getParameter(fileName); // 1. 过滤目录跳转符 if (userFileName.contains(..) || userFileName.contains(\\)) { throw new SecurityException(Invalid file name); } // 2. 拼接路径 File potentialFile new File(baseDir, userFileName); // 3. 获取规范化路径并检查是否逃逸 String canonicalPath potentialFile.getCanonicalPath(); if (!canonicalPath.startsWith(new File(baseDir).getCanonicalPath())) { // 试图跳出安全目录 throw new SecurityException(Access denied); } // 4. 确认文件存在且是普通文件非符号链接等 if (!potentialFile.isFile()) { throw new FileNotFoundException(); }运行权限降级确保运行Tomcat/JBoss等应用服务器的操作系统账户是一个专用、低权限的账户如www-data、tomcat避免使用root。输入输出编码在将文件内容输出到HTTP响应时确保设置正确的Content-Disposition头避免文件内容在浏览器中被当作HTML执行导致XSS等二次漏洞。6. 复现过程中的常见问题与排查实录即使按照步骤操作复现过程也可能遇到各种问题。这里记录几个我踩过的坑和解决方法。6.1 问题一发送Payload后返回404或空白页可能原因1路径计算错误。../的数量不够没能跳出Web应用的根目录。排查尝试增加或减少../的数量。可以先尝试读取一个已知存在的Web文件如fileName./index.jsp确认当前工作目录再计算到目标文件的相对路径。可能原因2目标文件不存在或权限不足。Web进程用户没有读取/etc/passwd等系统文件的权限在良好的系统配置下应如此。排查尝试读取一个肯定存在且有读权限的文件比如Web应用自身的WEB-INF/web.xml或一个图片文件。如果这些能读但系统文件不能读说明权限控制起了部分作用但这不意味着漏洞不存在只是危害范围被缩小了。可能原因3漏洞接口路径不对。你测试的URL可能不是存在漏洞的那个端点。排查回顾漏洞披露信息检查URL路径是否正确。使用目录扫描工具如dirsearch扫描/portal/、/appmonitor/等常见路径下的.jsp、.do、.action文件寻找其他可能的文件下载接口。6.2 问题二返回错误提示“路径非法”或“文件不存在”可能原因应用程序进行了初步过滤。后端代码可能检测到参数中包含..或/等字符直接返回了错误。排查尝试使用编码绕过。在Burp中选中../按CtrlU进行URL编码将../变为%2e%2e%2f再发送。也可以尝试双重编码、使用..\Windows路径分隔符等。6.3 问题三响应内容乱码或文件被下载而非显示可能原因1字符编码问题。读取的配置文件或二进制文件在HTTP响应中编码不一致。排查在Burp的响应窗口中尝试切换不同的解码视图如“HTML”、“Hex”。对于文本文件确保浏览器或Burp使用了正确的字符集如UTF-8进行渲染。可能原因2服务器设置了强制下载头。接口可能设置了Content-Disposition: attachment导致浏览器直接下载文件。排查这并不影响漏洞利用。你可以在Burp的响应中直接查看原始内容或者将响应体Response body保存为文件然后用文本编辑器打开查看。6.4 问题四Docker靶场环境无法启动或访问可能原因1端口冲突。靶场默认使用的端口如8080已被本机其他程序占用。排查使用netstat -tulnp | grep 8080查看端口占用情况。修改docker-compose.yml文件中的端口映射例如将8080:8080改为8081:8080然后通过http://localhost:8081访问。可能原因2镜像拉取失败或构建错误。排查检查网络连接。尝试手动拉取基础镜像docker pull vulhub/...。查看docker-compose up的错误输出根据提示解决问题可能是Dockerfile中的某条命令执行失败。一个实用的排查流程记录在一次复现中我遇到读取web.xml返回404但读取/etc/passwd却成功的情况。这很奇怪。后来我通过读取一个已知的图片文件logo.png发现其完整URL路径是/portal/resources/images/logo.png。我据此推断漏洞JSP文件fileDownload.jsp的实际物理路径可能比我想象的深。于是我尝试了fileName../../../../WEB-INF/web.xml增加了两层../果然成功了。这说明在测试时结合已知资源路径进行推理是定位正确../层数的有效方法。7. 从漏洞复现到企业安全防护的思考复现一个漏洞绝不仅仅是为了“证明它能通”。作为安全从业者我们应该想得更远。金蝶EAS这个文件读取漏洞像一面镜子映照出许多企业级应用在安全开发生命周期SDLC中的共性短板。对甲方的启示企业安全运维人员资产管理与漏洞预警必须建立完善的企业软件资产清单明确所有在用的商业软件如金蝶EAS、用友NC、OA系统等的名称、版本、部署位置。主动订阅这些产品的官方安全公告、CNVD/CNNVD等漏洞库信息一旦出现类似高危漏洞通告能第一时间定位受影响资产。最小化安装与权限配置在部署像EAS这样的大型系统时应遵循最小权限原则。为应用服务器分配独立的、低权限的系统账户。严格限制其文件系统访问权限确保其只能读写必要的应用目录和数据目录无法访问系统关键路径。纵深防御与WAF规则在网络边界或应用前端部署WAFWeb应用防火墙并配置针对路径遍历../,..\, 编码变形攻击的检测规则。即使应用本身有漏洞WAF也能作为一道有效的缓冲防线。定期安全评估对核心业务系统定期进行授权下的渗透测试或漏洞扫描主动发现潜在风险而不是等到被攻击后才补救。对乙方的启示安全研究人员与开发者漏洞研究的范式研究一个漏洞要从利用点攻击面追溯到根本原因代码缺陷再升华到防护方案。完整的漏洞报告应包括漏洞描述、影响版本、复现步骤含截图、原理分析可附关键代码段、修复建议。这比单纯提供一个Payload有价值得多。安全开发意识的灌输在项目开发中必须强制推行安全编码规范。对所有用户输入包括参数、头、Cookie视为不可信进行严格的校验、过滤和规范化。文件操作、数据库查询、命令执行等高风险函数的使用必须经过安全评审。组件安全与依赖管理很多漏洞源于陈旧的、有已知漏洞的第三方组件如旧版本的Apache Commons FileUpload、Spring框架等。需要建立软件成分分析SCA流程持续监控和升级第三方库。复现这个漏洞的过程就像一次精细的考古。我们不仅挖出了那个特定的“陷阱”更看清了形成这片“陷阱区”的地质结构。对于企业而言真正的安全不是堵住某一个漏洞而是构建起一套能够持续发现和修复漏洞的机制与文化。每一次成功的漏洞复现都应该是向着这个目标迈进的一步。在测试的最后别忘了将你的靶场环境清理干净执行docker-compose down安全研究始于合规也终于合规。