1. 程式人生 > >MD5加密及Hash長度拓展攻擊【通俗易懂】

MD5加密及Hash長度拓展攻擊【通俗易懂】

合成 adc color url 存在 light 之前 交換 非線性

先放一個簡單點的利用了Hash長度拓展攻擊的題目

if($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
      echo "Congratulations! You are a registered user.\n";
      die ("The flag is ". $flag);
    }

在理解Hash長度拓展攻擊之前需要大致了解下MD5的加密原理

MD5加密過程

1.數據分組

在MD5加密算法中,將一個字符串分為若幹個大小為512位的分組,而每一個分組又可分為16個子分組m0~m3{A},m4~m7{B},m8~m11{C},m12~m15{D}(這裏的ABCD在稍後的Hash計算中會講解到)。

2.數據填充

MD5值的計算都必須以512位為一組進行計算,所以就必須使得填充後的數據 [原字符串+填充100...+原字符串總長(64位)],剛好等於512的倍數。比如:

$str = "test",十六進制表示為0x74657374

數據填充後為0x74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000

中間的80...H=10000000...B,最後四字節也就是2000000000000000代表前面‘test‘的長度,也就是4×8位=32D=20H。

如下圖所示(圖取自另一篇博客,忽略水映啦~~)

技術分享圖片

下面說一下具體的一些計算:在MD5中有四個32位的被稱作鏈接變量的整數參數,是如下設置(這個ABCD是初始的固定的值,即初始向量):

A=0x67452301,

B=0xefcdab89,

C=0x98badcfe,  

D=0x10325476。

通過小端規則轉換A{m3~m0}B{m7~m4}C{m11~m8}D{m15~m12}就是MD5值:0123456789abcdeffedcba9876543210。即為初始向量的MD5值,記為md5_0。

之後有四個非線性函數,將字符串和那四個鏈接變量經過一系列的復雜運算(具體運算規則請自行查閱),算出一組新的A,B,C,D的值,公式即$md5_1=MD5($md_0+$ex_str_0);如果消息小於512,也就是只需要計算一次,這時候的$md5_1就是最終的MD5值;如果消息大於512的話,就用第一次得到的$md5_1代入公式$md5_2=MD5($md_1+$ex_str_1)對第二個512位數據進行運算...如此叠代即可。

這種加密可能導致的問題

思考,如果是這種情況,由兩個字符串組成一個字符串($str=$a+$b),第一個字符串($a)不知道也不可控,只可控第二個字符串($b),但知道第一個字符串($a)的MD5值和長度,這時候我將第二個字符串精心構造一下,便可以算出合成的字符串$str的MD5的值。

如何精心構造,且看下文。

正向計算

假如第一個字符串$a=“test”,十六進制表示0x74657374

構造第二個字符串首先手動將$str補成一個標準的可以直接計算的512位

$str=0x74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000

這樣子,這時候再在後面追加一個0x746573748

$str=0x74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000746573748

這時候再將$str大於512位,程序會自動先將這串數據補為1024位,補充完如下

$str=0x7465737480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000074657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002002000000000000

這時將$str分為兩部分

74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000

74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002002000000000000

這時候程序計算前一部分的ABCD的值,由於和之前算的test的數值是相同的所以

A=0xcd6b8f09

B=0x73d32146

C=0x834edeca

D=0xf6b42726

對應的MD5:098f6bcd4621d373cade4e832627b4f6

到了第二部分,第二部分的計算是用的第一部分的ABCD去計算,計算新的ABCD如下

A=0x226359e5

b=0x99df12eb

C=0x6853f59e

D=0xf5406385

最後算出來的MD5:e5596322eb12df999ef55368856340f5

按照給定條件計算一遍(此即MD5的Hash長度拓展攻擊原理)

我們知道的條件

1.$a的MD5(098f6bcd4621d373cade4e832627b4f6)

2.$a的長度=4

3.$b我們可以任意控制

由1的MD5我們可以逆推算出其ABCD的值

A=0xcd6b8f09

B=0x73d32146

C=0x834edeca

D=0xf6b42726

我們構造$b=‘\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00‘+‘test‘

此時$str如下,由於不知道$a,我們假設$a="aaaa"(任意構造,但需滿足條件已知長度為4)

那麽假設內容就為$str=‘aaaa‘+‘\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00‘+‘test‘

好了我們腦補一下程序計算str的過程

1.由於大於512位,先補全為1024位,

2.將其分為兩部分

3.計算第一部分的ABCD的值

4.再用第一部分算出來的ABCD拿來算第二部分的值。

這裏由於第一部分的ABCD我們可以逆推出來,我們可以直接跳過前三部分直接進行第四部分的計算,只需要將標準的MD5的源碼裏面的初始的ABCD的值改為逆推出來的那個值

我們用假的初始的ABCD計算一下

0x74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002002000000000000

的MD5,發現是e5596322eb12df999ef55368856340f5,和上面正向計算出來的一樣!

這裏可能需要反復理解一下,有點繞,但這就是真正理解Hash長度拓展攻擊原理的臨門一腳,過了便不難。

再結合一開始的那道題目來理解下吧,題目中,需要滿足條件$COOKIE["getmein"] === md5($secret . urldecode($username . $password))才能獲取到flag,但由於$secret不知道也不可控,所以就需要將我們構造的(512<位數(str)<1024)數據中第一個512位數據計算得到的md5值來取代$secret(即用第一向量md5_1取代初始向量md5_0/$secret),而usename和password仍舊是第一個512位數中的值,再將$COOKIE[‘getmein‘]改為第二個512位拓展數據得到的MD5值即可(即將第二向量md5_2取代第一向量md5_1)。我說過很好理解的叭~^^

總結

存在此類缺陷的加密算法主要有:md和sha系列等等

防範:1. Hash(secret, Hash(message))

2. HMAC算法 HMAC(secret||padding)=H(secret||H(secret||padding))

3. 交換secret和padding的位置,即MAC(padding||secret)

利用工具:主要有hash_dump,hash_extender,還有一些大佬的腳本,相關博客很多,自行學習吧。

任何疑問可留言,看到回復~^^

MD5加密及Hash長度拓展攻擊【通俗易懂】