漏洞触发点在include/memberlogin.class.php中的MemberLogin类中的登录校验函数
//php5构造函数 function __construct($kptime = -1, $cache=FALSE) { global $dsql; if($kptime==-1){ $this->M_KeepTime = 3600 * 24 * 7; }else{ $this->M_KeepTime = $kptime; } $formcache = FALSE; $this->M_ID = $this->GetNum(GetCookie("DedeUserID")); $this->M_LoginTime = GetCookie("DedeLoginTime"); $this->fields = array(); $this->isAdmin = FALSE; if(empty($this->M_ID)) { $this->ResetUser(); }else{ $this->M_ID = intval($this->M_ID); if ($cache) { $this->fields = GetCache($this->memberCache, $this->M_ID); if( empty($this->fields) ) { $this->fields = $dsql->GetOne("Select * From `#@__member` where mid='{$this->M_ID}' "); } else { $formcache = TRUE; } } else { $this->fields = $dsql->GetOne("Select * From `#@__member` where mid='{$this->M_ID}' "); } if(is_array($this->fields)){ #api{{ if(defined('UC_API') && @include_once DEDEROOT.'/uc_client/client.php') { if($data = uc_get_user($this->fields['userid'])) { if(uc_check_avatar($data[0]) && !strstr($this->fields['face'],UC_API)) { $this->fields['face'] = UC_API.'/avatar.php?uid='.$data[0].'&size=middle'; $dsql->ExecuteNoneQuery("UPDATE `#@__member` SET `face`='".$this->fields['face']."' WHERE `mid`='{$this->M_ID}'"); } } }
M_ID参数是由GetNum(GetCookie("DedeUserId"))赋值的。
之后通过intval()函数对M_ID进行整数转换便没有再进行任何处理和过滤,然后通过
SQL语句
Select * From '#@__member' where mid='{$this->M_ID}'
查询来判断用户的身份。
跟进GetCookie()函数和GETNum()函数,看是否过修改M_ID参数来进行越权
/** * 获取Cookie记录 * * @param $key 键名 * @return string */ if ( ! function_exists('GetCookie')) { function GetCookie($key) { global $cfg_cookie_encode; if( !isset($_COOKIE[$key]) || !isset($_COOKIE[$key.'__ckMd5']) ) { return ''; } else { if($_COOKIE[$key.'__ckMd5']!=substr(md5($cfg_cookie_encode.$_COOKIE[$key]),0,16)) { return ''; } else { return $_COOKIE[$key]; } } } }
/** * 获取整数值 * * @access public * @param string $fnum 处理的数值 * @return string */ function GetNum($fnum){ $fnum = preg_replace("/[^0-9/.]/", '', $fnum); return $fnum; }
根据传入字符串,找到cookie相应的值,但校验了$_COOKIE[$key.'__ckMd5']
使用的$ cfg_cookie_encode是在程序安装时设置的。无法破解$key.'__ckMd5'
GetNum()函数则是对GetCookie()函数返回的$_COOKIE[$key]值进行处理,获取整数值。
漏洞利用
在文件/menber/index.php中,找到这么一段代码
/*----------------------------- //会员空间主页 function space_index(){ } ------------------------------*/ else { require_once(DEDEMEMBER.'/inc/config_space.php'); if($action == '') { include_once(DEDEINC."/channelunit.func.php"); $dpl = new DedeTemplate(); $tplfile = DEDEMEMBER."/space/{$_vars['spacestyle']}/index.htm"; //更新最近访客记录及站点统计记录 $vtime = time(); $last_vtime = GetCookie('last_vtime'); $last_vid = GetCookie('last_vid'); if(empty($last_vtime)) { $last_vtime = 0; } if($vtime - $last_vtime > 3600 || !preg_match('#,'.$uid.',#i', ','.$last_vid.',') ) { if($last_vid!='') { $last_vids = explode(',',$last_vid); $i = 0; $last_vid = $uid; foreach($last_vids as $lsid) { if($i>10) { break; } else if($lsid != $uid) { $i++; $last_vid .= ','.$last_vid; } } } else { $last_vid = $uid; } PutCookie('last_vtime', $vtime, 3600*24, '/'); PutCookie('last_vid', $last_vid, 3600*24, '/');
$last_vid为空把$uid赋值给$last_vid,而$uid是可控的用户名,再通过PutCookie()函数写到cookie中。
这里加入构造出类似0000001的用户名,用last_vid_ckMd5的值 == ($cfg_cookie_encode.$_COOKIE['last_vie'])的MD5的前16位,满足条件。
接着在登录类的构造函数中,mid经GetNum()和intval()函数的过滤,就形成了1,接着进入数据库查询再展示到页面。
复现
前台注册普通用户,这里注册一个0001
访问/member/index.php?uid=0001,获取last_vid__ckMd5的值
接下来使用0001账号登录,登录后的未修改的cookie。
将last_vid的值赋给DedeUserID,last_vidckMd5的值赋给DedeUserIDckMd5修改后的cookie。
修改后刷新页面
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论