1. 程式人生 > >從零學習哈希長度擴展攻擊

從零學習哈希長度擴展攻擊

之前 轉化 等於 哈希 添加 計算 消息摘要 table register

哈希長度擴展攻擊,利用了md5、sha1等加密算法的缺陷,可以在不知道原始密鑰的情況下來進行計算出一個對應的hash值。


引言

最開始出現好像是在PCTF2014上
最近做題突然看見了
先來看下代碼

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php $auth = false; $role = "guest"; $salt = if (isset($_COOKIE["role"])) { $role = unserialize($_COOKIE["role"]); $hsh = $_COOKIE["hsh"];
if ($role === "admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))) { $auth = true; } else { $auth = false; } } else { $s = serialize($role); setcookie(‘role‘,$s); $hsh = md5($salt.strrev($s)); setcookie(‘hsh‘,$hsh);
} if ($auth) { echo "<h3>Welcome Admin. Your flag is"; } else { echo "<h3>Only Admin can see the flag!!</h3>"; } ?>

簡單了解hash函數

技術分享

hash函數補位

當hash函數拿到需要被hash的字符串後,先將其字節長度整除64,取得余數。如果該余數正好等於56,那麽就在該字符串最後添加上8個字節的長度描述符(具體用bit表示)。如果不等於56,就先對字符串進行長度填充,填充時第一個字節為hex(80),其他字節均用hex(00)填充,填充至余數為56後,同樣增加8個字節的長度描述符(該長度描述符為需要被hash的字符串的長度,不是填充之後整個字符串的長度)。以上過程,稱之為補位

hash計算

補位完成後,字符串以64位一組進行分組(因為上面的余數為56,加上8個字節的長度描述符後,正好是64位,湊成一組)。字符串能被分成幾組就會進行多少次“復雜的數學變化”。每次進行“復雜的數學變化”都會生成一組新的registers值供下一次“復雜的數學變化”來調用。第一次“復雜的數學變化”會調用程序中的默認值。當後面已經沒有分組可以進行數學變化時,該組生成的registers值就是最後的hash值。
在sha1的運算過程中,為確保同一個字符串的sha1值唯一,所以需要保證第一次registers的值也唯一。所以在sha1算法中,registers具有初始值。如上圖中的registers值0。
Hash值的隨機性完全依賴於進行“復雜的數學變化”時輸入的registers值和該次運算中字符串分組的數據。如果進行“復雜數學變化”時輸入的registers值和該次運算的字符串分組相同,那麽他們各自生成的新的registers值也相同。

如何攻擊

了解題意

哈希長度擴展攻擊適用於加密情況為: hash($salt . $message) 的情況,其中 hash 最常見的就是 md5、hash1。我們可以在不知道 $salt 的情況下推算出另外一個匹配的值。
如以上代碼中我們已知的有:
1.$hsh = $_COOKIE[“hsh”]
2.$role = unserialize($_COOKIE[“role”])
題目要求是我們需要通過構造使得$role === “admin” 時 $hsh === md5($salt.strrev($_COOKIE[“role”]

md5的實現

先將字符串轉化為16進制
技術分享

補位

消息必須進行補位,即使得其長度在對512取模後的值為448。也就是說,len(message)%512==448。當消息長度不滿448bit時(註意是位,而不是字符串長度),消息長度達到448bit即可。當然,如果消息長度已經達到448bit,也要進行補位。補位是必須的。
補位的方式的二進制表示是在消息的後面加上一個,後面跟有限個hex(00),直到len(message)%512==448。如下,將字符串補位到448bit,也就是56byte。
技術分享

補長度

補位過後,第57個字節儲存的是補位之前的消息長度。cccc是4個字母,也就是4個字節,32bit。換算成16進制為0x20。其後跟著7個字節的0x00,把消息補滿64字節。
技術分享

計算消息摘要

計算消息摘要必須用補位已經補長度完成之後的消息來進行運算,拿出512bit的消息(即64字節)。計算消息摘要的時候,有一個初始的鏈變量,用來參與第一輪的運算。MD5的初始鏈變量為:

1 2 3 4 A=0x67452301 B=0xefcdab89 C=0x98badcfe D=0x10325476

我們不需要關系計算細節,我們只需要知道經過一次消息摘要後,上面的鏈變量將會被新的值覆蓋,而最後一輪產生的鏈變量經過高低位互換(如:aabbccdd->ddccbbaa)後就是我們計算出來的md5值。

Attack

簡化代碼

為了看起來方便,簡化代碼如下

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php $auth = "guest"; $salt = "c014hashtest"; if (isset($_COOKIE["auth"])) { $hsh = $_COOKIE["hsh"]; if ($hsh === md5($salt . $_COOKIE["auth"])) { die("Welcome, admin!"); } else{ die("You are not admin!"); } } else { setcookie("auth", $auth); setcookie("hsh", md5($salt . "test")); die("You are not admin!"); } ?>

技術分享

擴展攻擊

本來準備手動一步步改hex值的,結果發現了python有個HashExtender庫..
那就賊簡單了
技術分享
不過文檔上的庫我沒裝成功。。
又發現了hashpumpy
假設已知salt長度為12和”test”但是不知道salt的值
技術分享
把\x改成%直接復制進cookie
刷新
技術分享

從零學習哈希長度擴展攻擊