PHPmyadmin SQL injection in Designer feature 研究(CVE-2019-18622)

本文最后更新于 2019.12.21,总计 6812 字 ,阅读本文大概需要 6 ~ 23 分钟
本文已超过 1586天 没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

目录

0x01 漏洞描述

cve 编号:CVE-2019-18622

4.9.2之前的phpMyAdmin中发现了一个问题。 攻击者通过精心设计的数据库名或者表名,可通过设计器功能触发SQL注入攻击。

官方信息

PMASA-2019-5

Announcement-ID: PMASA-2019-5

Date: 2019-10-28

Summary

Designer功能中的SQL注入

Description

提出了一个漏洞,攻击者可以使用特制的数据库名称,通过设计器功能来触发SQL注入攻击。

这类似于PMASA-2019-2和PMASA-2019-3,但影响了不同的版本。

Severity

我们认为此漏洞很严重

Affected Versions

4.9.2之前的phpMyAdmin版本会受到影响,至少影响到4.7.7。

0x02 漏洞分析

首先看官方修复的方式:

1.png

如上图,先关注/js/designer/move.js文件,可以看到单纯的修改了取值方式,最终的值通过POST 方式提交到db_desingner.php文件,关键内容如下:

if (isset($_POST['dialog'])) {

     ....
       
    } elseif ($_POST['dialog'] == 'add_table') {
        // Pass the db and table to the getTablesInfo so we only have the table we asked for
        $script_display_field = $designerCommon->getTablesInfo($_POST['db'], $_POST['table']);
     ...
}

传到了getTablesInfo()函数中,该函数内容主要如下:

public function getTablesInfo($db = null, $table = null)
    {
        .....
        foreach ($tables as $one_table) {
            $DF = $this->relation->getDisplayField($db, $one_table['TABLE_NAME']);
            $DF = is_string($DF) ? $DF : '';
            $DF = ($DF !== '') ? $DF : null;
            $designerTables[] = new DesignerTable(
                                    $db,
                                    $one_table['TABLE_NAME'],
                                    $one_table['ENGINE'],
                                    $DF
                                );
        }

        return $designerTables;
    }

跟进getDisplayField(),内容如下:

 public function getDisplayField($db, $table)
    {
        $cfgRelation = $this->getRelationsParam();

        /**
         * Try to fetch the display field from DB.
         */
        if ($cfgRelation['displaywork']) {
            $disp_query = '
                SELECT `display_field`
                FROM ' . Util::backquote($cfgRelation['db'])
                    . '.' . Util::backquote($cfgRelation['table_info']) . '
                WHERE `db_name`    = \'' . $GLOBALS['dbi']->escapeString($db) . '\'
                    AND `table_name` = \'' . $GLOBALS['dbi']->escapeString($table)
                . '\'';

            $row = $GLOBALS['dbi']->fetchSingleRow(
                $disp_query, 'ASSOC', DatabaseInterface::CONNECT_CONTROL
            );
            if (isset($row['display_field'])) {
                return $row['display_field'];
            }
        }
   ....

通过escapeString过滤 table 名,查看该过滤函数:

public function escapeString($link, $str)
    {
        return mysql_real_escape_string($str, $link);
    }

引入了mysql_real_escape_string()函数

这个函数类似于addslashes()函数,当编码不当的时候,可能导致宽字节注入

但真的那么简单吗?继续往下看

这里获得的table_name 参数会传入以下语句:

SELECT *, `COLUMN_NAME` AS `Field`, `COLUMN_TYPE` AS `Type`, `COLLATION_NAME` AS `Collation`, `IS_NULLABLE` AS `Null`, `COLUMN_KEY` AS `Key`, `COLUMN_DEFAULT` AS `Default`, `EXTRA` AS `Extra`, `PRIVILEGES` AS `Privileges`, `COLUMN_COMMENT` AS `Comment` FROM `information_schema`.`COLUMNS` WHERE `TABLE_SCHEMA` = 'day1' AND `TABLE_NAME` = '$table_name';

这里的$table_namedb_designer.php中可控,然而当环境准备好,语句配置好后,却出现了以下错误:

2.png

JSON encoding failed: Malformed UTF-8 characters, possibly incorrectly encoded

提示是因为编码问题,因此我们重新将 payload url 编码后再传入:

3.png

这次无误,查看执行的语句:

4.png

%df%27并没有按照我们想法闭合单引号,到底是什么原因呢?

5.png

在数据库连接的时候,phpmyadmin会将默认的字符格式设置为 utf8mb4,而我们宽字节注入必须要求编码为g bk,因此其实这里不存在宽字节注入。

说明这里的修复对SQL 漏洞并无多大关系(其实从修复文件上看,就知道了),继续看下一处修复。

/templates/database/designer/database_tables.twig

diff 如下:

-                    {{ designerTable.getTableName()|raw }}
+                    {{ designerTable.getTableName() }}

可以看到,唯一的差别就是删除了|raw,这种写法是Twig模板语言的写法,raw 的作用就是让数据在 autoescape 过滤器里失效,可以安装一个 twig 模板看看实例。

composer require "twig/twig:^3.0"

6.png

运行命令后该目录下会生成2个文件:composer.jsoncomposer.lock以及一个目录vendor

然后在同目录下创建文件夹templatestmp

进入templates目录下创建index.html.twig文件,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>twig</title>
</head>
<body>
<h1>test</h1><br>
 {{ name |raw}}
<br>
{{ name }}
</body>
</html>

根目录下创建index.php,内容如下:

<?php

require_once 'vendor/autoload.php';

$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader, [
    'cache' => '/Library/WebServer/Documents/twig/tmp',
]);

echo $twig->render('index.html.twig', ['name' => 'panda\' union select 1,2, from a']);

访问 index.php 可以发现:

7.png

单引号被转义成了实体字符

修复的 SQL 漏洞点在这里吗?

并不是。这里修复的仅仅是前端显示字符串的问题,与后端的 sql 注入也并无关系。

前文中提到的move.js修复的也是前端的内容,其实也和后端的 sql 注入并无关系。

那么这个修复方式和 sql 注入到底是什么关系呢?

可能没关系吧。

考虑到该修复内容全部为前端的内容,于是将表名改为 XSS 的 payload:

<script>alert(0)</script>

果然,和当初想的一样,触发了 XSS 漏洞。

8.png

9.png

然后看v4.9.2版本的 phpmyadmin:

10.png

11.png

转义成实体字符,无法触发 XSS 攻击 payload

0x03 总结

本以为是一次 SQL 的复现,变成了 XSS 漏洞的复现,也不得不怀疑到底是自己错了,还是官方公告有问题

然后看了官方公布的另一个 CVE:CVE-2019-11768

12.png

查看其修复方式:

13.png

同样,实际上修复的就是 XSS 漏洞,至于官方为什么声明是 SQL 漏洞,就不得而知了

0x04 参考

https://www.phpmyadmin.net/security/PMASA-2019-3/

https://www.phpmyadmin.net/security/PMASA-2019-5/

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18622

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11768

https://twig.symfony.com/doc/3.x/filters/raw.html

https://twig.symfony.com/doc/3.x/tags/autoescape.html

https://github.com/phpmyadmin/phpmyadmin/commit/c1ecafc38319e8f768c9259d4d580e42acd5ee86

https://gist.github.com/ibennetch/4ba7d2fac6f384a5039d697a110e0912

「感谢老板送来的软糖/蛋糕/布丁/牛奶/冰阔乐!」

panda

(๑>ڡ<)☆谢谢老板~

使用微信扫描二维码打赏

版权属于:

panda | 热爱安全的理想少年

本文链接:

https://www.cnpanda.net/sec/639.html(转载时请注明本文出处及文章链接)

暂时无法评论哦~

暂无评论