DedeCMS---V5.7_UTF8_SP1、SP2---任意前臺用戶登錄(cookie偽造)
漏洞觸發點在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‘。所以一般情況下,我們是無法破解$key.‘__ckMd5‘這類值的。
GetNum()函數則是對GetCookie()函數返回的$_COOKIE[$key]值進行處理,獲取整數值。
正常情況下,程序中的DedeUserID就是當前用戶的用戶ID。但是如果將其中的DedeUserID和DedeUserID__ckMd5都替換為其他的賬戶,是否就意味著我們可以以其他的賬戶登錄呢?
那麽現在的問題就在於,如何進行偽造呢?我們知道管理員admin的mid是1,但是我們如何得到對應的DedeUserID__ckMd5呢?所以目前的問題轉變為我們需要得到1所對應的DedeUserID__ckMd5的。
漏洞利用點:
在文件/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或1abcde這樣的用戶名,用我last_vid_ckMd5的值 == ($cfg_cookie_encode.$_COOKIE[‘last_vie‘])的MD5的前16位,滿足條件。
接著在登錄類的構造函數中,mid經GetNum()和intval()函數的過濾,就形成了1,接著進入數據庫查詢再展示到頁面。
在用戶空間主頁:
http://localhost/DedeCMS/member/index.php?uid=001
這裏代碼根據用戶提交的參數uid調用了Getcookie()函數生成了cookie值即相應的$_COOKIE[$key]和$_COOKIE[$key.‘__ckMd5‘]值。
由於GetNum()函數的處理,我們在復現的時候註冊攻擊賬號時應使用001、0001、00001之類的用戶名來繞過該函數,從而達到以管理員的身份登錄前臺。
---V5.7_UTF8_SP1、SP2---
DedeCMS---V5.7_UTF8_SP1、SP2---任意前臺用戶登錄(cookie偽造)