漏洞信息

在4.8.3之前在phpMyAdmin中发现了一个问题。已发现跨站点脚本漏洞,攻击者可以使用精心设计的文件来操作通过导入功能加载该文件的经过身份验证的用户
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15605

影响版本

phpmyadmin< 4.8.3

复现

环境搭建

惯例 上docker

mysql
docker run --name mysql2 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=a7552659 -d mysql:5.7

phpmyadmin
docker run --name admin -d --link mysql2:db -p 8080:80 phpmyadmin/phpmyadmin:4.8.2

然后就可以在127.0.0.1:8080访问到了

拷贝代码分析
git clone https://github.com/phpmyadmin/phpmyadmin

代码简单分析

查看修复提交 https://github.com/phpmyadmin/phpmyadmin/commit/00d90b3ae415b31338f76263359467a9fbebd0a1

只修改了一行
libraries/classes/Sql.php
$message = Message::notice($warning);->$message = Message::notice(Message::sanitize($warning));

那么很明显漏洞点就是这里

查看$warning引入点
第2220行 $warning_messages = $operations->getWarningMessagesArray();

跳入getWarningMessagesArray();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public function getWarningMessagesArray()
{
$warning_messages = array();
foreach ($GLOBALS['dbi']->getWarnings() as $warning) {
// In MariaDB 5.1.44, when altering a table from Maria to MyISAM
// and if TRANSACTIONAL was set, the system reports an error;
// I discussed with a Maria developer and he agrees that this
// should not be reported with a Level of Error, so here
// I just ignore it. But there are other 1478 messages
// that it's better to show.
if (! (isset($_REQUEST['new_tbl_storage_engine'])
&& $_REQUEST['new_tbl_storage_engine'] == 'MyISAM'
&& $warning['Code'] == '1478'
&& $warning['Level'] == 'Error')
) {
$warning_messages[] = $warning['Level'] . ': #' . $warning['Code']
. ' ' . $warning['Message'];
}
}
return $warning_messages;
}

是从getWarnings()引入 查找定义
虽然IDE不能直接跳转getWarnings() 使用全局搜索 也能找到在
libraries\classes\DatabaseInterface.php

1
2
3
4
public function getWarnings($link = DatabaseInterface::CONNECT_USER)
{
return $this->fetchResult('SHOW WARNINGS', null, null, $link);
}

fetchResult实际上是一个sql查询 在这里的语句是SHOW WARNINGS

漏洞源找到了 查看getWarningMessagesArray的调用
这里直接给出
文件import.php 718行->executeQueryAndGetQueryResponse->getWarningMessagesArray

查看调用上下文 赋值给了$html_output
然后直接调用$response->addHTML($html_output);

查看

1
2
3
4
5
6
7
8
9
10
11
12
public function addHTML($content)
{
if (is_array($content)) {
foreach ($content as $msg) {
$this->addHTML($msg);
}
} elseif ($content instanceof Message) {
$this->_HTML .= $content->getDisplay();
} else {
$this->_HTML .= $content;
}
}

无任何过滤 直接添加到html内容

那么如何注入payload呢,我们查看mysql文档(实际上我是先谷歌了一下) 发现有signal 来产生警告文本

我们写一个sql文件 然后通过导入功能导入 成功弹窗
poc SIGNAL SQLSTATE '01000' SET MESSAGE_TEXT = 'Warning: </p><script>alert("xss")</script>';

后言

这个漏洞影响/危害都不大 利益条件非常苛刻 毕竟都让人执行sql文件了
形成原因其实完全是程序员疏忽 以为这里警告信息是安全的 没加过滤