今天在實驗吧遇見的一道題(題目鏈接),考察了關於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,需要幾個條件:
- cookei字段的getmein不能爲空
- 發送過去的username = admin,並且,password != admin
- 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。