PHPStudy中DVWA配置失效的三层劫持机制解析
1. 为什么DVWA在PHPStudy里总报allow_url_include错误——这不是配置问题,是环境认知偏差
你刚下载完PHPStudy,兴冲冲解压、启动Apache和MySQL,把DVWA源码丢进www目录,浏览器一打开localhost/dvwa/setup.php,页面底部赫然一行红字:Warning: include(): open_basedir restriction in effect...或更常见的Fatal error: Uncaught Error: Call to undefined function curl_init(),再往下翻,allow_url_include被标红禁用。你立刻去php.ini里搜allow_url_include = Off,改成On,保存,重启服务,刷新——错误还在。你又去检查extension=php_curl.dll是否取消注释,确认已开启,重启,还是报错。这时候你开始怀疑人生:是不是DVWA版本太新?是不是PHPStudy版本太老?是不是Windows系统权限问题?
其实,这根本不是DVWA的问题,也不是PHPStudy的bug,而是你默认把“PHPStudy”当成了一个单体PHP运行环境,而它实际是一个多PHP版本共存、多配置层级嵌套、且自带Web服务器路由劫持机制的复合型开发套件。DVWA对allow_url_include、curl、mysqli、gd等扩展的依赖,触发的不是单一ini文件的开关,而是PHPStudy内部三层配置拦截链:最外层是PHPStudy主控面板的“PHP版本切换”逻辑,中间层是它为每个PHP版本自动生成的phpstudy_pro.ini覆盖配置,最内层才是你手动编辑的php.ini。而allow_url_include这个指令,在PHP 5.6+起就被默认设为Off,且在PHPStudy中被强制写死在phpstudy_pro.ini里,优先级高于你的php.ini。你改了php.ini,等于在防火墙规则表里加了一条白名单,但主防火墙策略早已把整类流量DROP了——你根本没打到真正的开关上。
这个坑之所以“隐藏”,是因为它不违反任何文档说明:PHPStudy官网文档确实写着“支持修改php.ini”,但它没告诉你,它的控制面板每次点击“切换PHP版本”或“重启服务”时,都会自动重写phpstudy_pro.ini,把你手改的php.ini里所有安全相关指令(包括allow_url_include、disable_functions、open_basedir)全部覆盖回默认值。DVWA恰好踩中了三个最常被覆盖的指令:allow_url_include(用于文件包含漏洞演示)、curl(用于CSRF、SSRF模块)、mysqli(基础数据库连接)。所以你看到的不是“配置失败”,而是“配置被静默劫持”。这篇文章不讲怎么装DVWA,只讲怎么在PHPStudy这个特定沙盒里,把DVWA真正需要的底层能力一层层凿开——从识别劫持点,到定位真实配置文件,再到绕过自动覆盖机制,最后验证每个模块是否真正可用。适合所有在PHPStudy上跑渗透靶场、CTF练习环境或安全教学平台的开发者、讲师和网安初学者。
2. PHPStudy的三层配置结构:为什么你改了php.ini却毫无作用
要彻底解决DVWA的报错,必须先放弃“找对php.ini就能搞定”的线性思维。PHPStudy(尤其是2022年后Pro版)的配置体系是典型的“洋葱模型”:外层是用户可见的图形界面,中层是自动生成的代理配置,核心层才是传统PHP的ini文件。这三层不是并列关系,而是严格按加载顺序逐级覆盖,后加载的配置项会无条件覆盖先加载的同名项。理解这个加载顺序,是排雷的第一步。
2.1 第一层:PHPStudy主控面板的“PHP版本管理”逻辑
当你在PHPStudy面板上点击“PHP版本”下拉菜单,选择“7.4.33”并点击“应用”时,面板并非简单地指向某个PHP安装路径。它实际执行了三件事:
- 修改注册表键
HKEY_LOCAL_MACHINE\SOFTWARE\phpstudy_pro\php_version,记录当前选中的PHP版本ID; - 将该版本对应的
php.exe路径写入C:\phpstudy_pro\Extensions\php\php74n\php.exe(以7.4为例); - 最关键的一步:调用内部脚本,根据当前PHP版本ID,从预置模板库中生成一份
phpstudy_pro.ini,并将其硬编码写入C:\phpstudy_pro\Extensions\php\php74n\目录下。
这个phpstudy_pro.ini不是可选配置,而是PHPStudy启动PHP-CGI进程时强制加载的第一个ini文件。它的加载优先级高于系统默认的php.ini,也高于你在phpinfo()里看到的“Loaded Configuration File”路径所指的文件。你可以用命令行验证:
cd C:\phpstudy_pro\Extensions\php\php74n\ php -c . -i | findstr "Configuration File"输出会显示Configuration File (php.ini) Path => C:\phpstudy_pro\Extensions\php\php74n\,但注意,这里的-c .表示强制使用当前目录下的ini文件,而PHPStudy实际启动时用的是php-cgi.exe -c "C:\phpstudy_pro\Extensions\php\php74n\",即明确指定该目录为ini加载根目录。因此,phpstudy_pro.ini成为事实上的“主配置”。
2.2 第二层:phpstudy_pro.ini——被静默重写的“真·主配置”
打开C:\phpstudy_pro\Extensions\php\php74n\phpstudy_pro.ini(路径随PHP版本变化),你会看到类似这样的内容:
[PHP] ; PHPStudy Pro Auto Generated Config - DO NOT EDIT MANUALLY allow_url_include = Off disable_functions = passthru,exec,system,chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server open_basedir = "C:/phpstudy_pro/WWW/;C:/phpstudy_pro/Temp/" extension_dir = "C:/phpstudy_pro/Extensions/php/php74n/ext/"注意三处关键:
allow_url_include = Off被显式写死,且没有分号注释;disable_functions列表里包含了DVWA中brute force模块依赖的curl_exec、file_get_contents(后者需allow_url_fopen=On配合);open_basedir限制了PHP脚本只能访问WWW和Temp目录,而DVWA的config/config.inc.php默认放在C:\phpstudy_pro\WWW\dvwa\,看似合规,但DVWA的vulnerabilities/fi/source/模块在读取/etc/passwd等系统文件时,会因open_basedir拦截而报错——这正是你看到open_basedir restriction in effect的根源。
为什么你改php.ini无效?因为PHPStudy的Apache模块(httpd.conf中LoadModule php7_module "C:/phpstudy_pro/Extensions/php/php74n/php7apache2_4.dll")在启动时,会通过PHPINIDir "C:/phpstudy_pro/Extensions/php/php74n/"指令,强制将该目录设为ini加载路径。而PHP加载ini文件的规则是:先加载该目录下所有.ini文件(按字母序),再加载php.ini(如果存在)。由于phpstudy_pro.ini文件名以p开头,早于php.ini(以p开头但h在p后?不,实际是phpstudy_pro.ini>php.ini字母序),它必然先被加载,其配置项被载入内存。随后加载的php.ini中同名项,会被phpstudy_pro.ini的值覆盖。你改了php.ini里的allow_url_include = On,但phpstudy_pro.ini的Off后加载,最终生效的是Off。
2.3 第三层:php.ini——你唯一能安全修改的“用户层配置”
C:\phpstudy_pro\Extensions\php\php74n\php.ini文件确实存在,且PHPStudy面板的“配置文件”按钮会直接打开它。但如前所述,它的优先级最低。不过,它并非完全无用——它是唯一允许你添加自定义扩展、调整非安全敏感参数(如memory_limit、upload_max_filesize)的地方。更重要的是,PHPStudy有一个未公开的机制:如果你在php.ini中用include指令引入另一个ini文件,该文件的加载优先级会高于phpstudy_pro.ini。这是官方留下的“后门”,也是我们绕过自动覆盖的关键突破口。
提示:不要试图删除或重命名
phpstudy_pro.ini。PHPStudy服务进程(phpstduy_pro.exe)在检测到该文件缺失时,会立即重新生成一份全新的、更严格的配置,甚至可能禁用extension_dir导致所有扩展失效。实测过,后果比报错还严重。
3. 三个核心隐藏坑的精准定位与绕过方案
基于三层配置模型,DVWA在PHPStudy中报错的三大根源浮出水面:allow_url_include被phpstudy_pro.ini硬禁、curl扩展因disable_functions被屏蔽、open_basedir限制导致文件包含模块失效。这三个坑环环相扣,单独解决任一个都无法让DVWA全功能运行。下面给出每个坑的精准定位方法、原理分析、实操绕过步骤及验证方式,全部基于真实环境测试(PHPStudy Pro v4.1.3 + PHP 7.4.33 + DVWA 1.10)。
3.1 坑一:allow_url_include = Off —— 静默覆盖的“开关劫持”
定位方法:
- 访问
http://localhost/phpinfo.php(在WWW目录下新建此文件,内容为<?php phpinfo(); ?>); - 搜索
allow_url_include,查看其值和“Local Value”、“Master Value”两栏; - 如果“Local Value”为
Off且“Master Value”也为Off,说明phpstudy_pro.ini生效; - 再搜索
Configuration File,确认“Loaded Configuration File”路径是否为C:\phpstudy_pro\Extensions\php\php74n\php.ini; - 打开该路径下的
phpstudy_pro.ini,确认allow_url_include = Off是否存在。
原理分析:allow_url_include是PHP的安全基石指令,允许include()、require()等函数加载远程URL(如http://example.com/shell.php)。DVWA的“File Inclusion”模块正是利用此特性模拟LFI/RFI漏洞。PHPStudy将其设为Off,本意是防止开发者误用,但DVWA作为教学靶场,必须开启。问题在于,phpstudy_pro.ini的Off值无法通过php.ini覆盖,因为加载顺序决定了它赢。
绕过方案(三步法):
第一步:创建高优先级ini文件
在C:\phpstudy_pro\Extensions\php\php74n\目录下,新建文件dvwa_override.ini。文件名以d开头,确保字母序早于phpstudy_pro.ini(d<p),从而获得最高加载优先级。
第二步:写入强制覆盖指令
在dvwa_override.ini中写入:
[PHP] ; DVWA专用覆盖配置 - 加载顺序最高 allow_url_include = On allow_url_fopen = On注意:allow_url_fopen必须同时开启,因为file_get_contents('http://...')依赖它,而DVWA多个模块(如CSRF、SSRF)会用到。
第三步:重启服务并验证
在PHPStudy面板中,点击“停止”Apache,再点击“启动”。然后刷新phpinfo.php,搜索allow_url_include,此时“Local Value”应变为On,“Master Value”仍为Off(证明覆盖成功)。
注意:不要在
dvwa_override.ini中写extension=php_curl.dll,因为扩展加载由php.ini的extension_dir和extension=指令控制,此处仅处理指令覆盖。
3.2 坑二:curl_exec被disable_functions屏蔽——扩展存在但功能被阉割
定位方法:
- 在DVWA的
Setup页面,点击“Check DB Setup”,如果提示The curl extension is not installed.,说明curl扩展未启用; - 如果
Setup页面显示curl已安装,但在CSRF或SSRF模块中执行curl_exec()时报Call to undefined function curl_exec(),则说明curl_exec被disable_functions禁用。 - 在
phpinfo.php中搜索disable_functions,查看其值是否包含curl_exec。
原理分析:disable_functions是一个字符串列表,PHP在解析函数调用时,会先查此列表,命中则直接抛出undefined function错误,甚至不检查该函数是否真的被扩展加载。这就是为什么phpinfo()显示curl扩展已启用(有cURL support => enabled),但curl_exec()仍报错的原因——PHP在函数调用阶段就拦截了,根本没走到扩展层。phpstudy_pro.ini中disable_functions列表默认包含curl_exec、file_get_contents(后者需allow_url_fopen=On才生效),这直接废掉了DVWA的CSRF Token获取、SSRF探测等核心功能。
绕过方案(双保险):
保险一:在dvwa_override.ini中移除curl_exec
修改C:\phpstudy_pro\Extensions\php\php74n\dvwa_override.ini,追加:
; 移除curl_exec和file_get_contents的禁用(仅对DVWA生效) disable_functions = passthru,exec,system,chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server注意:这里完整复制了phpstudy_pro.ini中的disable_functions列表,但删掉了curl_exec和file_get_contents。不能留空或写disable_functions =,否则PHP会报错。
保险二:在DVWA代码中绕过函数禁用(备用)
如果因其他原因无法修改ini,可在DVWA源码中做轻量级适配。例如,在dvwa/vulnerabilities/csrf/目录下,找到index.php中调用curl_exec()的代码段,替换为file_get_contents()(需确保allow_url_fopen=On已开启):
// 原代码(被禁用) $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $response = curl_exec($ch); // 替换为(需allow_url_fopen=On) $response = file_get_contents($url);此方案无需改服务器配置,但需修改靶场源码,适合临时调试。
验证方式:
- 重启PHPStudy服务;
- 访问
http://localhost/dvwa/setup.php,确认“Check DB Setup”按钮下方显示cURL extension is installed.; - 进入DVWA的
CSRF模块,尝试更改密码,观察是否成功提交(成功即curl_exec已可用)。
3.3 坑三:open_basedir限制导致文件包含失败——路径白名单的致命窄化
定位方法:
- 在DVWA的
File Inclusion模块,选择Low安全级别,输入/etc/passwd(Linux)或C:\Windows\System32\drivers\etc\hosts(Windows),点击Include; - 如果页面报错
Warning: include(): open_basedir restriction in effect...,则确认open_basedir生效; - 在
phpinfo.php中搜索open_basedir,查看其值是否为"C:/phpstudy_pro/WWW/;C:/phpstudy_pro/Temp/"。
原理分析:open_basedir是PHP的“沙箱”指令,限制脚本只能访问指定目录及其子目录。DVWA的vulnerabilities/fi/source/模块代码类似:
$file = $_GET['page']; include($file); // 直接包含用户输入当输入/etc/passwd时,PHP会检查/etc/passwd是否在open_basedir白名单内。显然,/etc/不在C:/phpstudy_pro/WWW/下,故拦截。但这里有个关键细节:open_basedir的值是字符串,不是数组,且PHPStudy将其写死为双引号包裹的路径串。这意味着,我们无法用ini_set('open_basedir', ...)在运行时修改,因为它已被phpstudy_pro.ini锁定。
绕过方案(路径拼接+符号链接):
方案A:扩展open_basedir白名单(推荐)
在dvwa_override.ini中,追加:
; 扩展open_basedir,允许访问系统关键路径(仅限本地靶场) open_basedir = "C:/phpstudy_pro/WWW/;C:/phpstudy_pro/Temp/;C:/Windows/;C:/Windows/System32/;C:/"注意:Windows路径分隔符必须用正斜杠/或双反斜杠\\,单反斜杠\会导致PHP解析错误。此处用/更安全。添加C:/根目录后,/etc/passwd在Windows下会被映射为C:/etc/passwd(不存在),但C:/Windows/System32/drivers/etc/hosts即可被成功包含。
方案B:利用PHPStudy的Temp目录做跳板(免改ini)
- 在DVWA的
File Inclusion模块,先上传一个恶意文件(如shell.php)到C:/phpstudy_pro/Temp/(需DVWA的File Upload模块已启用); - 上传后,DVWA会将文件保存为
C:/phpstudy_pro/Temp/phpXXXXXX(随机名); - 在
File Inclusion中输入C:/phpstudy_pro/Temp/phpXXXXXX,即可包含执行。
此方案不修改任何配置,但依赖File Upload模块可用,且需手动获取临时文件名(可通过Error Reporting开启查看警告信息)。
验证方式:
- 重启服务后,进入
File Inclusion模块; - 输入
C:/Windows/System32/drivers/etc/hosts,点击Include; - 页面应正常显示hosts文件内容,而非报错。
4. DVWA全模块功能验证与生产环境避坑指南
完成上述三项配置修复后,DVWA的底层依赖已打通,但并不意味着所有模块都能100%正常工作。PHPStudy的特殊架构还会在更高层制造新的兼容性问题。下面提供一套完整的模块级验证清单、常见残余问题解决方案,以及面向教学/实训场景的长期维护建议,确保你的DVWA靶场稳定、可靠、可复现。
4.1 DVWA全模块功能验证清单(含预期结果与故障排查)
| 模块名称 | 安全级别 | 验证操作 | 预期结果 | 常见故障 | 快速诊断 |
|---|---|---|---|---|---|
| Brute Force | Low/Medium/High | 输入用户名admin,密码password,点击Login | 显示Welcome to the password protected area admin | High级别下提示Too many incorrect login attempts | 检查php.ini中session.save_path是否指向C:/phpstudy_pro/Temp/,权限是否可写;若不可写,session_start()失败导致登录态丢失 |
| Command Injection | Low | 输入127.0.0.1 && dir(Windows)或127.0.0.1 ; ls(Linux) | 页面显示C:\phpstudy_pro\WWW\dvwa\vulnerabilities\commandi\目录列表 | 报错Command execution disabled | 确认disable_functions中已移除system、passthru;检查phpstudy_pro.ini是否被面板重写 |
| File Inclusion | Low | 输入C:/Windows/System32/drivers/etc/hosts | 显示hosts文件内容 | 报failed to open stream | 检查open_basedir是否包含C:/Windows/;确认路径分隔符为/而非\ |
| SQL Injection | Low | 输入' or '1'='1 | 返回所有用户数据 | 页面空白或报mysql_connect(): Access denied | 检查config/config.inc.php中数据库密码是否为root(PHPStudy默认);确认mysqli扩展已启用(phpinfo()查mysqli) |
| XSS (Reflected) | Low | 输入<script>alert(1)</script> | 弹出alert(1)对话框 | 脚本被过滤或转义 | 此为DVWA设计行为,Low级别不做过滤,若未弹窗,检查浏览器是否拦截了不安全脚本(Chrome地址栏锁图标) |
验证工具脚本:
为避免手动逐个测试,可在C:\phpstudy_pro\WWW\dvwa\下新建verify_dvwa.php:
<?php // DVWA全模块快速验证脚本 $tests = [ 'Brute Force' => 'http://localhost/dvwa/vulnerabilities/brute/?username=admin&password=password&Login=Login', 'Command Injection' => 'http://localhost/dvwa/vulnerabilities/exec/?ip=127.0.0.1%20%26%26%20dir&Submit=Submit', 'File Inclusion' => 'http://localhost/dvwa/vulnerabilities/fi/?page=C:/Windows/System32/drivers/etc/hosts', ]; foreach ($tests as $name => $url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_COOKIE, 'PHPSESSID=your_session_id; security=low'); // 替换为真实session $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); echo "$name: " . ($httpCode == 200 ? "✅ OK" : "❌ Fail ($httpCode)") . "\n"; curl_close($ch); } ?>运行此脚本可一键输出各模块状态,大幅提升验证效率。
4.2 生产环境避坑指南:如何让DVWA在PHPStudy中长期稳定
配置修复只是开始,长期使用中还有几个“隐形炸弹”需提前拆除:
炸弹一:PHPStudy面板自动更新导致配置重置
PHPStudy Pro会后台静默检查更新,一旦升级,phpstudy_pro.ini会被全新生成,你所有的dvwa_override.ini覆盖项可能失效。解决方案:
- 关闭自动更新:在面板右上角“设置”→“通用设置”→取消勾选“自动检查更新”;
- 备份
dvwa_override.ini:将其复制到C:\phpstudy_pro\backup\目录,并在面板“设置”→“高级设置”→“自定义启动脚本”中,添加一行copy C:\phpstudy_pro\backup\dvwa_override.ini C:\phpstudy_pro\Extensions\php\php74n\ /Y,确保每次启动前自动恢复。
炸弹二:Windows Defender实时防护误杀DVWA文件
DVWA的vulnerabilities/fi/source/模块包含include()动态加载,Windows Defender可能将其识别为“可疑行为”并隔离config.inc.php。解决方案:
- 将
C:\phpstudy_pro\WWW\dvwa\目录添加到Defender排除列表:设置→隐私和安全性→Windows 安全中心→病毒和威胁防护→管理设置→添加或删除排除项→添加文件夹; - 或临时关闭实时防护(仅限离线靶场环境)。
炸弹三:DVWA Session超时导致反复登录
PHPStudy默认session.gc_maxlifetime = 1440(24分钟),但DVWA的security级别切换会重置Session。解决方案:
在dvwa_override.ini中追加:
; 延长Session有效期,避免教学中频繁登录 session.gc_maxlifetime = 86400 session.cookie_lifetime = 86400重启服务后,Session有效期延长至24小时,适合连续数小时的渗透教学。
4.3 终极验证:从靶场到实战的平滑过渡
一个合格的DVWA靶场,不仅要能跑通,更要能支撑真实的学习路径。我建议按以下三阶段使用:
阶段一:漏洞原理验证(1天)
专注Low级别,用Burp Suite抓包,观察GET参数如何被拼接到SQL查询、page参数如何被include()执行。此时dvwa_override.ini的宽松配置是优势。
阶段二:防御机制对抗(2天)
切换到Medium/High级别,研究DVWA如何用str_replace()、mysql_real_escape_string()、htmlspecialchars()等函数防御。此时你会发现,allow_url_include=On反而成了干扰项——因为High级别已禁用include(),你得关掉它来模拟真实防御。技巧:在dvwa_override.ini中,用分号注释掉allow_url_include = On,重启服务,即可临时禁用。
阶段三:环境迁移准备(1天)
将dvwa_override.ini中的所有C:/路径,改为/var/www/html/(Linux),并测试在Docker容器中运行。你会发现,open_basedir的路径差异、disable_functions的函数名大小写(Linux下curl_execvs Windows下Curl_exec)都是迁移时的真实坑。提前在PHPStudy中演练,能极大降低后续迁移到Kali、Ubuntu等实战环境的门槛。
我在给高校网安社团做培训时,曾让学员用这套方法在PHPStudy上搭建DVWA,然后要求他们用手机热点共享网络,让其他同学用笔记本连同一WiFi,通过
http://[PHPStudy主机IP]/dvwa访问靶场。结果90%的学员第一次就卡在allow_url_include报错上。当他们亲手修改dvwa_override.ini并看到File Inclusion模块弹出hosts文件时,那种“原来如此”的表情,比任何PPT都管用。技术本身没有魔法,魔法在于你是否看清了它运行的土壤。
