齊博CMS HMAC+Cookie注入漏洞分析

前言

首先聲明這不是0day,具體齊博版本就不說了,後面應該有人也發現這個漏洞而且發出來了。php

本文爲篤行平常工做記錄,文章是大概14年國慶節寫的,一直未公開。那時候對當時的齊博系列進行完整的分析和代碼審計,漏洞很多,挑幾個有意思的發出來~。html

一.HMAC簡介

HMAC 是密鑰相關的哈希運算消息認證碼( Hash-based Message Authentication Code),HMAC 運算利用哈希算法,以一個密鑰和一個消息爲輸入,生成一個消息摘要做爲輸出。web

詳細介紹本身google吧。算法

https://en.wikipedia.org/wiki...shell

二.齊博CMS HMAC解析

見文件inc/function.inc.php 中的mymd5 函數安全

/**
*加密與解密函數
**/
function mymd5($string, $action = "EN", $rand = ''){ //字符串加密和解密
         global  $webdb;
$secret_string = $webdb[mymd5].$rand.'5*j,.^&;?.%#@!'; //絕密字符串,能夠 任意設定
if  (!is_string($string)){
                $string  =  strval($string);
}
if ($string == = "") return "";
if ($action == "EN") $md5code = substr(md5($string), 8, 10); else{
$md5code = substr($string, -10);
$string = substr($string, 0, strlen($string) - 10);
}
//$key = md5($md5code.$_SERVER["HTTP_USER_AGENT"].$secret_string);
$key = md5($md5code.$secret_string);
$string = ($action == "EN" ? $string : base64_decode($string)); $len = strlen($key);
$code = "";
for ($i = 0; $i < strlen($string); $i++){
                $k  =  $i%$len;
                $code  .  =  $string[$i]  ^  $key[$k];
}
$code = ($action == "DE" ? (substr(md5($code), 8, 10) == $md5code ? $code : NULL) : base64_encode($code)."$md5code");
       return  $code;
}

開發人員把加密和解密的算法都合起來在了一塊兒。這裏的交換密鑰以下(附帶 rand 隨機變量),且系統安裝時候也會隨機產生參數$webdb[mymd5]data/config.php:cookie

$secret_string    = $webdb[mymd5].$rand.'5*j,.^&;?.%#@!'

結算構成的密文信息結構以下以下:網絡

|任意長度密文|固定10字節hashcode|

整體加密過程歸納以下:函數

Data = 原文
Key = $webdb[mymd5].$rand.'5*j,.^&;?.%#@!'
HashKey = md5( Data + Key )
HashKey1 = substr( md5(Data),8,10 ) 固定 10 位的 hashcode,簽名用。
EncryptData = HashKey^Data    任意長度
最終密文則爲
EncryptData+hashcode
因爲網絡傳輸字符關係,齊博這裏對 EncryptData 進行了一次 base64encode 操做。
實際獲得的是 base64encode(EncryptData)+hashcode

整體解密過程以下:ui

Data = 密文
Key = $webdb[mymd5].$rand.'5*j,.^&;?.%#@!'
DataReal = base64decode( substr( Data, 0, len(Data) – 8 )) 取出真正的密文,而且還原成二進制 HashKey = md5(DataReal + Key)
HashKey1 = substr(Data,-8 ) 固定 10 位的 HashKey1,取最後 10 位。
OriginalData = HashKey^ DataReal    還原密文,並非逆向解密。
最終一步 HashKey1 校驗 若是 md5(OriginalData) 等於 HashKey1 那麼則認爲這個消息是有效的那麼最終明文爲
OriginalData

整個交換的過程當中對於用戶來講密鑰 Key 是不可見的,根據明文和密文是不可能直接還原出整個加密的算法,用戶對計算出 10 位 HashKey1 的簽名也是未知的,整體安全性比較高,要暴力破解枚舉則要 16^10 次方的數量級。

三.齊博類 HMAC 算法爆破的可能性

通過分析,次算法可能存在一個極大的安全隱患就是計算EncryptData 引入的是 Data 的長度,在長度較短的時候能夠進行暴力枚舉。

$len = strlen($key);
$code = "";
for ($i = 0; $i < strlen($string); $i++){
         $k  =  $i%$len;
         $code  .  =  $string[$i]  ^  $key[$k];

若是咱們構造原文Data = ‘ly’ 那麼 HashKey1 則能夠固定成 c6555942cb ,那麼整個加密串應該是 EncryptDatac6555942cb 的形式。只要讓算法知足 substr( md5(HashKey ^ Data),8,10) 等於 c6555942cb 便可。

又有:

Data = EncryptData^HashKey
EncryptData =HashKey ^ Data

咱們的明文只有 2 位,那麼能構造的 EncryptData 是 00~FF 規模爲 16^2 數量至關可觀,那麼暴力枚舉規模就轉換成了 16^len(Data) 複雜度。

四.齊博前臺認證 COOKIES 注入

齊博系統在COOKIE 中使用了 HMAC,COOKIE 產生和使用其實都是服務端作的工做,其實沒有第一章所說的明顯的客戶端/服務端模式交換密鑰,這裏的場景是廣義的 C/S模式,相似UC_Client/UC_Server,在業務邏輯上的C/S 模式並不是物理的 C/S 模式。進入整理,看文件 admin/global.php

/*用戶登陸*/
if ($_POST[loginname] && $_POST[loginpwd]) {
//省略省略
login_logs($_POST[loginname], "成功登陸,保密了"); $_COOKIE[Admin] = "$rs[uid]\t".mymd5($rs[password]); setcookie("Admin", $_COOKIE[Admin], 0, "/");
}
if ($ForceEnter == 1){
$groupdb = @include(ROOT_PATH."data/group/3.php"); $Apower = ($groupdb[allowadmindb]);
}elseif(!$userdb){
         include  './template/login.htm';
exit; }
else{
//同步前臺登陸
$md5code = mymd5("$lfjdb[uid]\t$lfjdb[username]\t$lfjdb[password]", 'E N', $onlineip);
}
setcookie("adminID", $md5code, $timestamp + 1800, '/');
}

在驗證登陸的後,屢次使用了 HMAC 算法對 cookie 進行加密典型的有 $_COOKIE[adminID]$_COOKIE[admin]

再看文件 inc/function.inc.php

//同步後臺登陸
if ($_COOKIE["adminID"] && $detail = mymd5($_COOKIE["adminID"], 'DE', $onlin eip)){
unset($_uid, $_username, $_password);
list($_uid, $_username, $_password) = explode("\t", $detail);
$lfjdb = $db->get_one("SELECT * FROM {$pre}memberdata WHERE uid='$
_uid' AND username='$_username'"); }

由上文可知 $_COOKIE[adminID]的明文形式是

uid\tusername\tpassword
三個參數由 tab 分割。

那麼 list($_uid, $_username, $_password) = explode("\t", $detail); 以後就把結果保存到 $_uid , $_username$_password若是先後參數個數不一樣,那麼 那個參數就會爲空。

下面進行查庫

$lfjdb = $db->get_one("SELECT * FROM {$pre}memberdata WHERE uid='$_uid' AND username='$_username'");

若是咱們構造 uid = 「1’#」那麼查詢語句實際就變成了 SELECT * FROM {$pre}memberdata WHERE uid=1知足條件,前臺登陸成功,前臺登陸認證就這一出。

因爲 COOKIE 採用了密文交換,那麼咱們就不用關心 單引號被轉移的問題,真是太棒了,固然這個 uid 必定要存在,通常創始人 uid 基本=1結合上文,咱們只要構造出一個解密後的 COOKIE[adminID] = 「1’#」便可。那麼根據暴力分析一章,咱們要構造的 EncryptData 長度爲 3範圍 000~fff總計 16^3=4096 規模,至關可觀。

計算出 hashcode 爲 cdb8c28d5d

ps:md5(1’#) =a425ef44cdb8c28d5d434b2a1343205e

那麼咱們只要枚舉 base64_encode( 000~fff) + cdb8c28d5d。

最重要的一點咱們發如今認證登陸的時候傳入了$onlineip 變量,可能致使 key 變更,不能暴力,看代碼 inc/function.inc.php

if ($_SERVER['HTTP_CLIENT_IP']){
$onlineip = $_SERVER['HTTP_CLIENT_IP']; }elseif($_SERVER['HTTP_X_FORWARDED_FOR']){
} else{
}
$onlineip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$onlineip  =  $_SERVER['REMOTE_ADDR'];

那麼咱們直接構造固定的HTTP_X_FORWARDED_FOR 參數便可。
而且 http 請求提交登陸認證頁面,並根據返回值判斷。

其實前臺能夠直接getshell不過不在咱們討論範圍內。

最後 ending…若有不足請指點,亦可留言或聯繫 fobcrackgp@163.com.
本文爲篤行原創文章首發於大題小做,永久連接:齊博CMS:HMAC+COOkie注入漏洞分析

https://www.ifobnn.com/qibocmshmac.html
相關文章
相關標籤/搜索