PHP Hash比較存在缺陷,影響大量Web網(wǎng)站登錄認證、忘記密碼等關(guān)鍵業(yè)務(wù)

最近一個被稱為“Magic Hash”的PHP漏洞可以使得攻擊者非法獲取用戶的賬號信息。漏洞原因是PHP以一種特定的方式處理被哈希的字符串,攻擊者可以利用其從中嘗試并可能獲取密碼,繞過登錄認證系統(tǒng)和其它運行在PHP哈希比較之上的函數(shù)。

漏洞描述

PHP在處理哈希字符串時,會利用”!=”或”==”來對哈希值進行比較,它把每一個以”0E”開頭的哈希值都解釋為0,所以如果兩個不同的密碼經(jīng)過哈希以后,其哈希值都是以”0E”開頭的,那么PHP將會認為他們相同,都是0。

攻擊者可以利用這一漏洞,通過輸入一個經(jīng)過哈希后以”0E”開頭的字符串,即會被PHP解釋為0,如果數(shù)據(jù)庫中存在這種哈希值以”0E”開頭的密碼的話,他就可以以這個用戶的身份登錄進去,盡管并沒有真正的密碼。

攻擊案例:

4月8日,wordpress發(fā)布了一個重要更新,在該次更新中,修復了一系列安全漏洞。其中最顯眼的就是cookie偽造漏洞(CVE -2014- 0166)。

我們來看修補的代碼:

$key=wp_hash($username.$pass_frag.'|'.$expiration,$scheme);$hash=hash_hmac('md5',$username.'|'.$expiration,$key);-if($hmac!=$hash){+if(hash_hmac('md5',$hmac,$key)!==hash_hmac('md5',$hash,$key)){

前日嘗試分析該漏洞,奈何知識匱乏,對php特性不夠了解,一連用了幾個小時都想不出。想不通為何加了一次hash_hmac就可以修復漏洞。當時的我以為是涉及到了加密算法上的一些問題,就放棄了。

今日突然看到一篇文章,頓悟是comparision operator的問題。其實之前也有注意到 “!=” 與 “!==”

這兩個符號的不同,不過大致想了一下沒想到利用的可能,就把重點放在了hash_hmac上。也許這是wordpress的障眼法?呵呵,說笑。

我們把全部的關(guān)注點放到 “!=” 與 “!==” 上來:

我們知道php比較相等性的運算符有兩種,一種是strict,一種是non-strict。php manual中是這樣定義的:


"==="和"!=="即strict比較符,只有在類型相同時才相等。"=="和"!="即non-strict比較符,會在類型轉(zhuǎn)換后進行比較。

再看php manual中給出的例子:


var_dump(0=="a");//?0?==?0?->?truevar_dump("1"=="01");//?1?==?1?->?truevar_dump("10"=="1e1");//?10?==?10?->?truevar_dump(100=="1e2");//?100?==?100?->?true?>

字符串在與數(shù)字比較前會自動轉(zhuǎn)換為數(shù)字,所以0=="a"了。

另外兩個字符串比較,如果兩個都是數(shù)字形式,則同時轉(zhuǎn)換為數(shù)字進行比較,所以"1"=="01"。

這時你要問了,wordpress的代碼中是將cookie中的hash和真實hash這兩個hash的字符串進行比較,和這個有什麼關(guān)系呢?

我們注意上面"10"=="1e1"這個例子,php智能的將科學計數(shù)形式的字符串轉(zhuǎn)換為對應(yīng)數(shù)字(1e1 = 1*10^1 = 1)。兩個不同的字符居然相等了,不知到這裡你是否得到了啟示?

好吧,來一個明顯的,你一定會恍然大悟:

var_dump("0e123456789012345678901234567890"==="0")//falsevar_dump("0e123456789012345678901234567890"=="0")//true

當hash以"0exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"之類的形式出現(xiàn)時,與"0"相等。

讓我們回到wordpress的驗證代碼上來。先生成根據(jù)用戶名($username)、密碼($pass_frag)、cookie有效期($expiration)、wp-config.php中的key($key)四個信息計算出對應(yīng)的$hash

(算法很簡單,不細說), 然后用cookie中取得的$hmac值與之進行比較($hmac != $hash ?),從而驗證cookie有效性。

另外提下,cookie的格式是這樣的:wordpress_hashofurl=username|expiration|hmac

我們能控制的變量有$username和$expiration,其中$username需要固定。于是我們可以通過控制cookie中的$expiration去改變$hash的值,然后將cookie中的$hmac設(shè)置為0

只要不斷改變$expiration,直到滿足$hash=="0"的$hash出現(xiàn),就成功偽造了有效的cookie。

當然,通過粗略的數(shù)學概率運算即可推知,滿足條件的hash出現(xiàn)概率非常之低:

P?=?Sum(10^n,n=0,30)/16^32?=?3.26526*10^-9

接近三億個請求才有一個可碰上的概率,嗚嗚~

有時看人品,人品好的很快就碰到了,人品不好的就如我,幾乎五億了:


怎么樣,少年,寫一個多線程腳本跑起?

影響范圍

影響大量web站點,其中的登錄認證,“忘記密碼”,二進制校驗,cookie等方面,由于都會用到PHP中的哈希函數(shù)值比較,因此都存在隱患。

解決方案

分析使用PHP的web站點中哈希比較函數(shù),將其中的”==”,”!=”分別更改為”===”和”!===”。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容