針對(duì)Linux系統(tǒng)全盤(pán)加密的啟動(dòng)攻擊
攻擊
由于市面上沒(méi)有現(xiàn)成的工具能夠執(zhí)行這種攻擊,所以我們自己制作了工具,并把它命名為EvilAbigail。Evil maid攻擊可以針對(duì)任何操作系統(tǒng)。此次的研究我們針對(duì)的是使用LUKS全盤(pán)加密的Linux系統(tǒng)。
一般來(lái)說(shuō),當(dāng)Linux系統(tǒng)使用了全盤(pán)加密后,會(huì)由一小塊分區(qū)還是沒(méi)有加密,這個(gè)區(qū)域就是用來(lái)解密和引導(dǎo)加密磁盤(pán)的。這個(gè)分區(qū)會(huì)掛載在/boot,并且包含內(nèi)核和初始RAM磁盤(pán)(initrd)。雖然攻擊內(nèi)核或者bootloader也是可行的,但是我們還是針對(duì)initrd進(jìn)行了攻擊。
initrd是指一個(gè)臨時(shí)文件系統(tǒng),它在啟動(dòng)階段被Linux內(nèi)核調(diào)用。initrd主要用于當(dāng)root文件系統(tǒng)被掛載之前,進(jìn)行準(zhǔn)備工作。initrd 中包含了是解密和掛載root文件系統(tǒng)所需要的目錄和可執(zhí)行程序的最小集合。一旦initrd任務(wù)完成,它就會(huì)執(zhí)行pivot_root,從而將initrd根文件系統(tǒng)卸載掉,并掛載真正的根文件系統(tǒng)。
一般來(lái)說(shuō),initrd是一個(gè)通過(guò)gzip壓縮的cpio鏡像。我們測(cè)試的基于Debian的操作系統(tǒng)是這樣,但基于RedHat的操作系統(tǒng) (Fedora, RHEL, CentOS)現(xiàn)在使用的是dracut,包含一個(gè)未壓縮的cpio鏡像。基于Debian的initrds 會(huì)用ash shell腳本執(zhí)行啟動(dòng),而dracut則會(huì)用systemd和它所關(guān)聯(lián)的配置方法。
為了執(zhí)行我們的攻擊,我們選擇使用一個(gè)基于LD_PRELOAD的bootkit,但是其實(shí)也可以注入惡意的內(nèi)核或可執(zhí)行文件中。我們使用LD_PRELOAD的主要目標(biāo)是對(duì)剛剛解密完成的root文件系統(tǒng)中的第一個(gè)可執(zhí)行文件注入一個(gè)共享對(duì)象。第一個(gè)可執(zhí)行文件通常是/sbin/init,PID一般會(huì)是1。進(jìn)行攻擊最簡(jiǎn)單的方法就是修改init腳本,導(dǎo)出這個(gè)環(huán)境變量,這樣執(zhí)行pivot_root的時(shí)候環(huán)境變量就設(shè)置好了。因?yàn)楫?dāng)文件系統(tǒng)更改的時(shí)候還得在合適的時(shí)候(解密之后)把共享對(duì)象復(fù)制到新系統(tǒng)中。把以下這兩行放入initrd的init腳本中,插在切換文件系統(tǒng)之前:
cp /hack.so /${rootmnt}/hack.so
export LD_PRELOAD=/hack.so
之所以這樣可行是因?yàn)檎嬲膔oot文件系統(tǒng)是在臨時(shí)root文件系統(tǒng)下解密掛載的,這先于pivot,并且rootmnt變量是用掛載點(diǎn)位置填充的。但是,在這之前需要把目標(biāo)文件系統(tǒng)重新掛載成讀寫(xiě),因?yàn)槟J(rèn)是只讀的。在我們的例子中我們對(duì)init腳本進(jìn)行了修改,修改了腳本分析內(nèi)核命令行的地方,因此無(wú)論提供的參數(shù)是什么,root文件系統(tǒng)都是讀寫(xiě)方式掛載。另一種方法是在注入的命令中添加mount -o remount,rw /${rootmnt}。
不過(guò)基于dracut的initrds中不存在注入點(diǎn),因?yàn)閕nit的可執(zhí)行文件是個(gè)二進(jìn)制文件而非shell腳本。這就給我們帶來(lái)了三個(gè)問(wèn)題,只有克服了這三個(gè)問(wèn)題我們才能夠注入到pid 1進(jìn)程中。
三個(gè)問(wèn)題
第一個(gè)問(wèn)題是有關(guān)復(fù)制我們的二進(jìn)制文件到解密的root文件系統(tǒng)中。這個(gè)問(wèn)題是三個(gè)問(wèn)題中最好解決的一個(gè)。我們可以加兩個(gè)ExecPre指令到負(fù)責(zé)pivote文件系統(tǒng)的systemd服務(wù)文件中。這基本就相當(dāng)于前面提到的插入腳本的方法。第一個(gè)命令會(huì)以讀寫(xiě)方式重新掛載root文件系統(tǒng),第二個(gè)執(zhí)行復(fù)制操作。
第二個(gè)問(wèn)題有關(guān)LD_PRELOAD。因?yàn)槲覀儾皇窃谛薷膕hell腳本,我們不能把環(huán)境變量傳遞給這個(gè)進(jìn)程(因?yàn)樗怯蓛?nèi)核調(diào)用的),因此加載我們的共享對(duì)象就有點(diǎn)棘手了。最簡(jiǎn)單的辦法就是,先把init二進(jìn)制文件移動(dòng)到另一個(gè)位置,然后在它原來(lái)的位置插入我們自己的shell腳本,最后再執(zhí)行原來(lái)的二進(jìn)制文件。我們只需要兩行代碼,第一行導(dǎo)出LD_PRELOAD,第二行執(zhí)行原來(lái)的systemd二進(jìn)制文件。請(qǐng)注意,這樣注入的是initrd中的pid 1進(jìn)程,而不是最終root文件系統(tǒng)的pid 1。
第三個(gè)問(wèn)題就是,在調(diào)用switch-root命令之前,systemd會(huì)用clearenv()函數(shù)清除所有環(huán)境變量。因?yàn)檫@個(gè)函數(shù)是標(biāo)準(zhǔn)庫(kù)的一部分,我們就可以重寫(xiě)這個(gè)函數(shù),讓被注入的進(jìn)程會(huì)調(diào)用我們的函數(shù)而不是原來(lái)的函數(shù)。我們不關(guān)心真正清除環(huán)境變量,我們寫(xiě)的clearenv()函數(shù)會(huì)清除所有環(huán)境變量,然后把我們的LD_PRELOAD變量注入到環(huán)境中。由于clearenv()只會(huì)被調(diào)用一次,我們的修改不會(huì)導(dǎo)致任何副作用。
解決了以上這三個(gè)問(wèn)題之后,我們的共享對(duì)新就會(huì)被復(fù)制到加密的root文件系統(tǒng)中,我們的LD_PRELOAD會(huì)被注入到目標(biāo)文件系統(tǒng)的pid 1進(jìn)程中。接下來(lái)我們就可以獲取用于解密的用戶密碼。
對(duì)于Debian的initrds,可執(zhí)行文件會(huì)要求用戶輸入密碼,然后解密、掛載root文件系統(tǒng)。我們可以把我們的腳本注入到pipeline進(jìn)程中從而獲取密碼。
至于systemd,它會(huì)通過(guò)Unix domain sockets使用一種更復(fù)雜的進(jìn)程間通信。我們選擇攻擊文件系統(tǒng)的掛載,而非這個(gè)進(jìn)程。這又是一個(gè)庫(kù)函數(shù),它在動(dòng)態(tài)加載庫(kù)中,從systemd里調(diào)用,所以我們可以hook這個(gè)函數(shù)。解密硬盤(pán)的函數(shù)叫做crypt_activate_by_passphrase。這個(gè)函數(shù)會(huì)把密碼作為char數(shù)組。通過(guò)hook這個(gè)函數(shù),我們可以獲取到密碼。我們要包裹這個(gè)原來(lái)的函數(shù),所以我們用dlsym打開(kāi)真正的函數(shù),并且調(diào)用它。不過(guò)在此之前我們會(huì)保存密碼以便以后取回。
為了“保存”密碼,我們簡(jiǎn)單地把密碼加到我們之后要復(fù)制到root文件系統(tǒng)的共享對(duì)象中。之所以選擇這種方法是因?yàn)槲覀円呀?jīng)知道這個(gè)文件存在,并且會(huì)被復(fù)制過(guò)去。采用這種方法還會(huì)減少我們接觸到的磁盤(pán)文件的數(shù)量。為了獲取密碼,我們之后會(huì)讀取我們自己文件末尾(通過(guò)LD_PRELOAD變量定位),然后把它設(shè)置為我們的反彈shell中PASSWORD環(huán)境變量的值,因此(以meterpreter為例)通過(guò)‘getenv PASSWORD’命令可以獲取用于解密磁盤(pán)的密碼。由于我們所有的目標(biāo)主機(jī)都默認(rèn)安裝了python,所以我們就使用了python meterpreter反彈shell。
解決方案
解決這種問(wèn)題有很多方法。但是即使使用了這些解決方法,如果攻擊者能夠物理接觸計(jì)算機(jī),并且有足夠的時(shí)間重刷BIOS/UEFI,那也是防不住的。
第一種方法是把bootloader、內(nèi)核和initrd放在外置的U盤(pán)上,然后從U盤(pán)上啟動(dòng)從而替代/boot分區(qū)。但對(duì)用戶來(lái)說(shuō)這個(gè)方法很糟糕,因?yàn)樗麄冸x開(kāi)筆記本的時(shí)候要記得拔掉U盤(pán),如果沒(méi)有卸載的話還要安全卸載/boot分區(qū)。更新的時(shí)候也很麻煩,要插上U盤(pán)才能更新initrd/內(nèi)核。
另一種方案則是徹底關(guān)閉從外置媒體啟動(dòng)系統(tǒng)。這樣就不存在自動(dòng)化攻擊的可能性了,但是某些情況下,如對(duì)于包含shell的Debian initrds,還是可以從initrd人工掛載和修改initrd的。這可以通過(guò)自動(dòng)鍵盤(pán)式設(shè)備完成,這樣就繞過(guò)了無(wú)法通過(guò)外置媒體啟動(dòng)系統(tǒng)的限制。
另外,還可以開(kāi)啟BIOS啟動(dòng)密碼,這樣沒(méi)有密碼的人就無(wú)法啟動(dòng)計(jì)算機(jī)了。
不過(guò)如果攻擊者有足夠的時(shí)間把硬盤(pán)拆下,然后用他們自己的筆記本啟動(dòng)硬盤(pán)的話,后兩種方案也不管用了。
最后,最安全的方案就是將SecureBoot拓展到initrd。SecureBoot可以驗(yàn)證bootloader和內(nèi)核,如果能夠驗(yàn)證經(jīng)過(guò)簽名的initrd的話,要不留痕跡地在/boot分區(qū)修改任何東西都會(huì)很困難。但是如果攻擊者可以通過(guò)刷BIOS/UEFI關(guān)閉secureboot的話,這種方案也沒(méi)用了。
防止這類攻擊最好的方法就是不要讓你的設(shè)備落入攻擊者們的手中,我們的PoC攻擊可以在2分鐘內(nèi)攻陷所有的目標(biāo)主機(jī),但在現(xiàn)實(shí)世界中,攻擊者也可以做出攻擊特定目標(biāo)的payload,這樣的payload只用幾秒就可以攻擊設(shè)備。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
版權(quán)聲明:本站文章來(lái)源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請(qǐng)保持原文完整并注明來(lái)源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來(lái)源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來(lái),僅供學(xué)習(xí)參考,不代表本站立場(chǎng),如有內(nèi)容涉嫌侵權(quán),請(qǐng)聯(lián)系alex-e#qq.com處理。