瀏覽器是如何存儲密碼的?

0 評論 9819 瀏覽 0 收藏 16 分鐘

一、引言

我曾經(jīng)介紹過名為dumpmon的推特機器人,它監(jiān)控著眾多“貼碼網(wǎng)站”的賬戶轉(zhuǎn)儲、配置文件和其他信息。自那以后,我一直留意著監(jiān)測到的信息。接下來會有關(guān)于dumpmon的一系列文章,而本文則關(guān)注瀏覽器是如何存儲密碼的。

這里提到dumpmon,是因為我偶然發(fā)現(xiàn)一些貼碼,比如這篇,應(yīng)該是感染在計算機上的惡意軟件的日志。我便想:我總是認(rèn)為最好不要讓瀏覽器直接存儲密碼,但是原因呢?惡意軟件從感染的計算機中獲得密碼會有多輕松呢?因為從一處獲得所有想要的資料有點困難,所以我決定在此文貼出結(jié)果以及一些從各個瀏覽器的密碼管理器中提取密碼的簡單代碼。

本文所述是在windows 8系統(tǒng)上分析下述瀏覽器。

二、Chrome瀏覽器

獲得密碼難易程度:簡單

我們從Chrome瀏覽器開始。令人失望的是,chrome瀏覽器是最容易被提取密碼的。加密后的密鑰存儲于%APPDATA%\..\Local\Google\Chrome\User Data\Default\Login Data”下的一個SQLite數(shù)據(jù)庫中。但是是如何獲轉(zhuǎn)存并加密的呢?我從《谷歌Chrome瀏覽器是如何存儲密碼的》這篇文章中獲得了Chrome存儲密碼的諸多信息,而這篇文章是4年前寫得。雖然從那篇文章以后Chrome做了些改變,但是我將按照同樣的方式,利用Chromium源碼的一些片段向你展示密碼是如何轉(zhuǎn)儲的。

存儲加密密碼

當(dāng)用戶訪問網(wǎng)站時,Chrome會首先判斷此次登陸是否是一次成功的登錄,判斷代碼片段:

瀏覽器是如何存儲密碼的?

如果成功登錄,并且使用的是一套新的證書,這個證書是瀏覽器之前沒有生成過的,Chrome就會生成一個提示條,詢問用戶是否需要記住密碼:

瀏覽器是如何存儲密碼的?

在此為節(jié)省篇幅,我省略了創(chuàng)建提示條的代碼。當(dāng)點擊“保存密碼”時,就會調(diào)用Chrome密碼管理器的“保存”函數(shù)來響應(yīng)操作:

瀏覽器是如何存儲密碼的?

簡單吧。如果是一次新的會話登錄,就以如下代碼執(zhí)行保存:

瀏覽器是如何存儲密碼的?

再次為控制篇幅,裁剪了一些內(nèi)容(例如一個對證書是否屬于google的網(wǎng)站的操作審查等等)。在這函數(shù)被調(diào)用之后,執(zhí)行AddLoginImpl()函數(shù)的任務(wù)被調(diào)用。這是用來使界面快速響應(yīng)的:

瀏覽器是如何存儲密碼的?

該函數(shù)會調(diào)用登陸數(shù)據(jù)庫對象的AddLogin()函數(shù),以檢查其操作是否成功。下面就是AddLogin()(我保證,我們馬上就要看到密碼是如何存儲的了):

瀏覽器是如何存儲密碼的?

這里有些有趣的東西。我們利用用戶密碼生成一個字符串密鑰。這段代碼已經(jīng)減掉了,但是”sql:Statement”行下面,執(zhí)行了一個SQL查詢語句,實現(xiàn)了在登錄數(shù)據(jù)文件中存儲加密數(shù)據(jù)。該EncryptedString函數(shù)僅僅是在一個加密對象上簡單調(diào)用了EncryptString16函數(shù)(就是下面這個):

瀏覽器是如何存儲密碼的?

最終,我們看到密碼是調(diào)用Windows API函數(shù)CryptProtectData來加密的。這意味著,只有用加密時使用的登陸證書,密碼才能被恢復(fù)。而這根本不是問題,惡意軟件通常就是在用戶登陸環(huán)境下執(zhí)行的。

密碼破譯

在討論如何破譯上面存儲的密碼之前,讓我們首先使用Sqlite瀏覽器來查看一下登陸文件中的數(shù)據(jù):

瀏覽器是如何存儲密碼的?

我們的目的是從這個數(shù)據(jù)庫中抽取出action_url,username_value和password_value(是二進(jìn)制數(shù)據(jù),所以SQLite瀏覽器不能顯示)。而破解密碼,只需要調(diào)用Windows API中的CryptUnprotectData函數(shù)。幸運地是,Python為調(diào)用Windows API準(zhǔn)備了一個完美的叫做pywin32的庫。

先看一下我們使用的PoC:

運行上述代碼,可以看到已經(jīng)成功了!

瀏覽器是如何存儲密碼的?

雖然找到密碼是如何存儲的有點費事(也可以使用其他的動態(tài)方法,但是分析代碼會更透徹),但是解密密碼則幾乎沒費什么力氣。唯一被保護起來的就是密碼的部分,還僅僅保護當(dāng)前用戶。

 

2/4

 

三、IE瀏覽器?

獲得密碼難易程度:簡單/一般/困難(依版本而定)

本質(zhì)上來講,直到IE10之前,IE瀏覽器的密碼管理與Chrome使用的是相同的技術(shù),但有一些有趣的改變。為了全面的展示,我們先簡單討論一下IE7——IE9的密碼存儲,然后再討論在IE10中的變革。

IE7-9瀏覽器

在IE的早期版本中,根據(jù)密碼類型的不同,會被存儲于兩個不同的地方:

注冊表(基于表單的驗證)——這類密碼是提交給諸如Facebook、Gmail之類站點的。

證書文件——HTTP驗證密碼方式,類似于網(wǎng)上登陸證書。

根據(jù)本篇文章需要,接下來討論基于表單驗證的證書,這也是大多數(shù)攻擊者可能選擇的攻擊目標(biāo)。這些證書存儲于如下注冊表鍵位置:

HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\Storage2

用regedit(注冊表編輯器)可以看到值,類似于下面這樣:

瀏覽器是如何存儲密碼的?

正如Chrome中的示例,這些證書使用Windows API中的CryptProtectData函數(shù)加密后儲存。不同之處是該函數(shù)添加了額外的熵(譯者注:熵,熵就是混亂的程度,用來描述某個事件不斷趨向混亂的過程)。這里的熵,就是這注冊表鍵值,它是網(wǎng)站URL的SHA1的校驗和,以供證書使用。

這非常有用,因為當(dāng)用戶訪問網(wǎng)站時,IE能夠迅速根據(jù)URL的哈希值判斷是否已經(jīng)有此證書,之后再用此哈希值完成證書解密。如果攻擊者不知道此處使用了URL,解密證書就會變得很困難。

通常,攻擊者能夠通過歷遍用戶因特網(wǎng)訪問歷史,hash每個URL以及檢查每個存儲證書的方式,來降低此種保護方式的效果。

本文中沒有貼出完整代碼,你可以在這里處獲得完整示例?,F(xiàn)在,我們開始討論IE10。

 

3/4

 

IE10瀏覽器

IE10改變了密碼存儲方式。所有自動填充的密碼存儲于證書管理中一個叫“web證書”的地方,如下圖所示:

瀏覽器是如何存儲密碼的?

個人理解(在這個問題上我找不到更多的信息),這些證書文件存放于%APPDATA%\Local\Microsoft\Vault\[random]目錄下。關(guān)于這些文件是什么及其所用格式,可以在這里找到。

我所知道的是獲得這些密碼并不難。事實上,非常容易。為了支持windows的應(yīng)用商店,微軟提供了一個新的Windows runtime,用來支持更多地API訪問。該winRT提供了對Windows.Security.Credentials namespace的訪問接口,它提供了用來遍歷用戶證書的所有函數(shù)。

事實上,這有一個簡短的C#腳本PoC,在用戶的環(huán)境下執(zhí)行時,它會檢索存儲的密碼:

瀏覽器是如何存儲密碼的?

執(zhí)行該程序后,輸出類似于下圖所示:

瀏覽器是如何存儲密碼的?

注意:我刪除了一些我已經(jīng)禁止IE儲存的站點。除此之外,我也不是很清楚為什么有些憑據(jù)被儲存了起來。

正如你所見,只要我們的程序在特定用戶環(huán)境中執(zhí)行,提取指定用戶使用的所有密碼略繁瑣但還是挺簡單的。下面我們繼續(xù)。

 

4/4

 

四、Firefox瀏覽器

獲得密碼的難易程度:一般/非常困難

接下來談?wù)劚容^棘手的Firefox。主要使用這些幻燈片中的方法獲取關(guān)于用戶數(shù)據(jù)存儲位置的資料。

首先,透露下Firefox的密碼管理的小秘密。為滿足開發(fā)者創(chuàng)建滿足各種安全標(biāo)準(zhǔn)的應(yīng)用程序,Mozilla開發(fā)了一個叫做“Network Security Services”,或叫NSS的開源庫。Firefox使用其中一個叫做”Security Decoder Ring”,或叫SDR的API來幫助實現(xiàn)賬號證書的加密和解密函數(shù)。雖然名字很文藝,我們還是來看看firefox是如何使用它完成加密的:

當(dāng)一個Firefox配置文件被首次創(chuàng)建時,一個叫做SDR的隨機key和一個Salt(譯者注:Salt,在密碼學(xué)中,是指通過在密碼任意固定位置插入特定的字符串,讓散列后的結(jié)果和使用原始密碼的散列結(jié)果不相符,這種過程稱之為“加鹽”)就會被創(chuàng)建并存儲在一個名為“key3.db”的文件中。利用這個key和鹽,使用3DES加密算法來加密用戶名和密碼。密文是Base64編碼的,并存儲在一個叫做signons.sqlite的sqlite數(shù)據(jù)庫中。Signons.sqlite和key3.db文件均位于%APPDATA%\Mozilla\Firefox\Profiles\[random_profile]目錄。

所以我們要做的就是得到SDR密鑰。正如此處解釋的,這個key被保存在一個叫PCKS#11軟件“令牌”的容器中。該令牌被封裝進(jìn)入內(nèi)部編號為PKCS#11的“槽位”中。因此需要訪問該槽位來破譯賬戶證書。

還有一個問題,這個SDR也是用3DES(DES-EDE-CBC)算法加密的。解密密鑰是Mozilla叫做“主密碼”的hash值,以及一個位于key3.db文件中對應(yīng)的叫做“全局鹽”的值。

Firefox用戶可以在瀏覽器的設(shè)置中設(shè)定主密碼,但關(guān)鍵是好多用戶不知道這個特性。正如我們看到的,用戶整個賬號證書的完整性鏈條依賴于安全設(shè)置中選擇的密碼,它是攻擊者唯一不知道的值。如果用戶使用一個強健的主密碼,那么攻擊者想要恢復(fù)存儲的證書是不太可能的。

那么——如果用戶沒有設(shè)置主密碼,空密碼就會被使用。這意味著攻擊者可以提取全局鹽,獲得它與空密碼做hash運算結(jié)果,然后使用該結(jié)果破譯SDR密鑰。再用破譯的SDR密鑰危害用戶證書。

該過程看起來就是這樣:

瀏覽器是如何存儲密碼的?

想知道的更清楚,我們可以簡單查下源代碼。負(fù)責(zé)證書解密的主要函數(shù)是PK11SDR_Decrypt。此處不再展示整個函數(shù),僅分別列出如下被調(diào)用的函數(shù):

PK11_GetInternalKeySlot() //得到內(nèi)部key槽

PK11_Authenticate() //使用主密碼對slot鑒權(quán)

PK11_FindFixedKey() //從slot中獲得SDR密鑰

Pk11_Decrypt() //使用SDR密鑰破譯Base64編碼的數(shù)據(jù)

至于破譯密碼的示例代碼,過程有點復(fù)雜,此處就不再累述了。介紹兩個可以完成此過程的開源工程:

FireMaster – 暴力破解主密碼

ffpasscrack – 推薦的是Python的解決方案。這個方案使用libnss.so庫做負(fù)載DLL。在Windows上使用的話,可以利用cygwin的DLL文件。

五、總結(jié)

希望此文能讓你清楚的了解到瀏覽器是如何存儲密碼的,以及為何在一些情況下不該讓它們存儲。但是,本文不能下這樣的論斷,即瀏覽器存儲密碼一點都不安全。例如,在Firefox瀏覽器案例中,如果采用高強度的主密碼,賬號的細(xì)節(jié)資料是非常難獲取的。

若是采用別的密碼管理,比如LastPass、KeePass,則是極好的方案,也可以借助設(shè)備采用雙因素認(rèn)證,比如Yubkey。

來源:51CTO

更多精彩內(nèi)容,請關(guān)注人人都是產(chǎn)品經(jīng)理微信公眾號或下載App
評論
評論請登錄
  1. 目前還沒評論,等你發(fā)揮!