方圓 盛劍橋 張亮 丁鑫
摘要:容器提供了一種邏輯打包機(jī)制,以這種機(jī)制打包的應(yīng)用可以脫離其實(shí)際運(yùn)行的環(huán)境。利用這種脫離,不管目標(biāo)環(huán)境是私有數(shù)據(jù)中心、公有云,還是開發(fā)者的個人筆記本電腦,都可以輕松、一致地部署基于容器的應(yīng)用。隨著容器技術(shù)的應(yīng)用,容器內(nèi)的安全性也同樣面臨著威脅。而不管是什么樣的攻擊方式最終都需要以程序的方式來執(zhí)行黑客的攻擊手段。進(jìn)程的生成由Linux 內(nèi)核接管,目前沒有對外放出進(jìn)程生成管理的接口,而如果以內(nèi)核級代碼進(jìn)行生成管理,若出一點(diǎn)意外將導(dǎo)致整個系統(tǒng)崩潰,無法使用。該研究是基于容器運(yùn)行的機(jī)制并結(jié)合Linux系統(tǒng)的特性,在應(yīng)用層接管進(jìn)程的生成管理,并對惡意進(jìn)程的生成進(jìn)行阻斷生成。
關(guān)鍵詞:容器;容器安全;進(jìn)程阻斷
中圖分類號:TP393??? 文獻(xiàn)標(biāo)識碼:A
文章編號:1009-3044(2021)28-0012-05
在云原生技術(shù)的應(yīng)用廣泛下,容器技術(shù)也得到了極大的推廣。越來越多的公司把服務(wù)從本地遷到云上,服務(wù)也越來越契合云原生框架。而容器是Paas(Platform-as-a-Service,平臺即服務(wù))的一種體現(xiàn),將所需軟件整合成一個應(yīng)用,一個服務(wù)。
容器技術(shù)的應(yīng)用提高了應(yīng)用程序的可移植性,容器中運(yùn)行的應(yīng)用程序可以輕松部署到多個不同的操作系統(tǒng)和硬件平臺。與傳統(tǒng)或硬件虛擬機(jī)環(huán)境相比,容器所需的系統(tǒng)資源更少,因?yàn)樗鼈儾话僮飨到y(tǒng)映像。容器中的應(yīng)用程序無論部署在何處,都會運(yùn)行相同的應(yīng)用程序,從而程序的操作得到一致和統(tǒng)一。
容器的虛擬技術(shù)應(yīng)用在帶來方便和高效的同時(shí),也成為黑客入侵攻擊的高地。
1研究背景
1.1背景分析
徐孝晉[1]等學(xué)者通過容器安全性弱點(diǎn)的研究,提到對于容器相比重量級虛擬化技術(shù),容器技術(shù)實(shí)現(xiàn)的是非硬件級虛擬化;同時(shí)它的實(shí)現(xiàn)和設(shè)計(jì)原理是將主機(jī)內(nèi)核進(jìn)行隔離,相比傳統(tǒng)虛擬化技術(shù)具有更高的安全性。這主要在于傳統(tǒng)的虛擬化技術(shù)是圍繞虛擬機(jī)內(nèi)核通信處理,阻斷主機(jī)內(nèi)核層的通信;由于容器技術(shù)沒有使用這個限定,容器技術(shù)的主機(jī)內(nèi)核呈“曝光式”,因此攻擊者也就可以直接對內(nèi)(主機(jī)內(nèi)核)發(fā)動惡意攻擊,無須繞行,直接參與主機(jī)內(nèi)核處理的過程便是容器安全性的關(guān)鍵問題所在,隔離性不強(qiáng)是容器安全性弱點(diǎn)的比較根本的原因之一。相對于KVM虛擬化技術(shù),容器中沒有虛擬出硬件,而是和系統(tǒng)共用,這也會導(dǎo)致系統(tǒng)的安全問題,同時(shí)也是容器的安全問題,并且容器自身的安全問題會感染到系統(tǒng)。
進(jìn)一步的觀察容器各個組件的安全性,由于責(zé)任不一樣表現(xiàn)出不一樣的特點(diǎn)。根據(jù)魯濤等人[2]對容器中的網(wǎng)絡(luò)、鏡像、容器、倉庫、容器所依賴的Linux 內(nèi)核、容器軟件本身等六個角度逐類分析其中存在的安全威脅,可以看到容器中主要組件的脆弱性不一樣,需要對各個組件有針對性地加固。
還有研究發(fā)現(xiàn)有因?yàn)槿萜髯陨淼呐渲貌划?dāng)而引起的安全問題[3]。例如若以root 權(quán)限啟動容器,一旦攻擊者入侵容器中,即擁有了主機(jī)內(nèi)核的所有功能,容器幾乎可以做主機(jī)可以做的一切。
1.2容器安全實(shí)踐
國內(nèi)外對容器技術(shù)安全有著不同的定義和安全標(biāo)準(zhǔn)規(guī)范。國外起步比國內(nèi)早,權(quán)威機(jī)構(gòu)美國國家標(biāo)準(zhǔn)與技術(shù)研究院發(fā)布了《NIST.SP.800—190應(yīng)用容器安全指南》作為國外容器安全的標(biāo)準(zhǔn)參考,目前國內(nèi)在容器安全仍處研究和探索階段,主要還是依靠一些研究機(jī)構(gòu)、云廠商和安全廠商,針對容器的安全性提出各自的防護(hù)意見[4]。
Dosec團(tuán)隊(duì)提出通過對靜態(tài)的容器鏡像掃描,發(fā)現(xiàn)文件漏洞和不安全的配置信息,幫助用戶解決傳統(tǒng)安全軟件無法感知的容器環(huán)境問題,同時(shí)提供容器進(jìn)程白名單、文件只讀保護(hù)和容器逃逸檢測功能,能有效防止容器運(yùn)行時(shí)安全風(fēng)險(xiǎn)事件的發(fā)生[5]。
綠盟安全廠商提出的容器安全解決方案,包括對容器鏡像、倉庫進(jìn)行漏洞掃描,對容器訪問控制,容器異常行為檢測等實(shí)現(xiàn)容器的防護(hù)功能[6]。
各個容器安全廠商都針對容器的特性和機(jī)制按各自的技術(shù)亮點(diǎn)進(jìn)行安全加固。但其實(shí),容器自身的機(jī)制也是可以通過檢測流程或者修改配置達(dá)到一定的安全加固[7],如:容器鏡像安全機(jī)制、容器虛擬化安全機(jī)制、容器網(wǎng)絡(luò)安全機(jī)制等。
2容器運(yùn)行時(shí)安全問題
容器運(yùn)行的安全保障主要來自 Linux 自帶的三個機(jī)制:Seccomp、AppArmor、SELinux。
Seccomp(secure computing mode)于2005年首次被引入 Linux 內(nèi)核。它是一種用于限制允許應(yīng)用程序進(jìn)行的系統(tǒng)調(diào)用 API 的機(jī)制。通過設(shè)置 seccomp 配置文件,讓容器在啟動的時(shí)候加載設(shè)置的seccomp 配置。配置文件內(nèi)可以設(shè)置容器內(nèi)進(jìn)程允許和不允許的系統(tǒng)調(diào)用API 。容器根據(jù)設(shè)置配置內(nèi)容,當(dāng)容器內(nèi)的進(jìn)程使用了配置內(nèi)不允許的系統(tǒng)調(diào)用API 時(shí),seccomp 會主動切斷進(jìn)程調(diào)用的系統(tǒng)API,從而達(dá)到限制惡意進(jìn)程的使用非法的問題,但同時(shí)缺陷也是很明顯。Seccomp 配置應(yīng)用范圍是整個容器而不是單個進(jìn)程,在限制惡意進(jìn)程使用系統(tǒng)調(diào)用 API,同時(shí)也在限制非惡意進(jìn)程使用系統(tǒng)調(diào)用 API,沒辦法在 Seccomp 里面做惡意與非惡意的區(qū)別。并且根據(jù)惡意風(fēng)險(xiǎn)不斷的增強(qiáng),seccomp 也需要更新配置文件,但是seccomp 不允許運(yùn)行著的容器動態(tài)加載seccomp 配置文件,只能通過把容器停下,修改完配置文件再重新加載。
AppArmor(Application Armor)是可以在 Linux 內(nèi)核部中啟用的少數(shù)Linux安全模塊(LSM)之一。在AppArmor中,可以將配置文件與可執(zhí)行文件關(guān)聯(lián),從而根據(jù)功能和文件訪問權(quán)限確定允許該文件執(zhí)行的操作。AppArmor和其他的LSM實(shí)施強(qiáng)行訪問控制,而強(qiáng)行訪問控制由管理員設(shè)置。一旦設(shè)置成功,其他用戶將無權(quán)修改該控制或?qū)⑵鋫鬟f給另一個用戶。在某種意義上,如果自己賬戶擁有文件,則可以授予其他用戶對該文件的訪問權(quán)限(除非此文件被強(qiáng)制訪問控制所覆蓋),或者可以將其設(shè)置為不可通過自己的用戶賬戶寫,以防止自己無意中更改。使用強(qiáng)制性訪問控制使管理員可以更細(xì)地控制其系統(tǒng)上可能發(fā)生的情況,而這是單個用戶無法覆蓋的方式。
SELinux(Security-Enhanced Linux)是Read Hat開發(fā)的另一種LSM,但是大多數(shù)人認(rèn)為它起源于美國國家安全局的項(xiàng)目。SELinux可以限制進(jìn)程與文件和其他進(jìn)程的相互作用,并且每個進(jìn)程都在SELinux的作用域下。SELinux權(quán)限和常規(guī)的DAC? Linux權(quán)限之間的主要區(qū)別在于:在SELinux中權(quán)限與用戶身份無關(guān),它們完全由標(biāo)簽描述。也就是說,它們是一起工作的,因此DAC和SELinux都必須允許采取對應(yīng)設(shè)置的措施。但是SE? Linux必須先在計(jì)算機(jī)上的每個文件上標(biāo)記其SELinux信息,然后才能執(zhí)行策略。這些策略可以指示特定域的進(jìn)程對特定類型的文件具有什么訪問權(quán)限。實(shí)際上,這意味著可以限制應(yīng)用程序只能訪問其自己的文件,并阻止其他任何進(jìn)程訪問這些文件。如果應(yīng)用程序受到威脅,即使正常的自由訪問控制允許它,SELinux也會限制可能影響的文件集。
2.1容器運(yùn)行的安全風(fēng)險(xiǎn)
2.1.1混亂的容器鏡像
容器的運(yùn)行依賴容器鏡像,如果容器鏡像從最開始就得不到安全保障,那運(yùn)行起來的容器就更沒有安全保障?,F(xiàn)在市面上容器鏡像有很多第三方倉庫,除了遵守基本的傳輸協(xié)議,容器鏡像安全沒有一個統(tǒng)一的安全檢查標(biāo)準(zhǔn),更不用說對容器鏡像安全的檢查,達(dá)不到對容器鏡像精簡、高效、安全的要求。
2.1.2容器運(yùn)行時(shí)資源占用
容器可以通過cgroup機(jī)制來控制整個容器的資源使用,但是卻沒辦法知道容器內(nèi)部具體的資源占用情況。如果一個容器被黑客占據(jù)在里面跑挖礦相關(guān)的程序,僅從容器外和資源占用情況是無法知道具體容器內(nèi)被哪個進(jìn)程占用過高的資源,反復(fù)停止、重啟容器也無法解決這類問題。
2.1.3容器內(nèi)運(yùn)行病毒
黑客入侵容器中一般有兩種方式,一種是通過容器與外網(wǎng)之間的連接進(jìn)入容器內(nèi),并留下病毒文件讓容器執(zhí)行。另一種是通過容器鏡像,在容器還未真地運(yùn)行起來就把病毒文件嵌入到鏡像內(nèi),當(dāng)容器運(yùn)行時(shí)就會把病毒文件運(yùn)行起來。不管黑客用哪種方式入侵容器內(nèi),當(dāng)入侵系統(tǒng)后往往會注入更多的工具進(jìn)行攻擊,比如滲透工具或挖礦軟件等。而如果開發(fā)人員直接在容器中注入鏡像外的可執(zhí)行程序則相當(dāng)于繞開了鏡像安全掃描管控,一定會造成黑客在容器內(nèi)利用漏洞逃逸,對主機(jī)勒索、破壞等惡意行為。
2.1.4容器啟動參數(shù)
鏡像中的entrypoint, cmd, volumes, env, ports, users, workdir參數(shù)限定了容器運(yùn)行的行為,然而這些參數(shù)可以在啟動鏡像時(shí)被啟動參數(shù)所覆蓋,這就導(dǎo)致了容器行為無法受控。比如用戶可以以bin/bash 啟動容器從而進(jìn)入容器內(nèi)部shell,或掛載主機(jī)上的重要系統(tǒng)文件,從而帶來安全隱患和風(fēng)險(xiǎn)。
2.2容器讀寫
2.2.1文件保護(hù)
容器內(nèi)部中大部分目錄都是靜態(tài)的,包括etc、lib、usr等系統(tǒng)目錄。關(guān)鍵的應(yīng)用目錄也應(yīng)該設(shè)置只讀保護(hù)以防止黑客進(jìn)行篡改和攻擊。
2.2.2容器讀寫控制
容器本身允許有讀寫行為的存在。但是如果容器被黑客控制,而容器本身的讀寫控制也同時(shí)下發(fā)到容器內(nèi),那黑客的惡意病毒文件利用漏洞同樣是可以獲取對應(yīng)的讀寫權(quán)限,可以針對容器的敏感數(shù)據(jù)進(jìn)行讀取,同時(shí)可以通過寫的權(quán)限,破壞容器內(nèi)部數(shù)據(jù)的完整性。
2.2.3環(huán)境變量加密
容器的環(huán)境變量中往往包含密碼和敏感信息,而擁有In?spect權(quán)限的用戶可以輕易地查看容器的環(huán)境變量從而導(dǎo)致信息的泄露。
3容器運(yùn)行分析
容器是一種操作系統(tǒng)虛擬化形式。可以使用一個容器運(yùn)行從小型微服務(wù)或軟件進(jìn)程到大型應(yīng)用程序的所有內(nèi)容。容器包含所有必要的可執(zhí)行文件、二進(jìn)制代碼、庫和配置文件。但是與服務(wù)器或計(jì)算機(jī)虛擬化方法不同,容器不包含操作系統(tǒng)映像。因此,它們更輕便且可移植,其開銷很小。而容器的運(yùn)行也是依賴主機(jī)提供的特征來做的虛擬化。
3.1容器的隔離性
容器建立在兩項(xiàng)關(guān)鍵技術(shù)之上:Linux Namespace 和Linux Cgroups。
Namespace 創(chuàng)建一個近乎隔離的用戶空間,并為應(yīng)用程序提供系統(tǒng)資源(文件系統(tǒng)、網(wǎng)絡(luò)棧、進(jìn)程和用戶ID)。Cgroup強(qiáng)制限制硬件資源,如CPU、內(nèi)存、設(shè)備和網(wǎng)絡(luò)等。在Namespace 的作用下容器內(nèi)部看到的資源視圖是單獨(dú)屬于容器自身,并且隔離出來的資源做的任何操作都不會影響到主機(jī)側(cè)。通過Cgroup功能,在主機(jī)側(cè)把主機(jī)本身的動態(tài)硬件資源按一定的用戶設(shè)置分配給對應(yīng)的容器,控制容器運(yùn)行動態(tài)資源的上限。在 Linux Namespace 和Linux Cgroups功能下對Linux主機(jī)做到靜態(tài)動態(tài)資源的分配和隔離,這并不代表容器本身就是安全的。隔離帶來了防護(hù)性,但同時(shí)也成為黑客的攻擊點(diǎn)。
3.2容器運(yùn)行時(shí)安全
容器和VM(Virtual Machine)不同之處在于VM模擬硬件系統(tǒng),每個VM都可以在獨(dú)立環(huán)境中運(yùn)行OS,管理程序模擬CPU、內(nèi)存、存儲、網(wǎng)絡(luò)資源等。容器正好與之反,雖然是一個獨(dú)立運(yùn)行環(huán)境,但是與主機(jī)的任何程序都是共享CPU、內(nèi)存、存儲、網(wǎng)絡(luò)資源,特別是共享了一個Linux 內(nèi)核。這也造成了容器相對于主機(jī)而言,在運(yùn)行的攻擊面也有所不同,如圖1所示。
容器一共有七個攻擊面:Linux Kernel、Namespace/Cgroups/ Aufs、Seccomp-bpf、Libs、Language VM、User Code、Container engine。
3.2.1 Linux 內(nèi)核漏洞
容器的內(nèi)核與宿主內(nèi)核共享,使用Namespace 與Cgroups這兩項(xiàng)技術(shù),使容器內(nèi)的資源與宿主機(jī)隔離,所以Linux 內(nèi)核產(chǎn)生的漏洞會導(dǎo)致容器逃逸。容器逃逸和內(nèi)核提權(quán)只有細(xì)微的差別,需要突破namespace 的限制。在容器內(nèi)運(yùn)行程序,收集有幫助的信息,然后觸發(fā)漏洞去執(zhí)行特權(quán)代碼,達(dá)到攬權(quán)的效果。而在容器內(nèi)一旦拿到最高的權(quán)限,namespace 本身的限制是沒有意義的,同宿主側(cè)一樣可以隨意操作獲取任何信息,如圖2 所示。
3.2.2不安全的部署配置
在實(shí)際中,我們經(jīng)常會遇到這種狀況:不同的業(yè)務(wù)會根據(jù)自身業(yè)務(wù)需求提供一套自己的配置,而這套配置并未得到有效的管控審計(jì),使得內(nèi)部環(huán)境變得復(fù)雜多樣,無形之中又增加了很多風(fēng)險(xiǎn)點(diǎn)。最常見的包括:
(1)特權(quán)容器或者以root 權(quán)限運(yùn)行容器;
(2)不合理的Capability 配置(權(quán)限過大的Capability)。
3.2.3容器內(nèi)部攻擊
不管容器內(nèi)以什么樣的方式被入侵,所有的行為都是依靠程序作為媒介來運(yùn)行其中的行為邏輯。那么只要對程序的行為進(jìn)行監(jiān)控,只要發(fā)現(xiàn)有危險(xiǎn)的行為就中斷程序的運(yùn)行。
結(jié)合容器本身的功能定義,一般只會運(yùn)行指定的一個業(yè)務(wù)邏輯程序,不會再刻意加載其它的程序。只要對容器內(nèi)部做程序加載監(jiān)控,阻斷非指定程序的加載,就能避免惡意程序在容器內(nèi)部被加載運(yùn)行,從而避免了被攻擊的可能。
4應(yīng)用層進(jìn)程生成阻斷分析
容器本質(zhì)是 Linux 下的特殊進(jìn)程,與應(yīng)用層的進(jìn)程共享 Linux 內(nèi)核。而在容器內(nèi)生成進(jìn)程的流程跟Linux應(yīng)用層生成進(jìn)程流程是一樣的,只是最終應(yīng)用的環(huán)境是在容器內(nèi)。
4.1進(jìn)程生成基本流程
Linux 系統(tǒng)創(chuàng)建進(jìn)程使用 fork()、vfork()、clone()和 exec()。 fork()、vfork()、clone()在當(dāng)前進(jìn)程的環(huán)境下,再創(chuàng)建出一個新的進(jìn)程運(yùn)行環(huán)境,也就是子進(jìn)程,并且子進(jìn)程會有自己的pid,ppid與父進(jìn)程區(qū)分開;而此時(shí)的進(jìn)程是一個空的狀態(tài),也就只有一個進(jìn)程環(huán)境,并沒有進(jìn)程運(yùn)行的業(yè)務(wù)邏輯代碼。這三個函數(shù)接口是應(yīng)用層封閉的內(nèi)核創(chuàng)建進(jìn)程的功能,而這三個函數(shù)接口最終都會進(jìn)到內(nèi)核中調(diào)用_do_fork()來創(chuàng)建進(jìn)程,而這三個函數(shù)接口的區(qū)別也只是對應(yīng)的flag 不同。如圖3所示。
exec()用于讀取可執(zhí)行文件并載入上面新生成的進(jìn)程空間內(nèi)執(zhí)行可執(zhí)行文件內(nèi)的業(yè)務(wù)邏輯代碼;一般稱之為 exec 函數(shù)族,有一系列的exec 開頭的函數(shù)接口,比如:execl(),execve()等。 Exec()系列函數(shù)與fork()、vfork()、clone()函數(shù)接口一起使用,生成一個完整、獨(dú)立的進(jìn)程。而他們時(shí)序關(guān)系如圖4所示。
4.2進(jìn)程阻斷原理&Linux 系統(tǒng)調(diào)用Hook技術(shù)
根據(jù)3.1里面的進(jìn)程生成原理,把一個可執(zhí)行文件創(chuàng)造成執(zhí)行的進(jìn)程需要兩個步驟:
步驟1:使用fork()、vfork()、clone()中的一個函數(shù)生成全新的進(jìn)程運(yùn)行環(huán)境。
步驟2:使用exec()系列函數(shù)加載可執(zhí)行文件。
而在步驟1 中,只是單純地生成程序運(yùn)行環(huán)境,跟實(shí)際的業(yè)務(wù)邏輯沒有連接關(guān)系,并且沒有任何特征可以表明生成的程序運(yùn)行環(huán)境是做什么用的。而在步驟2中使用exec()系列函數(shù)是會傳入需要執(zhí)行的對應(yīng)業(yè)務(wù)邏輯代碼的地址;以此邏輯代碼地址找到對應(yīng)的業(yè)務(wù)邏輯并做判斷,再讓exec()系列函數(shù)的調(diào)用失敗,就可以做到不讓對應(yīng)的可執(zhí)行文件運(yùn)行起來。而exec ()系統(tǒng)函數(shù)都是對系統(tǒng)調(diào)用中的execve()函數(shù)做的封閉,最終都是調(diào)用的系統(tǒng)調(diào)用execve();使用Linux Hook技術(shù)替換成帶檢測進(jìn)程特征的函數(shù),就能對進(jìn)程的生成做干預(yù)。
系統(tǒng)調(diào)用(syscall)是一個通用的概念,它既包括應(yīng)用層系統(tǒng)函數(shù)庫的調(diào)用,也包括內(nèi)核層系統(tǒng)提供的syscall_table提供的系統(tǒng)api。Hook技術(shù)是一個相對較寬的話題,因?yàn)椴僮飨到y(tǒng)從ring3到ring0是分層次的結(jié)構(gòu),在每一個層次上都可以進(jìn)行相應(yīng)的Hook,它們使用的技術(shù)方法以及取得的效果也是不盡相同的。而在容器內(nèi),本身就只有應(yīng)用層的內(nèi)容也就是ring3層的環(huán)境視圖,所以只能在ring3層做Hook處理,來實(shí)現(xiàn)系統(tǒng)調(diào)用的監(jiān)控功能。
4.3 ring3 Hook技術(shù)之動態(tài)連接so 函數(shù)劫持
LD_PRELOAD hook 技術(shù)屬于 so 依賴劫持技術(shù)的一種實(shí)現(xiàn),若要討論這種技術(shù)的技術(shù)原理先來看一下linux操作系統(tǒng)加載so 的底層原理,包括Linux 系統(tǒng)在內(nèi)的很多開源系統(tǒng)都是基于glibc的,動態(tài)鏈接的ELF可執(zhí)行文件在啟動時(shí)同時(shí)會啟動動態(tài)鏈接器(/lib/ld-linux.so.X),程序所依賴的共享對象全部由動態(tài)鏈接器負(fù)責(zé)裝載和初始化,所以這里所謂的共享庫的查找過程本質(zhì)上就是動態(tài)鏈接器(/lib/ld-linux.so.X)對共享庫路徑的搜索過程。
4.3.1/etc/ld.so.cache共享庫搜索
Linux為了加速LD_PRELOAD 的搜索過程,在系統(tǒng)中建立了一個ldconfig程序,這個程序負(fù)責(zé)將共享庫下的各個共享庫維護(hù)一個SO-NAME(一一對應(yīng)的符號鏈接),這樣每個共享庫的 SO-NAME就能夠指向正確的共享庫文件。將全部SO-NAME 收集起來集中放到/etc/ld.so.cache文件里面,并建立一個 SO- NAME 的緩存。當(dāng)動態(tài)鏈接器要查找共享庫時(shí),它可以直接從/ etc/ld.so.cache里面查找。所以,如果我們在系統(tǒng)指定的共享庫目錄下添加、刪除或更新任何一個共享庫,或者我們更改了/ etc/ld.so.conf、/etc/ld.preload的配置,都應(yīng)該運(yùn)行一次ldconfig這個程序,以便更新 SO-NAME 和/etc/ld.so.cache,很多軟件包的安裝程序在結(jié)束共享庫安裝以后都會調(diào)用ldconfig
4.3.2/etc/ld.so.preload配置搜索
Linux 動態(tài)共享庫加載器根據(jù)/etc/ld.so.preload文件中的配置順序進(jìn)行逐行廣度搜索,而該配置文件中保存了需要搜索的共享庫路徑。
4.3.3環(huán)境變量搜索
在/etc/environment 文件內(nèi)存放著當(dāng)前程序運(yùn)行環(huán)境的默認(rèn)的全部環(huán)境變量值。而其中LD_LIBRARY_PATH 項(xiàng)根據(jù)指定的動態(tài)庫搜索路徑,Linux動態(tài)共享庫加載器會根據(jù)該選項(xiàng)內(nèi)的值按順序進(jìn)行搜索。
4.3.4 ELF文件中的配置信息搜索
任何一個動態(tài)鏈接的模塊所依賴的模塊路徑保存在“.dy?namic”段中,由DT_NEED 類型的項(xiàng)表示,動態(tài)鏈接器會按照這個路徑去查找DT_RPATH 所指定的路徑,編譯目標(biāo)代碼時(shí),可以對gcc加入鏈接參數(shù)“-Wl,-rpath”指定動態(tài)庫搜索路徑。
可以看到,LD_PRELOAD 是Linux 系統(tǒng)中啟動新進(jìn)程首先要加載 so 的搜索路徑,可以影響程序的運(yùn)行時(shí)的鏈接(Run? time linker),它允許你定義在程序運(yùn)行前“優(yōu)先加載”的動態(tài)鏈接庫。只要在通過 LD_PRELOAD 加載的.so 中編寫需要 hook 的同名函數(shù),根據(jù)Linux對外部動態(tài)共享庫的符號引入全局符號表的處理,后引入的符號會被省略,即系統(tǒng)原始的.so(/lib64/ libc.so.6)中的符號會被省略。
4.4繞過基于Linux消息隊(duì)列通信的Hook模塊
消息隊(duì)列提供了一種在兩個不相關(guān)的進(jìn)程之間傳遞數(shù)據(jù)的相當(dāng)簡單且有效的方法,但是對于消息隊(duì)列的使用,很容易產(chǎn)生幾點(diǎn)安全風(fēng)險(xiǎn):
(1)在創(chuàng)建消息隊(duì)列的時(shí)候?qū)essage queue 的權(quán)限控制沒有嚴(yán)格控制,讓任意非 root 用戶也可以從消息隊(duì)列中讀取消息。
(2)在用戶態(tài)標(biāo)識消息隊(duì)列的MSGID很容易通過“ipcs”指令得到,從而攻擊者可以獲取到和Hook模塊相同的消息隊(duì)列,從中讀取消息。
(3)Linux下的消息隊(duì)列是內(nèi)核態(tài)維護(hù)的一個消息隊(duì)列,每個消息只能被“取出”一次。
(4)當(dāng)系統(tǒng)中存在多個進(jìn)程同時(shí)在從同一個消息隊(duì)列中“消費(fèi)”消息的時(shí)候,對消息隊(duì)列中消息的獲取的順序是一個“競態(tài)條件”,誰先獲取到消息取決進(jìn)程的內(nèi)核調(diào)度優(yōu)先級以及接收進(jìn)程自身的接收邏輯,為了提高“競態(tài)條件”的“獲勝率”,可以使用nice(-20)提高進(jìn)程的靜態(tài)優(yōu)先級,從而間接影響到內(nèi)核調(diào)度優(yōu)先級。
綜合以上四點(diǎn)就可以得出一種攻擊“監(jiān)控軟件”本身的技術(shù)方式,如果監(jiān)控軟件使用消息隊(duì)列進(jìn)行日志的通信,則攻擊者可以通過這種方式強(qiáng)制取出隊(duì)列中的消息,從而使監(jiān)控軟件的監(jiān)控失效。
4.5基于ptrace()調(diào)試技術(shù)進(jìn)行API Hook
Linux 系統(tǒng)基于調(diào)試器(Debuger)思想在用戶層提供了一種調(diào)試機(jī)制ptrace。ptrace是一種父進(jìn)程可以控制子進(jìn)程運(yùn)行,可以檢查和改變它的核心image,它主要用于實(shí)現(xiàn)斷點(diǎn)調(diào)試。一個被跟蹤的進(jìn)程運(yùn)行中,直到發(fā)生一個信號。則進(jìn)程被中止,并且通知其父進(jìn)程。在進(jìn)程中止的狀態(tài)下,進(jìn)程的內(nèi)存空間可以被讀寫。父進(jìn)程還可以使子進(jìn)程繼續(xù)執(zhí)行,并選擇是否忽略引起中止的信號。
利用Linux系統(tǒng)提供的ptrace()技術(shù),可以主動注入方式,注入程序中從而達(dá)到Hook程序的API效果??傮w思路如下
(1)使用Linux Module、或者LSM掛載點(diǎn)對進(jìn)程的啟動動作進(jìn)行實(shí)時(shí)的監(jiān)控,并通過Ring0-Ring3通信通知到Ring3程序有新進(jìn)程啟動的動作。
(2)用ptrace函數(shù)attach 上目標(biāo)進(jìn)程。
(3)讓目標(biāo)進(jìn)程的執(zhí)行流程跳轉(zhuǎn)到mmap函數(shù)來分配一小段內(nèi)存空間。
(4)把一段機(jī)器碼拷貝到目標(biāo)進(jìn)程中剛分配的內(nèi)存中去。
(5)最后讓目標(biāo)進(jìn)程的執(zhí)行流程跳轉(zhuǎn)到注入的代碼執(zhí)行。
4.6容器內(nèi)進(jìn)程阻斷方案可行性
從主機(jī)側(cè)看容器本身只是一個特殊的進(jìn)程,而在容器內(nèi)的進(jìn)程也只是以容器進(jìn)程為父進(jìn)程生成的子系進(jìn)程。而本質(zhì)的進(jìn)程生成的方式和方式,在上面4.1小節(jié)已經(jīng)分析過,只有三種方式;并且最終換可執(zhí)行加載成可執(zhí)行程序,也只有唯一一種途徑;而該方法也是同樣用于容器內(nèi)部的進(jìn)程生成,那么在容器內(nèi)部只要對唯一的途徑做攔截,再根據(jù)特征值做檢測就可以。
只要有一種技術(shù)方案可以做到在容器內(nèi)部對唯一途徑的攔截,方案就可以得到實(shí)施,也就是對execve()函數(shù)做控制監(jiān)控。
而在4.3小節(jié)里面提到的四種動態(tài)連接 so 函數(shù)劫持Hook 方法,其實(shí)除4.3.4小節(jié)的方法跟運(yùn)行程序本身有關(guān),其它方法都和運(yùn)行的環(huán)境變量有關(guān)。而容器運(yùn)行因?yàn)槊臻g的隔離性,在真實(shí)的容器內(nèi)部是完全獨(dú)立于主機(jī),那么如果通過修改環(huán)境變量的方式來做execve()函數(shù)的劫持監(jiān)控是可以的,并且不會干擾到主機(jī)的環(huán)境變量。
4.4小節(jié)中的對消息隊(duì)列通信做Hook,在容器內(nèi)也是可以。同樣也是因?yàn)槿萜鞯拿臻g的隔離性,會為容器單獨(dú)隔離出自己的消息隊(duì)列用來通信,所以在容器內(nèi)部對消息隊(duì)列做通信 Hook也是可行的。
而4.5是使用主機(jī)上的ptrace()調(diào)用技術(shù)做Hook,需要在主機(jī)側(cè)對容器內(nèi)部的進(jìn)程做實(shí)時(shí)的監(jiān)控,但是也只能監(jiān)控到單個的進(jìn)程生成,進(jìn)程的子系進(jìn)程無法再進(jìn)行監(jiān)控。
5容器內(nèi)進(jìn)程阻斷
根據(jù)第4節(jié)的分析,在容器內(nèi)可以應(yīng)用多個Hook方案。而在4.1小節(jié)內(nèi)分析的進(jìn)程生成流程,真正能用在容器內(nèi)Hook到execve()系統(tǒng)調(diào)用API 函數(shù)的只有:LD_PRELOAD 和ptrace()系統(tǒng)調(diào)用功能。
而ptrace()功能的應(yīng)用是有幾個前提條件:
(1)有一個能承載ptrace()功能的運(yùn)行程序。
(2)知道當(dāng)前平臺系統(tǒng)可執(zhí)行文件加載函數(shù)execve()系統(tǒng)調(diào)用對應(yīng)的映射編號。不同的Linux 內(nèi)核版本對應(yīng)的映射可能會不一樣,不同的硬件架構(gòu)平臺不一樣,對應(yīng)的映射可能會不一樣。
(3)需要承載ptrace()功能的運(yùn)行程序,要知道被監(jiān)控程序的運(yùn)行信息,一般都以pid為監(jiān)控條件。
但在容器內(nèi),因?yàn)镻ID Namepace的進(jìn)程隔離性,在容器內(nèi)部獲取到的pid并不是真實(shí)的進(jìn)程pid。使用ptrace功能就不能真實(shí)地捕獲到容器內(nèi)部的進(jìn)程運(yùn)行情況,從而無法監(jiān)控到內(nèi)部的系統(tǒng)調(diào)用情況,更無法獲取到execve()系統(tǒng)調(diào)用是否在容器內(nèi)部被使用。
根據(jù)Linux對外部動態(tài)共享庫的符號引入全局符號表的處理,后引入的符號會被省略,即系統(tǒng)原始的.so(/lib64/libc.so.6)中的符號會被省略。而 LD_PRELOAD 是環(huán)境變量,用于動態(tài)庫的加載,動態(tài)庫加載的優(yōu)先級最高,一般情況下,其加載順序?yàn)?LD_PRELOAD > LD_LIBRARY_PATH >/etc/ld.so.cache>/lib>/ usr/lib 。如圖5所示。
所以使用LD_PRELOAD 指定自己的so 來“覆蓋”系統(tǒng)調(diào)用接口,從而可以達(dá)到檢查系統(tǒng)調(diào)用接口,和參數(shù)的目的。當(dāng)接口和參數(shù)特征是需要阻斷的直接阻斷返回。
6結(jié)語
云原生是為了能構(gòu)建一種符合云計(jì)算特性的標(biāo)準(zhǔn)來指導(dǎo)云計(jì)算應(yīng)用的編寫。而容器作為當(dāng)前云原生架構(gòu)下基礎(chǔ)組件之一,容器自身的安全直接影響整個云原生架構(gòu)的安全性。
在享受著容器技術(shù)便利性的同時(shí),往往會忽略對容器環(huán)境的安全加固。在彈性的容器環(huán)境中配置安全監(jiān)控和防護(hù)軟件顯然是個費(fèi)時(shí)費(fèi)力且消耗資源的事情。雖然容器自身在設(shè)計(jì)之初就帶有一定的安全考慮因素,再加上容器廠商的二次封閉設(shè)計(jì)對安全性進(jìn)行了進(jìn)一步的加強(qiáng),但同時(shí)也造成了一定量的攻擊面的增強(qiáng)。
隨著容器虛擬技術(shù)的不斷發(fā)展,容器已經(jīng)作為微服務(wù)、API 服務(wù)、業(yè)務(wù)服務(wù)等多種服務(wù)的載體,并成為保護(hù)服務(wù)的最后一道安全屏障。不管是對容器自身運(yùn)行的保障,還是對容器內(nèi)的業(yè)務(wù)的管理,容器被攻擊的風(fēng)險(xiǎn)都是不能忽略的。
本次研究利用容器的重要特性“容器的行為都是事先預(yù)定且固化的”,那么任何超出預(yù)定范圍內(nèi)的行為都代表著異常和攻擊。充分利用這個特性作為容器惡意攻擊的特點(diǎn)。而所有的攻擊行為都需要應(yīng)用程序做行為承接點(diǎn)才能實(shí)施;而容器本身只是Linux 系統(tǒng)下的一個特殊進(jìn)程,只要是進(jìn)程就一定要遵守Linux進(jìn)程的生成流程和機(jī)制。Linux 的系統(tǒng)調(diào)用接口作為內(nèi)核層與應(yīng)用層之間的“橋梁”,而對應(yīng)的接口庫的加載優(yōu)先級是存放在LD_PRELOAD 內(nèi)。通過修改優(yōu)先級來優(yōu)先加載進(jìn)程生成過濾策略,從而達(dá)到在應(yīng)用層阻斷惡意進(jìn)程的生成。參考文獻(xiàn):
[1]徐孝晉,伍澤軍,鄧文杰,等. 基于開源平臺的docker 安全性分析 [C]//2019電力行業(yè)信息化年會論文集. 無錫 , 2019:175-178.
[2]魯濤, 陳杰,史軍.Docker安全性研究[J].計(jì)算機(jī)技術(shù)與發(fā)展, 2018,28(6):115-120.
[3]胡俊,李漫.容器安全解決方案探討與研究[J].網(wǎng)絡(luò)空間安全, 2018,9(12):105-113.
[4]劉曉毅,王進(jìn),馮中華,等.容器云安全風(fēng)險(xiǎn)分析及防護(hù)體系設(shè)計(jì)[J].通信技術(shù),2020,53(12):3065-3071.
[5] DoSec安全團(tuán)隊(duì).Docker容器最佳安全實(shí)踐白皮書[R].中國: DoSec,2018.
[6]綠盟星云實(shí)驗(yàn)室.綠盟科技容器安全技術(shù)報(bào)告[R].中國:綠盟科技,2018.
[7]陳偉,涂俊亮.Docker容器安全的分析研究[J].通信技術(shù),2020, 53(12):3072-3077.
【通聯(lián)編輯:代影】