企业级应用文件读取漏洞深度剖析:从路径遍历到安全防御

发布时间:2026/7/5 12:03:01

企业级应用文件读取漏洞深度剖析:从路径遍历到安全防御 1. 项目概述一次典型的企业级应用文件读取漏洞深度剖析最近在梳理一些历史漏洞案例时我重新审视了“亿赛通电子文档安全管理系统”的几处任意文件读取漏洞。这个案例非常经典它不像那些利用复杂链式攻击的漏洞那么炫技但却实实在在地暴露了许多企业级应用在设计和开发过程中普遍存在的、容易被忽视的安全短板。对于从事安全研究、渗透测试或者企业安全运维的朋友来说这类漏洞的挖掘和复现思路具有很高的学习价值。它教会我们有时候最危险的漏洞就藏在那些看似最普通、最不起眼的文件操作功能里。亿赛通电子文档安全管理系统简单来说是一款对企业内部电子文档进行加密、权限控制和流转管理的软件。它的核心使命是“防止信息泄露”但讽刺的是其自身存在的漏洞却可能成为泄露的源头。本次复现涉及的“任意文件读取漏洞”顾名思义就是攻击者能够通过构造特定的请求绕过系统正常的权限校验读取服务器上的任意文件内容。这听起来可能不如“远程代码执行”那么有冲击力但其危害性同样巨大。试想一下如果能够读取到系统的配置文件、数据库连接字符串、日志文件甚至密码哈希那么整个系统的防线就形同虚设了。本次复现的目标不仅仅是按照公开的漏洞描述“走一遍流程”拿到一个flag。我更想深入拆解漏洞的成因理解开发人员当时可能犯下的错误并从中提炼出在代码审计和黑盒测试中如何系统性地寻找这类漏洞的思路。整个过程会涉及到对Web应用常见功能点的测试、对参数传递和路径处理的逻辑分析以及对一些“想当然”的安全假设的挑战。无论你是想入门Web安全的新手还是希望巩固自己测试方法论的老手相信这个案例都能给你带来一些启发。2. 漏洞原理与核心成因深度解析2.1 任意文件读取漏洞的通用模型在深入亿赛通的具体案例之前我们有必要先建立一个关于“任意文件读取漏洞”的通用心智模型。这类漏洞的本质是应用程序在处理用户提供的“文件路径”或“文件名”参数时未能进行充分、有效的安全校验导致攻击者可以通过目录穿越../、绝对路径、或利用特殊协议如file://等方式访问到应用程序预期范围之外的文件系统区域。一个最典型的漏洞代码模式如下以Java为例String fileName request.getParameter(file); File file new File(/safe/directory/ fileName); // 直接读取文件内容并返回这段代码的意图是从/safe/directory/目录下读取用户指定的文件。但如果攻击者传入../../../etc/passwd拼接后的路径就变成了/safe/directory/../../../etc/passwd最终指向了系统的/etc/passwd文件。这就是经典的“路径遍历”攻击。为什么开发人员会写出这样的代码原因往往有几个一是过度信任前端输入认为前端传递的参数是“安全”的二是对API的理解不足例如误以为File类构造函数会自动将路径限制在某个基目录下三是为了“灵活性”或“快速实现功能”而牺牲了安全性比如为了方便调试而留了一个读取日志文件的功能却没有做权限控制。注意现代Web框架和语言通常提供了更安全的API。例如Java中可以使用Paths.get(basePath, userInput).normalize()并进行校验确保规范化后的路径仍然以basePath开头。但关键在于开发者必须有这个安全意识去使用它们。2.2 亿赛通漏洞的具体场景推测根据公开的漏洞描述信息亿赛通电子文档安全管理系统的任意文件读取漏洞存在“多处”。这是一个非常重要的线索。“多处”意味着这可能不是一个孤立的编码错误而更可能是一种架构设计缺陷或通用组件的问题。常见的情况包括文件下载/预览功能这是任意文件读取漏洞的“重灾区”。系统可能提供了文档下载、在线预览、附件查看等功能。这些功能的后端接口通常会接收一个文件ID或文件名作为参数然后去服务器的特定目录读取文件流并返回给前端。如果对参数的处理不当漏洞就产生了。日志查看功能为了方便管理员排查问题系统后台往往提供了查看应用日志、操作日志的功能。这个功能本身就需要读取服务器上的日志文件。如果该功能的权限控制不严例如低权限用户也能访问或者路径参数可控且未校验就可能被利用来读取其他文件。配置文件导入/备份恢复功能一些系统管理功能允许上传配置文件或从备份恢复。这些功能在读取服务器上已有文件时如果路径参数可控也可能存在问题。通用文件处理组件系统可能封装了一个统一的“文件读取工具类”被多个模块调用。如果这个工具类本身存在路径遍历问题那么所有调用它的地方都会 inherits 这个漏洞。结合“电子文档安全管理系统”的特性其核心业务就是处理文件因此上述第1点和第4点的可能性最大。攻击者可能通过伪装成一个“合法”的文档查看请求在参数中夹带私货实现越权读取。2.3 漏洞利用的关键参数构造与路径穿越漏洞利用的核心技巧在于“路径遍历”Path Traversal符号的灵活使用。最基本的当然是../。但在实际测试中我们需要考虑多种变体和绕过方式基础穿越../../../etc/passwd编码绕过服务器端可能对../进行了简单的字符串过滤但我们可以尝试URL编码、双重编码甚至其他编码。URL编码..%2f..%2f..%2fetc%2fpasswd(%2f是/)双重URL编码..%252f..%252f..%252fetc%252fpasswd(%25是%)绝对路径如果程序是直接将用户输入与某个基础路径拼接但校验逻辑有缺陷直接传入绝对路径/etc/passwd有时也能成功。空字节截断在一些较老的技术栈中如PHP特定版本在文件名后添加空字节%00可以截断后续的字符串。例如如果代码是include($_GET[file] . .php)传入../../../etc/passwd%00拼接后变成../../../etc/passwd%00.php处理时%00后的.php被忽略。但这种方法在现代Java、.NET等环境中通常无效。利用操作系统特性在Windows系统上路径分隔符是\但许多应用也接受/。还可以尝试使用..\、..//等混合形式。甚至可以利用Windows的短文件名、UNC路径等特性进行测试。在实际对亿赛通进行测试时我们需要系统地遍历其所有涉及文件操作的接口并对每一个可能的参数尝试上述多种Payload。3. 漏洞复现环境搭建与测试思路3.1 环境准备与目标定位由于直接测试真实的企业系统既不合法也不道德安全研究必须在授权和隔离的环境中进行。对于这类历史漏洞的复现学习我们通常有以下几种选择寻找公开的漏洞靶场或环境有些安全社区或平台会搭建一些包含已知漏洞的练习环境。但针对亿赛通这种特定商业系统的靶场并不常见。使用虚拟机安装特定版本软件这是最理想的复现方式。我们需要找到存在漏洞的亿赛通电子文档安全管理系统的具体版本安装包例如根据漏洞披露时间可能是某个2019-2021年间的版本并将其安装在虚拟机如VMware或VirtualBox中。务必确保虚拟机网络设置为Host-Only或NAT模式并与物理主机隔离绝不允许连接到互联网或内部网络。基于描述搭建模拟环境如果找不到原版软件我们可以根据漏洞原理使用相同技术栈例如Java Spring MVC搭建一个具有类似缺陷的简易Web应用用于理解漏洞触发流程。这对于理解原理非常有帮助。假设我们通过某种途径获得了存在漏洞的软件安装包版本号例如 V3.0.5.2。以下是在虚拟机中搭建测试环境的一般步骤准备一台Windows Server 2012 R2或Windows 10的纯净虚拟机。按照软件安装手册安装必要的依赖如Java Runtime Environment (JRE)、数据库如MySQL等。安装并配置亿赛通电子文档安全管理系统记录其安装路径、Web服务端口如8080、后台管理地址等信息。安装完成后在虚拟机内部访问系统确认其运行正常。3.2 黑盒测试方法论与工具链面对一个陌生的Web系统如何高效地发现“任意文件读取”这类漏洞我们需要一套系统的测试方法。第一步信息收集与接口枚举这是所有渗透测试的起点。我们需要尽可能全面地找出系统所有与文件读取相关的接口。爬虫与目录扫描使用工具如Burp Suite的Target - Site map功能通过代理浏览系统的每一个功能页面让其自动爬取所有链接。同时使用dirsearch、gobuster或Burp Intruder配合常用Web路径字典对目标进行目录和文件爆破寻找像download、file、view、show、load、getfile、export、report、log等关键词的接口。分析前端代码在浏览器中打开系统页面查看源代码搜索.action、.do、.jsp、/api/、/servlet/等URL模式以及ajax请求中可能包含文件参数的API。参数猜测对于发现的疑似接口观察其请求参数。常见的文件参数名有file、fileName、path、url、filename、document、id可能是文件ID但也需测试等。第二步漏洞探测与Payload构造针对每一个可疑的接口和参数开始系统性的测试。基础测试首先尝试最简单的../../../etc/passwdLinux或../../../windows/win.iniWindows。观察响应。如果返回“文件不存在”、“路径非法”等说明可能有基础过滤如果返回应用错误页面可能是路径格式不对如果返回了正常页面但内容不对需进一步分析。编码绕过测试如果基础Payload被拦截立即尝试编码绕过。将../替换为..%2f、..%252f、..%c0%afUTF-8过长的/等。Burp Suite的Decoder模块是进行编码转换的好帮手。绝对路径测试尝试直接传入/etc/passwd或C:\windows\win.ini。文件类型限制绕过如果接口原本是用于读取图片如imageView?filexxx.jpg尝试../../../etc/passwd%00.jpg空字节截断针对老系统或../../../etc/passwd?.jpg利用某些解析逻辑?后的内容被当作查询参数忽略。利用已知文件不要只盯着/etc/passwd。在Windows上可以尝试读取C:\Windows\System32\drivers\etc\hosts、C:\boot.ini旧系统、应用自身的配置文件如web.xml、config.properties、application.yml等。读取这些文件既能证明漏洞存在也能获取更多关于系统配置的信息为后续渗透做准备。第三步工具辅助与自动化手动测试几个接口后如果发现规律可以考虑使用工具进行半自动化测试。Burp Suite Intruder这是我们的主力武器。将找到的疑似接口和参数在Burp中发送到Intruder设置攻击类型为“Sniper”或“Pitchfork”如果多个参数然后加载一个包含各种路径遍历Payload的字典文件进行Fuzz。通过观察响应长度、状态码和内容快速筛选出成功的Payload。自定义脚本如果需要测试的接口非常多或者有复杂的会话、Token机制可以编写Python脚本使用requests库来自动化整个过程。3.3 针对亿赛通系统的测试切入点猜想基于对同类系统的经验我们可以对亿赛通的测试入口做一些有根据的猜测文档在线预览接口/preview、/onlineView、/showDocument等。参数可能为docId、filePath。文档下载接口/download、/fileDownload、/exportFile。参数可能为id、name、url。日志管理模块通常在管理员后台路径如/admin/log/view、/sys/log/download。参数可能为logDate、logFile。报表导出功能/report/export。参数可能指定了报表模板文件路径。静态资源处理有些系统会有一个统一的静态资源处理器如/resource、/static参数可能指向服务器上的物理文件。在测试时我会首先以普通用户身份登录系统尝试访问文档相关功能用Burp抓包重点观察上述几类请求。4. 漏洞复现实操过程与关键环节4.1 场景一文档下载功能处的路径遍历假设我们通过爬虫或手动浏览发现了一个文档下载链接点击后Burp抓到的请求如下GET /downloadDocument.action?fileId12345typepdf HTTP/1.1 Host: target:8080 Cookie: JSESSIONIDxxxxxx响应是一个PDF文件。这看起来很正常。但如果我们尝试将fileId参数替换为其他值呢可能返回“文件不存在”。这说明后端可能是通过fileId去数据库查询真实的文件存储路径。但有时系统为了“灵活”或“兼容旧版”会提供另一种通过“文件名”直接下载的接口。经过进一步目录扫描我们可能发现另一个接口GET /fileDownload.do?fileNamequarter_report.pdf HTTP/1.1 Host: target:8080 Cookie: JSESSIONIDxxxxxx这个接口看起来就危险得多参数名直接叫fileName。我们立即开始测试。测试1基础路径遍历将请求修改为GET /fileDownload.do?fileName../../../windows/win.ini HTTP/1.1发送请求。观察响应。情况A最理想服务器返回了win.ini文件的内容。漏洞直接复现成功情况B被过滤服务器返回“非法参数”或“文件不存在”。这说明后端可能对../进行了简单的字符串匹配和过滤。测试2编码绕过针对情况B我们尝试编码绕过。在Burp的Repeater模块中选中../../../windows/win.ini右键选择Convert Selection - URL - URL-encode或者手动编码。请求变为GET /fileDownload.do?fileName..%2f..%2f..%2fwindows%2fwin.ini HTTP/1.1再次发送。如果这次成功读取到文件内容说明后端只做了简单的字符串过滤没有对解码后的参数进行二次校验。这是非常常见的防御失效场景。测试3深入利用与信息收集成功读取win.ini后我们的目标远不止于此。我们需要读取更有价值的文件来评估漏洞的实际危害。读取Web应用配置文件尝试读取应用目录下的配置文件这能帮助我们了解系统结构、数据库信息等。fileName..%2f..%2f..%2f..%2fProgram%20Files%2fYisaitong%2fWEB-INF%2fclasses%2fapplication.properties路径需要根据实际安装位置调整可以通过读取web.xml来定位读取数据库配置文件在配置文件中寻找jdbc.url、username、password等关键词。如果成功获取意味着攻击者可能直接访问核心数据库。读取系统敏感文件尝试读取C:\Windows\System32\config\SAM存储用户密码哈希但通常被系统锁定、C:\Windows\System32\drivers\etc\hosts查看网络配置等。实操心得在Windows系统上路径中的空格需要编码为%20。另外Web应用的根目录通常不是磁盘根目录可能需要多次..%2f才能跳出去。一个技巧是先尝试读取一些已知的、肯定存在的文件来“校准”层数比如C:\windows\win.ini在磁盘根目录下两层如果从Web应用子目录如/webapp/开始可能需要..%2f..%2f..%2f..%2fwindows%2fwin.ini。4.2 场景二日志查看功能处的越权读取假设我们通过猜测或信息泄露进入了管理员后台的日志查看页面地址可能是/admin/logManage.jsp。页面有一个下拉框让选择日志文件点击查看后抓包POST /admin/loadLogContent.do HTTP/1.1 Host: target:8080 Content-Type: application/x-www-form-urlencoded Cookie: JSESSIONIDxxxxxx logFileapp_20231027.logtypeview参数logFile看起来是日志文件名。系统可能默认从某个固定的日志目录如/logs/读取。我们尝试进行路径遍历logFile../../../../windows/win.ini同样如果被拦截尝试编码..%2f。如果成功这意味着低权限用户如果能访问到这个接口或者通过其他漏洞进入后台的攻击者可以利用这个功能读取服务器任意文件。更危险的是这个接口可能在设计时就被认为是“高权限”功能因此开发人员放松了警惕未做路径校验。4.3 场景三通用文件处理Servlet的缺陷在信息收集阶段我们可能通过扫描发现一个看似普通的ServletGET /showFile?pathupload/2023-10/image.jpg HTTP/1.1这个showFile可能是一个用于显示用户上传图片的通用处理器。其本意是从upload/目录下读取文件。但如果没有校验path参数是否包含..或者校验逻辑可以被绕过那么攻击者就可以读取其他目录的文件。测试Payloadpath../../../../etc/passwd或者如果服务器是Windows并且upload目录在D:盘而系统文件在C:盘单纯的../可能无法跨盘符。这时可以尝试绝对路径或者利用Windows的网络路径如\\127.0.0.1\C$\windows\win.ini但这取决于服务器配置和权限。5. 漏洞修复方案与安全开发建议5.1 临时缓解措施如果作为系统管理员在漏洞被公开但尚未打补丁时可以采取以下紧急措施Web应用防火墙WAF规则在WAF上部署规则拦截包含../、..\、%2e%2e%2f../的URL编码等路径遍历特征的请求。但要注意WAF规则可能被高级的编码方式绕过这只是一个临时屏障。网络层访问控制严格限制对亿赛通系统管理后台端口的访问仅允许管理员IP段访问。这可以防止外部攻击者利用后台的漏洞点如日志查看功能。文件系统权限加固运行Web服务的账户如tomcat、www-data应该只拥有其必要目录的最小权限。确保其无法读取/etc/、/windows/、/Program Files/等系统关键目录。这在很大程度上可以限制漏洞的影响范围即使被读取也只能读到Web应用自身的文件。5.2 根本性修复方案对于开发人员而言修复此类漏洞必须从代码层面入手遵循“不信任任何用户输入”的原则。方案一白名单校验最推荐如果业务逻辑是读取某个特定类型的文件如图片、指定格式的文档最安全的方式是使用白名单。// 假设只允许读取 upload 目录下的 .jpg, .png, .pdf 文件 String userFileName request.getParameter(file); String safeBaseDir /opt/app/upload/; // 1. 校验文件后缀 ListString allowedExtensions Arrays.asList(.jpg, .png, .pdf); boolean isValidExt allowedExtensions.stream().anyMatch(userFileName::toLowerCase().endsWith); if (!isValidExt) { throw new SecurityException(Invalid file type.); } // 2. 构造规范路径并校验是否在安全目录内 Path userPath Paths.get(userFileName).normalize(); // 规范化处理掉 ../ Path safePath Paths.get(safeBaseDir).resolve(userPath).normalize(); // 解析为绝对路径 if (!safePath.startsWith(Paths.get(safeBaseDir).normalize())) { // 规范化后的路径不在安全目录内说明有路径穿越 throw new SecurityException(Illegal file path.); } // 3. 安全检查通过读取文件 File file safePath.toFile();方案二基于数据库索引业务相关如果文件是通过ID来管理的那么最好的方式是完全不信任客户端提供的路径而是通过ID去数据库查询服务器上存储的真实、安全的相对路径或文件标识。String fileId request.getParameter(fileId); // 1. 校验fileId格式防止SQL注入 // 2. 根据fileId从数据库查询对应的存储路径 storedPath String storedPath fileService.getStoredPathById(fileId); if (storedPath null) { throw new FileNotFoundException(File not found.); } // 3. 直接使用从数据库查出的、受控的路径进行文件操作 Path safePath Paths.get(/secure/storage/root/, storedPath).normalize(); // 可以再加一层校验确保storedPath不包含 ..方案三严格过滤与规范化次选如果业务上确实需要用户提供部分路径则必须进行严格的过滤和规范化校验。禁止目录穿越字符在获取参数后立即检查是否包含..、../、..\等字符无论是否编码。需要同时检查多种编码形式。使用安全的API使用java.nio.file.Paths.get()和normalize()进行规范化然后检查规范化后的路径是否仍然以允许的基目录开头。切记不要使用字符串替换来删除../因为攻击者可能使用....//或..\/等变体来绕过。5.3 安全开发习惯养成输入验证对所有用户输入进行“白名单”验证明确允许的字符和格式拒绝其他一切。最小权限原则运行应用程序的进程账户在操作系统和文件系统上应被授予最小必需的权限。安全代码审查将“文件操作”列为代码审查的重点关注项。审查所有使用File、FileInputStream、Paths、include、require等关键字的地方。使用安全函数库考虑使用经过社区验证的安全库来处理文件路径避免自己重复造轮子时引入漏洞。错误信息处理当文件操作失败时返回通用的错误信息如“文件处理失败”而不是详细的系统路径或错误堆栈防止信息泄露。6. 漏洞挖掘的扩展思考与防御视角通过复现亿赛通的这个漏洞我们不应该仅仅停留在“这个点能读文件”的层面。更重要的是要学会这种攻击面发现和测试的思维方式。对于任何一个新的Web系统我们可以问自己以下几个问题来主动发现这类问题这个系统有哪些功能是需要从服务器读文件的下载、预览、导入、加载模板、查看日志、显示图片…这些功能对应的HTTP接口是什么参数叫什么名字通过爬虫、扫描、前端分析找到它们参数的值用户能控制多少是完全控制还是只能从有限列表中选择如果是列表能否篡改参数的值是如何被后端使用的是直接拼接成文件路径吗通过尝试路径遍历来验证除了../还有哪些绕过方式可能生效编码、绝对路径、空字节、特殊协议file://、php://filter等从防御者或安全开发的角度每次写一个文件读取相关的函数时也应该进行同样的灵魂拷问这个功能真的需要用户指定文件路径吗能不能用ID代替如果必须用路径我能把用户输入限制在一个安全的子目录内吗我使用的API是安全的吗new File(basePath userInput)是危险的我该用什么替代我是否对用户输入进行了规范化normalize和校验startsWith我的错误信息会不会泄露服务器路径漏洞复现的最终目的不是为了“炫技”或进行非法攻击而是为了深刻理解漏洞产生的根源从而在设计和开发环节就将其扼杀。亿赛通电子文档安全管理系统的这个案例像一面镜子照见了许多开发团队在安全意识、安全编码习惯和安全测试流程上的缺失。作为技术人员无论是开发、测试还是运维我们都应该从中吸取教训将安全思维融入日常工作的每一个细节。毕竟保护系统安全最有效的方法永远是在漏洞被利用之前就发现并修复它。

相关新闻