dedecms v5.7 sp2前臺任意用戶登錄(包括管理員)
前言
我們繼續來說一下dedecms最新的幾個漏洞,今天是一個前臺任意用戶登錄的漏洞,該漏洞結合上一次提到的前臺任意密碼修改漏洞可以直接修改管理員的密碼,剩下的就是找後臺了,廢話不多說,我們開始吧
漏洞版本
還是2018-1-09發行的最新版本
漏洞影響
前臺用戶可以登錄其他任意用戶,包括管理員
漏洞利用條件
- 攻擊者必須註冊一個賬戶
- 開啓了會員模塊功能
漏洞復現
我們先註冊一個用戶,用戶名爲000001,密碼爲123(同樣的,dedecms新建賬戶是需要審覈的,我在本地搭建的,所以直接在數據庫裏做了一下修改)
登錄我們的賬戶
/member/index.php?uid=000001,獲取cookie中的last_vid__ckMd5
/member/index.php ,用burp替換
DedeUserID
和DedeUserID__ckMd5
的值 ,分別爲我們的用戶名000001和last_vid__ckMd5
成功登陸管理員賬號
代碼分析
用戶登錄後會跳轉到/member/index.php這個頁面,所以我們第一步就是要分析訪問/member/index.php的條件,我們直接看源碼,從第24行起
我標出來的那一句就是關鍵,只要IsLogin()函數返回true,那麼我們就還可以確認某個用戶登錄了,然後就是根據M_ID的值來獲取該頁面的各種信息,例如用戶名、短消息等,如下圖:
所以,我們可以初步確定,M_ID決定了我們登錄的用戶,IsLogin函數的返回值決定了是否能夠登錄成功。沿着這個思路,我們追蹤一下IsLogin函數(include\memberlogin.class.php中)
/** * 驗證用戶是否已經登錄 * * @return bool */ function IsLogin() { if($this->M_ID > 0) return TRUE; else return FALSE; }
可見這個函數還是對M_ID進行了判斷,我們繼續追蹤M_ID,在同一個文件的170行處:
$this->M_ID = $this->GetNum(GetCookie("DedeUserID"));
分別看一下這兩個函數:
GetCookie(include\helpers\cookie.helper.php):
這個函數作用大概就是更具輸入的key值,獲取cookie中相應的值(我標記出來的地方是重點)
GetNum(include\memberlogin.class.php):
/** * 獲取整數值 * * @access public * @param string $fnum 處理的數值 * @return string */ function GetNum($fnum){ $fnum = preg_replace("/[^0-9\.]/", '', $fnum); return $fnum; }
該函數的作用就是獲取整數值,沒什麼特別的地方。我們把目光聚焦在getcookie函數我標出來的部分,那個判斷本意是想要防止別人直接通過更改DedeUserID登錄別人的賬號(希望沒人說錯),加了剛剛那個判斷語句,我們不僅僅需要DedeUserID的值,還要知道這個用戶對應的DedeUserID__ckMd 值。
那可不可以我們自己註冊一個用戶,使它繞過if判斷,並且它的M_ID的值與其他用戶M_ID值相等,這樣我們就可以登錄到別人的賬戶上了。但是自己註冊的賬戶的M_ID是來自cookie中的DedeUserID,而DedeUserID又是後臺按序生成的,比如管理員的M_ID爲1,第二個註冊的人的M_ID爲2。這麼一來好像我們就不可能使兩個賬戶的M_ID相等了。
但是include\memberlogin.class.php的178行有這麼一段代碼:
$this->M_ID = intval($this->M_ID);
這裏對M_ID施加了intval,而intval在進行轉換時會把000001轉換爲1,或者把1+字母的形式轉換爲1
var_dump(intval(000001)); var_dump(intval('1wwww')); //D:\wamp64\www\some_practice\test3.php:2:int 1 //D:\wamp64\www\some_practice\test3.php:3:int 1
現在我們解決了僞造M_ID的問題,那麼怎麼使上面那個if語句成立呢?我們還是以000001這個賬戶爲例,我們可以把DedeUserID更改爲000001,然後就是需要再找一個substr(md5($cfg_cookie_encode.’000001’),0,16))的值,然後把這個值替換到DedeUserID__ckMd,就可以成功繞過登錄。那哪裏可以找到剛剛那個東西呢?
index.php中有一個功能就是會記錄最後一個訪客的數據,並存在cookie中的last_vid_ckMd5中
我們來看一下這個值是怎麼計算的,可能會是個驚喜!
我們從index.php的141行開始,有這麼一段代碼
上面的代碼中的last_id就是最後一個訪問你的用戶的id,來源如下:
$last_vid = GetCookie('last_vid');
上面的代碼邏輯就是,如果你的空間還沒有訪客,那麼last_vid就等於你url中傳過去的uid,否則就直接取cookie中的那個last_vid。然後這個last_vid會被寫入cookie,我們接着看PutCookie的處理方式
可以看到last_vid_ckMd5的值其實就是我們前面需要的substr(md5($cfg_cookie_encode.’000001’),0,16)),所以我們只需要把這裏的last_vid_ckMd5替換掉DedeUserID__ckMd,並把DedeUserID修改爲000001就可以從前臺登錄到管理員賬戶,當然想登錄其他賬戶也是同樣的道理,就是註冊用戶的時候更改一下用戶名。
總結
總的來說這個漏洞的可利用性比上一次好很多,上一次的任意用戶密碼修改漏洞的利用條件較爲苛刻,而且這兩個漏洞結合起來就可以達到修改管理員用戶密碼的目的,我也將在下一篇文章裏復現