IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    PHPCMS V9最新版本后台设计缺陷导致getshell

    没穿底裤发表于 2016-09-19 01:16:01
    love 0

    from:http://www.cnbraid.com/2016/09/14/phpcms/

    0x01 背景

    周末审计了下phpcms的最新版本,前台已经很难找到漏洞了,故看了看后台相关的代码,发现还是有一处可以拿shell的漏洞。由于默认安装后需要超级管理员权限,故该漏洞很鸡肋,但感觉应该会在其它cms中也存在,所以主要分享下挖掘思路~
    PS:使用的测试环境是php5.6(已经移除gpc选项)

    01

    0x02 漏洞分析

    漏洞起源:
    yoursite\phpsso_server\phpcms\modules\admin\system.php下的uc函数:

    <?php
    public function uc() {
    	if (isset($_POST['dosubmit'])) {
    		$data = isset($_POST['data']) ? $_POST['data'] : '';
    		$data['ucuse'] = isset($_POST['ucuse']) && intval($_POST['ucuse']) ? intval($_POST['ucuse']) : 0;
    		$filepath = CACHE_PATH.'configs'.DIRECTORY_SEPARATOR.'system.php';
    		$config = include $filepath;
    		$uc_config = '<?php '."\ndefine('UC_CONNECT', 'mysql');\n";
    		foreach ($data as $k => $v) {
    			$old[] = "'$k'=>'".(isset($config[$k]) ? $config[$k] : $v)."',";
    			$new[] = "'$k'=>'$v',";
    			$uc_config .= "define('".strtoupper($k)."', '$v');\n";
    		}
    		$html = file_get_contents($filepath);
    		$html = str_replace($old, $new, $html);
    		$uc_config_filepath = CACHE_PATH.'configs'.DIRECTORY_SEPARATOR.'uc_config.php';
    		@file_put_contents($uc_config_filepath, $uc_config);
    		@file_put_contents($filepath, $html);
    		$this->db->insert(array('name'=>'ucenter', 'data'=>array2string($data)), 1,1);
    		showmessage(L('operation_success'), HTTP_REFERER);
    	}
    	$data = array();
    	$r = $this->db->get_one(array('name'=>'ucenter'));
    	if ($r) {
    		$data = string2array($r['data']);
    	}
    	include $this->admin_tpl('system_uc');
    }
    ...

    将表单中的数据$data按照键值对遍历并以如下形式存储到$uc_config变量里:

    $uc_config .= "define('".strtoupper($k)."', '$v');\n";

    上面只是对$k变量进行了字母转大写处理,然后就写到yoursite\phpsso_server\caches\configs\uc_config.php中了,所以这里应该可以构造一句话木马写入到uc_config.php中,从而拿到webshell。

    0x03 漏洞证明

    通过观察uc_config.php,我们构造一句话木马的方法如下(审查元素或者代理改包均可):

    02

    04

    0x04 漏洞修复

    我这里引入了特殊字符的数组$array_key_safe = array(“,”, “;”, “‘“, “(“, “)”, “\“);
    然后在foreach循环时对$k进行过滤如下:

    public function uc() {
    //引入$array_key_safe
    $array_key_safe = array(",", ";", "'", "(", ")", "\\");
    if (isset($_POST['dosubmit'])) {
    $data = isset($_POST['data']) ? $_POST['data'] : '';
    $data['ucuse'] = isset($_POST['ucuse']) && intval($_POST['ucuse']) ? intval($_POST['ucuse']) : 0;
    $filepath = CACHE_PATH.'configs'.DIRECTORY_SEPARATOR.'system.php';
    $config = include $filepath;
    $uc_config = '<?php '."\ndefine('UC_CONNECT', 'mysql');\n";
    foreach ($data as $k => $v) {
    //对$k中敏感字符替换为空
    $k = str_replace($array_key_safe, "", $k);
    $old[] = "'$k'=>'".(isset($config[$k]) ? $config[$k] : $v)."',";
    $new[] = "'$k'=>'$v',";
    $uc_config .= "define('".strtoupper($k)."', '$v');\n";
    }
    $html = file_get_contents($filepath);
    $html = str_replace($old, $new, $html);
    $uc_config_filepath = CACHE_PATH.'configs'.DIRECTORY_SEPARATOR.'uc_config.php';
    @file_put_contents($uc_config_filepath, $uc_config);
    @file_put_contents($filepath, $html);
    $this->db->insert(array('name'=>'ucenter', 'data'=>array2string($data)), 1,1);
    showmessage(L('operation_success'), HTTP_REFERER);
    }

    当然这个修补方法很暴力~



沪ICP备19023445号-2号
友情链接