Web安全实战:路径遍历漏洞原理、复现与防御指南

发布时间:2026/6/29 18:48:41

Web安全实战:路径遍历漏洞原理、复现与防御指南 1. 项目概述一次典型的Web应用路径遍历漏洞复现最近在安全圈里CVE-2025-54100这个编号开始被频繁提及。这是一个典型的Web应用路径遍历漏洞影响了一款在特定场景下广泛使用的文件管理中间件。简单来说攻击者可以利用这个漏洞绕过应用设定的访问限制读取或下载服务器上本不应被访问的敏感文件比如配置文件、日志、甚至是源代码。这类漏洞虽然原理不复杂但危害极大一旦被利用可能导致服务器敏感信息泄露甚至为后续攻击打开大门。我之所以花时间深入研究并复现这个CVE是因为路径遍历Path Traversal是Web安全中经久不衰的“经典”问题。尽管开发框架和安全规范日益完善但在参数处理、路径拼接等细节上稍有不慎就可能埋下隐患。通过亲手复现不仅能深刻理解漏洞的成因和利用条件更能掌握在代码审计和渗透测试中快速识别此类问题的“嗅觉”。无论你是安全研究员、渗透测试工程师还是希望提升代码安全性的开发者跟着我走一遍这个复现过程都会大有裨益。整个过程我们会在一个完全可控的本地实验环境使用Docker搭建漏洞靶场中进行确保安全、合法。2. 漏洞原理深度解析路径拼接的“信任危机”2.1 核心漏洞成因不当的路径规范化与校验缺失CVE-2025-54100的核心问题出在Web应用对用户可控的输入参数进行文件路径拼接时没有进行充分的安全校验和规范化处理。我们假设受影响的应用有一个文件下载或预览功能其接口大致逻辑如下前端请求一个文件例如GET /download?filereport.pdf后端接收到file参数后会将其与一个预设的基础目录进行拼接。拼接后的完整路径可能是/var/www/uploads/report.pdf/var/www/uploads/report.pdf应用然后使用这个拼接路径去读取文件内容并返回给用户。漏洞就隐藏在第二步。如果应用没有对用户传入的file参数进行严格的过滤攻击者可以传入包含目录遍历序列如../的恶意参数。例如攻击者构造请求GET /download?file../../../etc/passwd。后端如果直接拼接路径就变成了/var/www/uploads/../../../etc/passwd。在操作系统进行路径解析时../表示上级目录经过解析最终访问的路径就变成了/etc/passwd从而成功越权读取了系统的密码文件。注意这里/etc/passwd只是一个经典示例实际中可能读取数据库配置文件如config.php、.env、日志文件、备份文件等危害极大。2.2 关键利用条件与绕过技巧并非所有存在路径拼接的地方都能被利用。成功利用CVE-2025-54100这类漏洞通常需要满足几个条件了解这些条件也是我们审计和防御的关键用户输入直接参与路径拼接这是前提。文件名、路径名等参数必须来自用户请求且未被充分过滤。应用具有读取文件的权限Web服务进程如www-data, nginx用户必须有权限读取目标敏感文件。路径解析发生在操作系统层面最终用于访问文件的系统调用如open()、readfile()接收的是拼接后的字符串并由操作系统内核进行解析。如果应用在自身逻辑层面对../进行了拦截但拦截逻辑有缺陷如只过滤一次就可能被绕过。常见的绕过技巧包括编码绕过使用URL编码%2e%2e%2f表示../、双重编码%252e%252e%252f或Unicode编码以绕过基于字符串匹配的简单过滤。**绝对路径覆盖**如果拼接逻辑是简单的字符串连接且基础目录处理不当攻击者可能直接传入绝对路径如/etc/passwd来覆盖整个基础路径。空字节截断在一些老旧或特定语言的处理中在路径后添加空字节%00可能截断后续的校验或追加的后缀。例如file../../../etc/passwd%00.jpg如果后端代码是base_path user_input “.jpg”空字节可能导致系统只读取/etc/passwd。理解这些原理后我们就能有的放矢地进行复现了。接下来我们将搭建一个模拟环境亲手触发这个漏洞。3. 实验环境搭建与漏洞复现实操为了安全、可重复地复现漏洞我们不会去找真实的受影响系统而是使用一个专门用于安全学习的漏洞靶场环境。这里我选择用Docker快速部署一个包含类似漏洞场景的靶场。3.1 环境准备与靶场部署首先确保你的实验机器上安装了Docker和Docker Compose。我们使用一个广受好评的Web安全学习平台——DVWADamn Vulnerable Web Application的Docker版本但它本身可能没有我们要的精确漏洞。因此我更倾向于使用一个专门训练路径遍历的靶场比如“Web Security Academy”的实验室环境或者自己构建一个简单的漏洞Demo。这里我演示如何快速构建一个最简单的漏洞Demo容器创建漏洞应用文件新建一个目录例如cve-2025-demo。mkdir cve-2025-demo cd cve-2025-demo编写有漏洞的PHP脚本创建index.php。?php // 模拟存在CVE-2025-54100漏洞的代码 $base_dir /var/www/html/uploads/; // 预设的基础目录 if (isset($_GET[file])) { $file $_GET[file]; // 直接获取用户输入未过滤 $path $base_dir . $file; // 危险的路径拼接 // 模拟读取文件内容真实漏洞可能直接输出文件 // 这里为了演示安全只显示路径不真正读取 echo 尝试访问的路径模拟 . htmlspecialchars($path) . br; echo 解析后的真实路径模拟 . htmlspecialchars(realpath($path)); } else { echo 请使用 ?filefilename 参数请求文件。; } ?实操心得在真实复现中我们可能需要一个真正会读取并返回文件内容的脚本。但为了绝对安全且聚焦于漏洞原理我们先使用这个“无害”的版本进行路径构造演示。后续可以替换为一个在严格隔离环境下真正有风险的脚本。编写Dockerfile创建Dockerfile。FROM php:8.2-apache RUN docker-php-ext-install mysqli docker-php-ext-enable mysqli COPY index.php /var/www/html/ RUN mkdir -p /var/www/html/uploads \ echo This is a safe upload file. /var/www/html/uploads/safe.txt \ echo Sensitive system file content (simulated) /etc/passwd_simulated # 注意我们复制了一个模拟的passwd文件避免触及真实系统文件构建并运行容器docker build -t cve-2025-demo . docker run -d -p 8080:80 --name cve-2025-lab cve-2025-demo现在访问http://localhost:8080/就能看到我们的漏洞演示页面了。3.2 漏洞验证与利用步骤环境就绪后我们开始验证和利用漏洞。正常功能测试首先测试正常功能。访问http://localhost:8080/?filesafe.txt。页面会显示拼接后的路径例如尝试访问的路径模拟 /var/www/html/uploads/safe.txt。这说明文件参数正常工作。基础路径遍历测试现在尝试利用漏洞。访问http://localhost:8080/?file../../../etc/passwd_simulated。观察结果页面显示的拼接路径会是/var/www/html/uploads/../../../etc/passwd_simulated而realpath函数解析后可能会显示/etc/passwd_simulated取决于容器内的路径存在性。这证明我们构造的路径成功穿越了目录指向了系统文件。关键点这里我们使用的是realpath函数来模拟操作系统解析后的结果。在真实漏洞中如果后端代码直接使用拼接路径去readfile()或file_get_contents()那么/etc/passwd或模拟文件的内容就会被输出到响应中。编码绕过测试假设原始代码有一个简单的过滤str_replace(../, , $file)。我们可以尝试编码绕过。访问http://localhost:8080/?file..%2f..%2f..%2fetc%2fpasswd_simulated%2f是/的URL编码。如果过滤逻辑没有解码后再过滤这个请求可能绕过检查。利用工具进行自动化探测在实际渗透测试中我们不会手动构造每一个Payload。可以使用 Burp Suite 的 Intruder 模块或者命令行工具如ffuf加载包含常见路径遍历Payload的字典进行模糊测试。# 使用ffuf进行模糊测试示例需安装ffuf ffuf -u http://localhost:8080/?fileFUZZ -w /path/to/traversal-payloads.txt -fs 0注意事项在测试真实目标前务必获得书面授权。未经授权的测试是违法行为。3.3 漏洞复现的深入从信息显示到内容读取我们之前的Demo只显示了路径。要完整复现“文件内容读取”的影响我们需要稍微修改一下漏洞脚本但必须在高度可控的环境下进行。以下操作仅在隔离的Docker实验容器中进行。修改index.php为有风险的版本仅用于教育目的?php $base_dir /var/www/html/uploads/; if (isset($_GET[file])) { $file $_GET[file]; $path $base_dir . $file; // 危险操作直接读取文件并输出 if (file_exists($path)) { header(Content-Type: text/plain); readfile($path); } else { echo File not found: . htmlspecialchars($path); } } ?重建并运行容器使用新的镜像名docker build -t cve-2025-demo-risky . docker run -d -p 8081:80 --name cve-2025-risky-lab cve-2025-demo-risky此时访问http://localhost:8081/?file../../../etc/passwd_simulated你将直接看到模拟的敏感文件内容被输出到浏览器。这就完整再现了CVE-2025-54100漏洞被成功利用后的效果。4. 代码审计视角如何发现此类漏洞复现漏洞之后我们更应该掌握如何主动发现它。从开发和安全审计的角度有以下关键检查点4.1 危险函数与代码模式识别在不同的编程语言中需要警惕的文件操作函数和模式语言危险函数/模式安全建议PHPfile_get_contents(),readfile(),include(),require()与用户输入直接拼接。使用basename()过滤文件名或使用白名单校验。include/require更危险可能导致代码执行。Javanew File(),FileInputStream,Paths.get()参数包含用户输入。使用Path.normalize()后与预设的基准路径Path.of(baseDir)进行解析检查规范化后的路径是否仍以基准路径开头。Pythonopen(),os.path.join()在拼接前未校验。send_file(Flask) 直接使用用户输入。使用os.path.normpath()后用os.path.commonprefix()或pathlib.Path的resolve()和is_relative_to()(Python 3.9) 检查是否在安全目录内。Node.jsfs.readFile(),path.join()与用户输入拼接。使用path.resolve()解析完整路径然后检查解析后的路径是否以安全目录的绝对路径开头。审计时在代码中全局搜索这些函数名并追踪其参数来源是快速定位潜在漏洞的有效方法。4.2 安全的路径校验实现方案发现危险代码后如何修复核心原则是白名单优于黑名单规范化后校验。方案一白名单机制最推荐如果业务上只允许访问有限的文件建立白名单是最安全的。$allowed_files [report.pdf, contract.docx, data.csv]; if (in_array($_GET[file], $allowed_files)) { $path $base_dir . $_GET[file]; // 安全地读取文件 } else { die(Access denied.); }方案二规范化后前缀校验通用方案当文件范围不固定时使用此方案。$user_input $_GET[file]; $base_dir /var/www/html/uploads/; // 1. 规范化路径 $full_path realpath($base_dir . $user_input); // 2. 检查规范化后的路径是否以基准路径开头 if ($full_path false || strpos($full_path, realpath($base_dir)) ! 0) { die(Invalid file path.); } // 3. 安全检查通过读取文件 readfile($full_path);重要提示realpath()函数会解析..和符号链接并返回绝对路径。校验strpos($full_path, realpath($base_dir)) 0确保最终路径没有“逃出”安全目录。注意realpath在文件不存在时返回false需要处理。5. 防御加固与安全开发实践理解了漏洞和审计方法最终目标是构建更安全的系统。以下是从开发到部署的全链路防御建议。5.1 开发阶段的安全编码规范最小化用户输入信任永远不要相信客户端传来的任何路径信息。视其为污染数据。使用安全的API尽可能使用框架提供的安全文件操作方法。例如在Spring框架中使用Resource接口在Flask中使用send_from_directory。实施严格的输入验证结合白名单首选和规范化校验。对于文件名可以校验其是否符合预期的字符集如字母、数字、连字符、下划线和长度。运行在最小权限下运行Web服务的操作系统用户如www-data、nginx应仅拥有对Web根目录及其子目录的必要读写权限绝不能以root身份运行。代码审查与自动化扫描将路径遍历漏洞检查项纳入代码审查清单。使用SAST静态应用安全测试工具如SonarQube、Checkmarx在CI/CD流水线中自动扫描代码。5.2 运维与部署层面的缓解措施即使应用代码存在隐患运维层面也能设置防线容器化与文件系统隔离使用Docker/Kubernetes等容器技术将应用运行在隔离的环境中。通过只读挂载read-only或绑定挂载bind mount严格控制容器内进程可访问的主机目录。Web服务器配置在Nginx或Apache配置中可以设置规则阻止请求中包含..的URL。Nginx示例location /download { if ($request_uri ~* \.\.) { return 403; } # ... 其他代理配置 }注意这只是一道辅助防线不能替代应用层校验因为攻击者可能使用编码绕过。文件系统权限加固确保Web根目录以外的敏感目录如/etc,/home,/root对Web服务进程用户不可读。部署WAFWeb应用防火墙配置成熟的WAF如ModSecurity规则集可以有效地拦截常见的路径遍历攻击Payload为存在漏洞的应用提供临时保护。5.3 漏洞修复后的验证流程修复漏洞后必须进行验证回归测试确保原有的正常文件下载功能不受影响。渗透复测使用之前成功的Payload如../../../etc/passwd及其各种编码变形进行测试确认均返回“拒绝访问”或“文件不存在”等错误而非文件内容。自动化扫描再次使用动态应用安全测试DAST工具或手动渗透测试工具对修复后的接口进行扫描。路径遍历漏洞就像一扇忘记上锁的后门攻击者一旦发现便可长驱直入。通过这次对CVE-2025-54100的深入复现与分析我们可以看到安全无小事往往就败在细节处理上。作为开发者在编写每一行处理用户输入的代码时都要心怀警惕作为安全人员则需要练就一双能快速识别这些危险模式的“火眼金睛”。防御的核心始终在于不信任任何外部输入并在最终执行操作前进行彻底的、基于规范化路径的校验。把这个案例的思路和方法带入你的日常工作和学习下次再看到文件下载、预览、模板包含这类功能时你就能本能地去思考这里的路径真的安全吗

相关新闻