MD5擴展長度攻擊(實驗吧 —— 讓我進去)

 

今天在實驗吧遇見的一道題(題目鏈接),考察了關於MD5擴展長度攻擊的有關原理。本文會首先對原理進行說明,後面會放上實驗吧題目的wp。

MD5擴展長度攻擊原理

爲了更好地理解改攻擊,首先了解以下MD5的加密算法,加密過程的示意圖如下:

通俗來講,就是MD5把每512位當作一組進行加密計算,首先有一個初始序列的值(該值是固定的),這個初始序列與信息的第一組512位進行運算,得到一個結果,該結果作爲下一組512位的初始序列,再進行同樣的運算,依此類推。需要注意的是,最後一個分組的後64位用來顯示原消息的總長,是預留的,也就是說,最後一個分組只能有448位。

有一個問題就是,如果要是(加密的信息長度+64)並不是512的整數倍怎麼辦呢?

MD5的策略是:

最後一個分組如果不足512,則進行填充,填充的策略是:在原消息和原消息總長之間填充01字符串,第一位爲1,剩下的全部填充0。

這樣其實就有了一個漏洞:

如果給出一個message和該message經過md5加密後的值,我們可以通過手動填充,把消息長度填充到512的整數倍,再根據這個新的字符串,自己計算出md5值(因爲有原message的md5值,相當於知道了加密的初始序列),同樣可以成功。

 

填充過程簡要說明

比如原信息爲test,md5('test') = 098f6bcd4621d373cade4e832627b4f6;也就是說原信息只有4*8=32位,我們要填充448 - 32 = 416位。

‘test'的十六進制是0x74673574(十六進制每個字符可以轉成4個二進制位),根據我們上文提到的策略,填充後應該是:80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000

注意:MD5中的填充都是小端序,也就是說,數據的高位字節存放在地址的高端 低位字節存放在地址低端,比如十六進制的後16位(64/4)是32,表示信息長度是32位,就是2000000000000000;

 

實驗吧題目wp

首先使用burpsuite抓包,發現在請求包頭中的cookie參數中,有一個source字段,在其它的嘗試暫時都沒有頭緒的情況下,考慮到source這個詞有點特殊(可以想到頁面源碼之類的),試着把source的值改爲1,發現得到了程序源代碼:

$flag = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "XXXXXXXXXXXXXXX"; // This secret is 15 characters long for security!

$username = $_POST["username"];
$password = $_POST["password"];

if (!empty($_COOKIE["getmein"])) {
    if (urldecode($username) === "admin" && urldecode($password) != "admin") {
        if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
            echo "Congratulations! You are a registered user.\n";
            die ("The flag is ". $flag);
        }
        else {
            die ("Your cookies don't match up! STOP HACKING THIS SITE.");
        }
    }
    else {
        die ("You are not an admin! LEAVE.");
    }
}

setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));

if (empty($_COOKIE["source"])) {
    setcookie("source", 0, time() + (60 * 60 * 24 * 7));
}
else {
    if ($_COOKIE["source"] != 0) {
        echo ""; // This source code is outputted here
    }
}

通過閱讀源碼,我們可以知道,如果想要得到flag,需要幾個條件:

  1. cookei字段的getmein不能爲空
  2. 發送過去的username = admin,並且,password != admin
  3. getmein的值 = $secret + $username + $password 的md5值

前兩個條件都很容易滿足,關鍵是第三個,因爲我們不知道$secret的內容,只知道長度爲15,不過繼續閱讀後面的內容,可以獲得一個信息是:

    md5($secret + adminadmin)已知,也就是請求頭中的sample-hash :

那麼,

如果 $username = admin,$password = adminwn,則問題則轉化成:

已知md5('xxxxxxxxxxxxxxxadminadmin'),求md5('xxxxxxxxxxxxxxxadminadminwn')的值,然後只要把該值賦給geimein即可。綜上,可以利用md5擴展長度攻擊。

由於md5算法較爲複雜,我使用了一個工具hashpump:

附上安裝方法:

git clone https://github.com/bwall/HashPump
apt-get install g++ libssl-dev
cd HashPump
make
make install

用法:

輸入已知的字符串和md5結果(在這裏是adminadmin和),輸入密鑰的長度(15),再輸入你想要在後面添加的字符串,它會自動給你返回md5後的結果,以及填充數據:

把數據在burpsuite中填入後重發即可得到flag。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章