
1. 项目概述一次典型的企业应用文件读取漏洞实战最近在梳理一些历史漏洞案例易宝OA的DownloadFile任意文件读取漏洞是一个挺有代表性的例子。这个漏洞本身原理不复杂但它的出现和利用过程恰恰反映了早期很多企业级Web应用在安全设计上的一些通病——对用户输入过于信任对文件路径的校验形同虚设。我之所以想把这个复现过程详细写下来是因为它不仅仅是一个漏洞的利用步骤更是一个理解“路径遍历”这类基础但高危漏洞的绝佳样本。对于刚入门安全测试的朋友或是负责企业内部应用运维的工程师搞清楚这类漏洞的来龙去脉无论是为了防御还是进行合规的自检都很有价值。简单来说这个漏洞允许攻击者通过构造特定的HTTP请求绕过系统正常的文件下载逻辑直接读取服务器上的任意文件。这意味着什么配置文件、数据库连接字符串、源代码、甚至系统密码哈希都可能被一览无余。它的危害等级通常被定义为“高危”或“严重”。复现它我们需要一个存在漏洞的易宝OA环境可以是官方历史版本搭建的测试环境一个能发送HTTP请求的工具比如Burp Suite、Postman甚至浏览器然后就是关键的一步找到那个未对输入进行过滤的接口并构造出那个能“穿越目录”的请求。2. 漏洞原理深度解析为什么一个下载功能会变成后门要动手复现先得把原理吃透。知其然更要知其所以然这样你才能举一反三在面对其他类似系统时具备基本的判断力。2.1 核心问题路径遍历Path Traversal这个漏洞的本质是经典的路径遍历也叫目录穿越。它的根源在于应用程序在处理用户提供的文件路径参数时没有进行有效的规范化Normalization和合法性校验。一个正常的文件下载功能逻辑应该是这样的前端告诉后端“我要下载ID为123的文件”后端去数据库查询ID123的文件记录得到它在服务器上的安全存储路径例如/upload/2023/05/abc.pdf然后读取这个路径下的文件并返回给前端。在这个过程中用户无法控制服务器上的具体路径。而易宝OA这个漏洞出问题的接口很可能采用了另一种设计前端直接传递了一个文件路径或文件名给后端。比如参数可能是fileName../../../../etc/passwd。如果后端代码简单地拼接这个参数到基础目录上如$basePath . $fileName而没有检查$fileName中是否包含../这样的上级目录跳转符那么拼接后的路径就可能跳出预定的下载目录指向系统的任意位置。2.2 易宝OA DownloadFile 接口的潜在缺陷场景基于常见的代码缺陷模式我们可以推测漏洞发生的几种可能代码场景场景一直接拼接用户输入// 伪代码示例 $file $_GET[file]; // 用户可控参数 $base_dir /var/www/html/yibaooa/upload/; $file_path $base_dir . $file; // 危险直接拼接 readfile($file_path); // 读取并输出文件如果攻击者传入file../../../etc/passwd那么$file_path就变成了/var/www/html/yibaooa/upload/../../../etc/passwd经过系统路径解析最终指向的就是/etc/passwd。场景二使用了存在缺陷的过滤有些开发者会尝试过滤但方法不彻底。$file str_replace(../, , $_GET[file]); // 只替换一次这种过滤很容易被绕过例如使用....//或..\Windows下等变体。更高级的绕过可能涉及编码如URL编码%2e%2e%2f代表../或双重编码。场景三逻辑缺陷导致路径可控可能接口本意是通过一个ID或经过校验的令牌来下载但在某些分支逻辑或错误处理流程中意外地留下了一个可以直接指定文件路径的参数入口。注意以上代码仅为基于漏洞现象和常见编程错误进行的合理推测用于解释原理。实际漏洞代码可能有所不同但核心思想一致用户输入控制了文件读取的最终路径。2.3 漏洞利用的影响范围成功利用此漏洞攻击者可以读取哪些文件这取决于Web服务器进程如www-data, apache, nginx的运行权限。Web目录外的敏感文件如/etc/passwdLinux用户列表、/etc/shadowLinux密码哈希需root权限、C:\Windows\System32\config\SAMWindows密码哈希需系统权限。应用本身的配置文件这是最常被攻击的目标。例如易宝OA的数据库配置文件可能叫web.config,config.php,application.properties等里面通常明文或弱加密存储着数据库IP、端口、用户名和密码。拿到数据库密码几乎就等于拿到了整个应用的数据。应用源代码通过读取.java,.php,.class等文件攻击者可以进行白盒审计寻找更深入的漏洞如SQL注入、反序列化等。日志文件可能包含管理员的访问记录、错误信息、甚至调试日志里的敏感数据。理解了这个原理我们就知道复现的关键在于找到那个接收文件路径参数的接口并尝试通过路径遍历符号../跳出限制。3. 环境搭建与漏洞复现实操理论清楚了我们进入实战环节。郑重声明所有测试必须在您拥有完全控制权的授权环境如本地虚拟机、专属测试服务器中进行。未经授权对任何线上系统进行测试是非法行为。3.1 测试环境准备获取易宝OA存在漏洞的版本根据漏洞披露时间通常需要搜索历史漏洞库如CNVD、CNNVD或安全社区文章确定存在漏洞的易宝OA具体版本号。例如可能是 v8.0 或更早的某个版本。请通过合法渠道获取该版本的安装包。搭建测试环境系统建议使用Windows Server 2008/2012或CentOS 7更贴近当时的主流部署环境。中间件根据易宝OA的要求安装对应版本的IISWindows或TomcatLinux/Windows。数据库通常需要SQL Server或MySQL。部署OA按照官方安装手册将易宝OA部署起来并初始化数据库。确保能正常登录访问主页面。测试工具Burp Suite Professional/Community首选。用于拦截、重放、修改HTTP请求是Web漏洞测试的瑞士军刀。浏览器Chrome或Firefox配合开发者工具F12使用。Postman用于手动构造和发送请求适合简单的PoC验证。3.2 漏洞接口探测与利用这是最核心的一步。我们并不知道漏洞接口的确切URL需要根据经验和常见模式进行探测。步骤一信息收集与接口发现静态分析如果有源码搜索源码中包含“Download”、“downloadFile”、“file”、“read”等关键词的Servlet、Controller或ASP/ASPX/PHP文件。关注那些接收file,fileName,path,url等参数的函数。动态爬取与模糊测试使用浏览器正常使用易宝OA同时开启Burp Suite作为代理拦截所有流量。重点关注任何触发文件下载或预览的链接比如“下载附件”、“查看图片”、“导出报表”等功能。在Burp的Target - Site map中查看收集到的所有URL路径。寻找包含download,file,read,getfile,showfile,display等关键词的路径。常见的可疑路径可能类似于/DownloadFile/file/download/servlet/DownloadServlet/common/download.jsp步骤二构造并发送恶意请求假设我们通过探测发现了一个疑似接口http://your-test-ip:port/yibaooa/DownloadFile基础测试首先我们尝试读取一个Web应用目录下已知存在的文件比如index.jsp或login.jsp。GET /yibaooa/DownloadFile?fileName../../WEB-INF/web.xml HTTP/1.1 Host: your-test-ip:port../../是向上跳两级目录。我们需要根据应用的实际部署路径来调整../的数量。这是一个“试”的过程。WEB-INF/web.xml是Java Web应用的标准配置文件通常包含重要信息且位于Web根目录下的WEB-INF文件夹内该文件夹无法通过普通URL直接访问但通过路径遍历漏洞可能可以读取。系统文件测试如果上一步成功尝试读取系统文件。GET /yibaooa/DownloadFile?fileName../../../../../../etc/passwd HTTP/1.1 Host: your-test-ip:port这里使用了更多的../以确保跳出Web根目录。Linux系统可以尝试/etc/passwdWindows系统可以尝试../../../../../../Windows/System32/drivers/etc/hosts。参数名与编码绕过如果fileName参数不成功尝试其他常见参数名file,path,url,filename,f。如果直接使用../被拦截尝试URL编码%2e%2e%2f(../),%2e%2e/(../)。尝试双重编码%252e%252e%252f服务器解码两次。尝试使用绝对路径如果程序逻辑是直接使用用户输入fileName/etc/passwd。尝试空字节截断在较老系统中可能有效fileName../../../etc/passwd%00.jpg程序可能期望一个图片文件名用空字节截断后面的.jpg。步骤三判断结果成功服务器返回HTTP状态码200响应体内容就是目标文件的内容。例如读取/etc/passwd会返回系统的用户列表文本。失败可能返回403禁止访问、404文件未找到、500服务器内部错误。404可能意味着路径跳转不对需要调整../的层数。500可能意味着触发了服务器的安全机制或程序异常。3.4 一个完整的复现案例记录为了更直观我模拟一次在测试环境中的操作记录环境本地虚拟机IP为192.168.1.100部署了易宝OA v7.5假设该版本存在漏洞访问地址为http://192.168.1.100:8080/yibaooa。开启代理配置浏览器代理到Burp Suite127.0.0.1:8080。访问OA并拦截登录OA点击一个“文档下载”链接。在Burp的Proxy - HTTP history中我找到了请求GET /yibaooa/servlet/DownloadFile?fileId12345 HTTP/1.1看起来是用fileId下载似乎安全。但我尝试直接访问DownloadFile这个Servlet。直接探测接口在浏览器或Burp的Repeater中发送GET /yibaooa/servlet/DownloadFile HTTP/1.1 Host: 192.168.1.100:8080服务器返回了400错误错误请求提示缺少参数。这说明DownloadFile这个接口确实存在并且需要参数。尝试路径参数我猜测它可能支持file或fileName参数。发送GET /yibaooa/servlet/DownloadFile?fileNametest.txt HTTP/1.1 Host: 192.168.1.100:8080返回404。这并不一定是漏洞不存在可能只是test.txt文件不存在。我尝试读取一个肯定存在的Web文件比如index.jsp但需要知道相对路径。我先尝试读取当前目录下的GET /yibaooa/servlet/DownloadFile?fileNameindex.jsp HTTP/1.1返回404。我猜测Servlet的当前路径可能不是Web根目录。尝试向上跳转GET /yibaooa/servlet/DownloadFile?fileName../index.jsp HTTP/1.1返回200并且内容正是OA的首页JSP代码。漏洞存在深入利用现在尝试读取系统文件。我需要确定从Servlet路径到系统根目录需要多少层../。经过几次尝试我发现GET /yibaooa/servlet/DownloadFile?fileName../../../../../../etc/passwd HTTP/1.1成功返回了/etc/passwd文件的内容。读取配置文件接下来我尝试寻找OA的配置文件。根据Java Web应用常见结构我尝试GET /yibaooa/servlet/DownloadFile?fileName../../../../WEB-INF/classes/config.properties HTTP/1.1成功在返回的内容中我找到了数据库连接信息jdbc:mysql://localhost:3306/yibaooa_db?userrootpasswordAdmin123。至此漏洞复现成功。从发现接口到读取系统敏感文件和应用配置整个过程清晰展示了路径遍历漏洞的巨大危害。4. 漏洞修复方案与安全开发建议复现漏洞是为了更好地防御。对于开发者和运维人员了解如何修复和避免此类漏洞至关重要。4.1 临时缓解措施如果线上系统短期内无法升级可以考虑以下应急方案Web应用防火墙WAF规则在WAF上部署规则拦截HTTP请求参数中包含连续../、..\、编码后的路径遍历字符以及尝试访问/etc/passwd、web.config等敏感路径的请求。输入验证与过滤在应用层如Filter、Interceptor或Middleware对所有用户输入的参数进行严格的过滤。但要注意单纯替换../可能被绕过应采用白名单机制。权限最小化确保运行Web服务的操作系统账户如www-data具有尽可能低的权限。禁止该账户读取Web目录之外的非必要文件。这可以在漏洞被利用时极大限制攻击者能读取的文件范围。4.2 根本性修复方案修复的核心在于对用户输入的文件名或路径进行严格的“净化”和“校验”。方案一白名单校验推荐这是最安全的方式。不信任用户输入的任何路径而是通过一个不可篡改的标识如文件ID、经过签名的临时令牌来映射到服务器上的真实路径。// 伪代码示例 - 安全版本 String fileId request.getParameter(fileId); // 1. 校验fileId格式如是否为数字 if (!fileId.matches(\\d)) { throw new SecurityException(Invalid file ID); } // 2. 根据fileId从数据库查询安全的存储路径 String safeFilePath fileService.getSafePathById(Long.valueOf(fileId)); // 3. 确保查询到的路径在允许的基目录下 Path basePath Paths.get(/var/www/secure_upload/); Path resolvedPath basePath.resolve(safeFilePath).normalize(); if (!resolvedPath.startsWith(basePath)) { throw new SecurityException(Illegal file path attempt); } // 4. 读取并返回文件 Files.copy(resolvedPath, response.getOutputStream());方案二强过滤与规范化如果业务上必须接受用户输入的文件名则必须过滤非法字符移除所有路径分隔符/,\和跳转符..。使用安全的API进行路径解析String userInput request.getParameter(fileName); // 移除所有路径跳转和目录分隔符 String safeFileName userInput.replaceAll([\\\\/:\*?|], ).replaceAll(\\.\\., ); // 使用安全的API构造最终路径 Path basePath Paths.get(/var/www/upload/); Path finalPath basePath.resolve(safeFileName).normalize(); // 关键检查最终路径是否仍然在基目录之下 if (!finalPath.startsWith(basePath)) { throw new SecurityException(Path traversal attack detected!); }normalize()方法会解析掉.和..startsWith()检查确保了最终路径没有“逃出”允许的范围。4.3 安全开发与运维建议原则永远不要信任用户输入。所有来自客户端的数据都应视为可疑的。使用安全的文件操作API如Java的Path.normalize()和Path.startsWith()PHP的realpath()函数需结合检查前缀。部署目录隔离将用户上传的文件存储在Web根目录之外通过一个专门的文件服务有严格校验逻辑来提供访问而不是直接通过Web服务器映射。定期安全审计与更新对老旧系统进行代码安全审计或使用自动化漏洞扫描工具进行检测。及时关注官方漏洞公告并更新补丁。错误信息处理避免在错误响应中泄露服务器内部路径、堆栈跟踪等敏感信息。应返回统一的、模糊的错误提示。5. 常见问题与排查技巧实录在复现和后续的漏洞挖掘中你肯定会遇到各种问题。这里记录一些我踩过的坑和总结的技巧。5.1 复现过程中常见问题问题现象可能原因排查思路与解决方案返回404Not Found1.../层数不对未跳出Web目录或跳过了目标文件。2. 目标文件确实不存在。3. 参数名猜错了。1.系统文件从../../../etc/passwd开始逐渐增加/减少../的层数如4层、5层、6层。对于Windows尝试../../../../windows/system32/drivers/etc/hosts。2.应用文件先尝试读取Web目录下已知存在的文件如index.jsp、logo.png来确定基础路径和参数有效性。3.参数爆破使用Burp Intruder对常见参数名file, filename, path, url, f, doc, load等进行爆破。返回403Forbidden1. 目标文件系统权限不足Web服务进程无权读取。2. 中间件如IIS、Apache或应用自身设置了目录访问权限限制。1. 尝试读取其他可能具有可读权限的文件如/proc/self/environLinux有时可读、C:\boot.ini旧版Windows。2. 检查是否触发了WAF或应用防火墙规则。尝试对payload进行轻微变形如使用URL编码、大小写变换、添加垃圾参数等。返回500Internal Server Error1. 应用程序在处理畸形路径时抛出未捕获的异常。2. 输入触发了某些安全防护机制的异常。1. 查看返回的详细错误信息如果开启调试可能包含路径信息。2. 尝试更“温和”的payload比如先读取一个合法存在的文件再慢慢引入../。返回200但内容是错误页面或空1. 接口存在但逻辑不是直接文件读取可能经过了其他处理如模板渲染。2. 读取到了文件但文件是二进制或编码格式导致显示乱码。1. 检查响应头的Content-Type。如果是text/html可能是被错误页面覆盖。尝试不同的文件扩展名如.txt,.properties,.xml。2. 在Burp中查看响应的Raw格式或者下载到本地用文本编辑器/十六进制查看器打开。5.2 漏洞挖掘与利用的进阶技巧利用漏洞读取源代码进行二次审计一旦能读取任意文件优先目标就是获取应用的配置文件找数据库密码和关键业务逻辑的源代码。通过阅读源代码你可能发现更严重的漏洞如SQL注入、命令执行、反序列化等。结合其他漏洞扩大战果例如如果同时存在文件上传漏洞你可以先通过文件读取漏洞查看上传组件的校验逻辑然后制作一个能绕过校验的恶意文件上传最终实现代码执行。Windows环境下的路径特点路径分隔符为\但很多Web应用在代码中也会处理/。可以尝试..\或../的混合。可以尝试利用Windows的UNC路径或特殊设备名进行测试需谨慎可能影响服务稳定性但这通常需要更特殊的条件。编码与双重编码始终记得对payload进行编码测试。../的URL编码是%2e%2e%2f。如果服务器解码两次你需要发送%252e%252e%252f%25是%的编码。空字节截断在PHP等语言的老版本中filename../../../etc/passwd%00.jpg可能会被系统在遇到空字节%00时截断而校验逻辑可能只检查了后缀.jpg。这在现代环境中已较少见。5.3 防御视角的排查清单如果你是运维或开发怀疑自己的系统存在此类漏洞可以按以下清单自查代码审计全局搜索readfile(),file_get_contents(),FileInputStream,ServletOutputStream等文件读取函数/类检查其参数是否用户可控。参数追踪追踪所有涉及文件下载、预览、包含功能的接口检查其输入参数是否直接拼接到了文件系统路径中。黑盒测试使用自动化扫描器如Burp Scanner, AWVS或手动对下载类接口进行路径遍历测试。日志分析检查Web日志或应用日志中是否有大量包含../、..\或敏感文件名如passwd,web.config的404或500错误请求这可能是攻击探测的痕迹。这个漏洞的复现过程就像一次标准的外科手术目标明确步骤清晰。它再次印证了安全领域那句老话“所有的输入都是有害的”。对于开发者在设计任何与文件系统、数据库、网络交互的功能时都必须将这句话刻在脑子里。对于安全人员理解这类基础漏洞的利用方式是构建更复杂攻击链的起点。每一次成功的复现都应该让我们对系统的脆弱性多一分敬畏对防御的必要性多一分坚定。在测试的最后别忘了彻底清理你的测试环境避免残留的漏洞利用痕迹带来意外风险。