安全研究

安全漏洞
PHPWind多个文件包含漏洞

发布日期:2010-01-11
更新日期:2010-01-11

受影响系统:
PHPWind PHPWind 7.5
描述:
PHPWind是一款国内比较流行的基于PHP的Web论坛程序。

PHPWind的api/class_base.php、apps/share/index.php、apps/groups/index.php页面的多个本地和远程文件包含漏洞导致执行任意PHP代码。

1. api/class_base.php文件中callback函数没有正确地过滤$mode变量,导致任意包含本地文件,从而可以执行任意PHP命令。

在api/class_base.php文件中:

    function callback($mode, $method, $params) {
        if (!isset($this->classdb[$mode])) {
            if (!file_exists(R_P.'api/class_' . $mode . '.php')) {
                return new ErrorMsg(API_MODE_NOT_EXISTS, "Class($mode) Not Exists");
            }
            require_once(R_P.'api/class_' . $mode . '.php'); //这里
            $this->classdb[$mode] = new $mode($this);
        }
        if (!method_exists($this->classdb[$mode], $method)) {
            return new ErrorMsg(API_METHOD_NOT_EXISTS, "Method($method of $mode) Not Exists");
        }
        !is_array($params) && $params = array();
        return @call_user_func_array(array(&$this->classdb[$mode], $method), $params);
    }

继续跟具体变量传递的过程,上面的函数在run()里有调用:

    function run($request) {
        $request = $this->strips($request);
        if (isset($request['type']) && $request['type'] == 'uc') {
            $this->type        = 'uc';
            $this->apikey    = $GLOBALS['uc_key'];//注意这个变量也是该漏洞的关键
        } else {
            $this->type        = 'app';
            $this->apikey    = $GLOBALS['db_siteownerid'];
            $this->siteappkey = $GLOBALS['db_siteappkey'];
        }
        /***
        if ($this->type == 'app' && !$GLOBALS['o_appifopen']) {
            return new ErrorMsg(API_CLOSED, 'App Closed');
        }
        ***/
        ksort($request);
        reset($request);
        $arg = '';
        foreach ($request as $key => $value) {
            if ($value && $key != 'sig') {
                $arg .= "$key=$value&";
            }
        }
        if (md5($arg . $this->apikey) != $request['sig']) { //注意这个判断,需要绕过它.上面的代码可以看的出来$this->apikey    = $GLOBALS['uc_key'],和$request['sig']我们
                                                            //都可以控制,那么很容易绕过它
            return new ErrorMsg(API_SIGN_ERROR, 'Error Sign');
        }
        $mode    = $request['mode']; //取$mode 没有过滤直接进入下面的callback()
        $method    = $request['method'];
        $params = isset($request['params']) ? unserialize($request['params']) : array();
        if (isset($params['appthreads'])) {
            if (PHP_VERSION < 5.2) {
                require_once(R_P.'api/class_json.php');
                $json = new Services_JSON(true);
                $params['appthreads'] = $json->decode(@gzuncompress($params['appthreads']));
            } else {
                $params['appthreads'] = json_decode(@gzuncompress($params['appthreads']),true);
            }
        }
        if ($params && isset($request['charset'])) {
            $params = pwConvert($params, $this->charset, $request['charset']);
        }
        return $this->callback($mode, $method, $params); //调用callback ()
    }

继续看run()函数的调用,在pw_api.php文件中:

$api = new api_client();
$response = $api->run($_POST + $_GET);//直接run了$_POST , $_GET提交的变量.

上面的分析是逆向分析了整个漏洞变量提交的过程,这个漏洞还包含一次编码与解码的问题:require_once(R_P.'api/class_' . $mode . '.php');。这个需要绕过魔术引号才可以包含文件。注意看run()的第一句:

$request = $this->strips($request);

strips()的代码:

    function strips($param) {
        if (is_array($param)) {
            foreach ($param as $key => $value) {
                $param[$key] = $this->strips($value);
            }
        } else {
            $param = stripslashes($param); //变量直接使用了stripslashes,那么我们可以直接绕过魔术引号了 :)
        }
        return $param;
    }

2. apps/share/index.php中$route和$basePath变量没有初始化,导致远程包含或者本地包含php文件。

<?php
if ($route == "share") {
    require_once $basePath . '/action/m_share.php';
} elseif ($route == "sharelink") {
    require_once $basePath . '/action/m_sharelink.php';
}
?>

3. apps/groups/index.php中$route和$basePath变量没有初始化,导致远程包含或者本地包含php文件。

<?php
if ($route == "groups") {
require_once $basePath . '/action/m_groups.php';
} elseif ($route == "group") {
require_once $basePath . '/action/m_group.php';
} elseif ($route == "galbum") {
require_once $basePath . '/action/m_galbum.php';
}

<*来源:80vul
  
  链接:http://www.80vul.com/pwvul/phpwind.txt
*>

建议:
厂商补丁:

PHPWind
-------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

http://www.phpwind.net/read-htm-tid-914851.html

浏览次数:3861
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障