科普:哈希長度擴(kuò)展攻擊
貌似大多數(shù)滲透師都很少測試密碼學(xué)方面的漏洞。我一直都對密碼學(xué)頗有興趣,于是決定研究web應(yīng)用開發(fā)者誤用加密算法的情況,以及如何利用這些漏洞。
一月份的時(shí)候,我研究了下對于一些比較弱的Message Authentication codes(MACs)[譯者注:關(guān)于MAC與hash的區(qū)別參見此鏈接],如何進(jìn)行哈希長度擴(kuò)展(hash length extension)攻擊。我發(fā)現(xiàn)一些很不錯(cuò)的論文和博文,談到了這種攻擊方式。然而,針對哈希長度擴(kuò)展攻擊的具體細(xì)節(jié),卻鮮有資料。在這篇文章中,我將會(huì)對此進(jìn)行詳細(xì)解釋。
Message Authentication Codes 101
Message authentication codes (MACs)是用于驗(yàn)證信息真實(shí)性的。最簡單的MAC算法是這樣的:服務(wù)器把key和message連接到一起,然后用摘要算法如MD5或SHA1取摘要。例如,假設(shè)有一個(gè)網(wǎng)站,在用戶下載文件之前需驗(yàn)證下載權(quán)限。這個(gè)網(wǎng)站會(huì)用如下的算法產(chǎn)生一個(gè)關(guān)于文件名的MAC:
def create_mac(key, fileName)
return Digest::SHA1.hexdigest(key + fileName)
End
最終產(chǎn)生的URL會(huì)是這樣:
http://example.com/download?file=report.pdf&mac=563162c9c71a17367d44c165b84b85ab59d036f9
當(dāng)用戶發(fā)起請求要下載一個(gè)文件時(shí),將會(huì)執(zhí)行下面這個(gè)函數(shù):
def verify_mac(key, fileName, userMac)
validMac = create_mac(key, filename)
if (validMac == userMac) do
initiateDownload()
else
displayError()
end
End
這樣,只有當(dāng)用戶沒有擅自更改文件名時(shí)服務(wù)器才會(huì)執(zhí)行initiateDownload()開始下載。實(shí)際上,這種生成MAC的方式,給攻擊者在文件名后添加自定義字串留下可乘之機(jī)。
Length Extension Attacks, The Simple
Explanation
哈希摘要算法,如MD5,SHA1, SHA2等,都是基于Merkle–Damgård結(jié)構(gòu)。這類算法有一個(gè)很有意思的問題:如果你知道m(xù)essage和MAC,只需再知道key的長度,盡管不知道key的值,也能在message后面添加信息并計(jì)算出相應(yīng)MAC。
Example: message + padding +extension
繼續(xù)用上面的例子,對文件下載的功能進(jìn)行長度擴(kuò)展攻擊:
http://example.com/download?file= report.pdf%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00% 00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%A8/../ ../../../../../../etc/passwd&mac=ee40aa8ec0cfafb7e2ec4de20943b673968857a5
Length Extensions In Depth
為了理解這種攻擊方式,你必須先了解hash函數(shù)的內(nèi)部原理。
How Hash Algorithms Work
哈希函數(shù)以區(qū)塊為單位操作數(shù)據(jù)。比如說,MD5, SHA1, SHA256的區(qū)塊長度是512 bits 。大多數(shù)message的長度不會(huì)剛好可以被哈希函數(shù)的區(qū)塊長度整除。這樣一來,message就必須被填充(padding)至區(qū)塊長度的整數(shù)倍。用前面文件下載的MAC的例子來說,填充后的message是這樣的(‘x'表示key):
xxxxxxxxxxxreport.pdf\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\xA8
在本例所用的SHA1算法中,哈希值由五組整數(shù)構(gòu)成。一般我們看到的形式是把這五個(gè)整數(shù)轉(zhuǎn)換為16進(jìn)制然后連接到一起。運(yùn)行算法時(shí),初始值(又叫registers)被設(shè)置為這組數(shù):67452301, EFCDAB89,
98BADCFE, 10325476, C3D2E1F0. 緊接著,填充message,再將其分割為512bits的區(qū)塊。算法輪流操作每個(gè)區(qū)塊,進(jìn)行一系列的計(jì)算并更新registers的值。一旦完成了這些運(yùn)算,registers里的值就是最終的哈希值。
Calculating An Extension
計(jì)算擴(kuò)展值得第一步是創(chuàng)建一個(gè)新的MAC。我們首先對待擴(kuò)展的值:上例中的‘/../../../../../../../etc/passwd’進(jìn)行哈希摘要。但是,在進(jìn)行摘要之前,我們要把registers里的初始值設(shè)置為原始message的MAC。你可以將其想象為讓SHA1函數(shù)從服務(wù)器上的函數(shù)運(yùn)行結(jié)束的地方繼續(xù)進(jìn)行。
攻擊者的 MAC = SHA1(extension + padding) <- 覆蓋registers初始值
這個(gè)攻擊有個(gè)前提,在傳入服務(wù)器的哈希函數(shù)時(shí),擴(kuò)展值必須存在于單獨(dú)的區(qū)塊中。所以我們的第二步,就是計(jì)算出一個(gè)填充值使得 key + message + padding == 512 bits 的整數(shù)倍。在此例中,key是11個(gè)字符的長度。因此填充之后的message是這樣的:
report.pdf\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\xA8
傳送到服務(wù)器的填充及擴(kuò)展之后的message以及新的MAC:
http://example.com/download?file=report.pdf %80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%
00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%
00%00%A8/../../../../../../../etc/
passwd&mac=ee40aa8ec0cfafb7e2ec4de20943b673968857a5
服務(wù)器要進(jìn)行摘要運(yùn)算的被攻擊者篡改過的message如下:
secret + message + padding to the next block +
extension + padding to the end of that block.
服務(wù)器算出的哈希值將是ee40aa8ec0cfafb7e2ec4de20943b673968857a5,正好與我們添加擴(kuò)展字串并覆蓋registers初始值所計(jì)算出來的一樣。這是因?yàn)楣粽叩墓S?jì)算過程,相當(dāng)于從服務(wù)器計(jì)算過程的一半緊接著進(jìn)行下去。
How To Run The Attack
為了簡單,在這個(gè)例子中我透露了密鑰長度是11位。在現(xiàn)實(shí)攻擊環(huán)境中,攻擊者無法獲知密鑰長度,需要對其長度進(jìn)行猜測。
繼續(xù)之前的例子,假設(shè)當(dāng)MAC驗(yàn)證失敗時(shí),這個(gè)存在漏洞的網(wǎng)站會(huì)返回一個(gè)錯(cuò)誤信息(HTTP response code 或者response body中的錯(cuò)誤消息之類)。當(dāng)驗(yàn)證成功,但是文件不存在時(shí),也會(huì)返回一個(gè)錯(cuò)誤信息。如果這兩個(gè)錯(cuò)誤信息是不一樣的,攻擊者就可以計(jì)算不同的擴(kuò)展值,每個(gè)對應(yīng)著不同的密鑰長度,然后分別發(fā)送給服務(wù)器。當(dāng)服務(wù)器返回表明文件不存在的錯(cuò)誤信息時(shí),即說明存在長度擴(kuò)展攻擊,攻擊者可以隨意計(jì)算新的擴(kuò)展值以下載服務(wù)器上未經(jīng)許可的敏感文件。
How To Defend Against This Attack
解決這個(gè)漏洞的辦法是使用HMAC算法。該算法大概來說是這樣 :MAC =
hash(key + hash(key + message)),而不是簡單的對密鑰連接message之后的值進(jìn)行哈希摘要。
具體HMAC的工作原理有些復(fù)雜,但你可以有個(gè)大概的了解。重點(diǎn)是,由于這種算法進(jìn)行了雙重摘要,密鑰不再受本文中的長度擴(kuò)展攻擊影響。HMAC最先是在1996年被發(fā)表,之后幾乎被添加到每一種編程語言的標(biāo)準(zhǔn)函數(shù)庫中。
Summary
盡管仍有一些瘋狂的人類在寫自己的加密算法,絕大多數(shù)人已經(jīng)漸漸發(fā)現(xiàn)自己寫加密算法不是什么好主意。然而,不單純的套用公開的加密算法也是有其意義的,前提是你能夠正確的使用這些加密算法。除非你徹底吃透你使用的加密算法的原理,并懂得如何正確使用,否則還是直接用那些經(jīng)過了專業(yè)級審查的高級算法庫要安全些。
原文地址:https://blog.whitehatsec.com/hash-length-extension-attacks/