崔曉龍, 簡川杰, 劉 欣, 張 敏
(北京科技大學計算機與通信工程學院,北京 100083)
隨著計算機應用的發(fā)展和普及,人們越來越多地利用計算機來存儲和處理各種數(shù)據(jù),其中不乏大量的敏感數(shù)據(jù),惡意獲取這些數(shù)據(jù)將對安全造成極大的威脅?;ヂ?lián)網(wǎng)上惡意應用程序數(shù)量每年都在快速增長,由惡意軟件引起的本地感染已經達到了相當龐大的數(shù)量并呈現(xiàn)逐年上升的態(tài)勢,黑客通常將惡意應用程序偽裝為普通應用程序,將其發(fā)布到網(wǎng)絡上,欺騙計算機用戶偶然在本地下載和執(zhí)行這些應用程序,給黑客獲得未經授權訪問高權限系統(tǒng)資源的機會,并獲取或操縱存儲在用戶計算機上的敏感數(shù)據(jù)。
計算機系統(tǒng)面臨不同種類惡意程序或代碼的威脅,沙箱技術將為解決這類問題提供一種可行性方案。將網(wǎng)絡上安全性未知的程序運行在一個虛擬空間,該虛擬空間與真實系統(tǒng)環(huán)境類似,同時將未知程序和真實環(huán)境隔離,如果在程序運行過程中發(fā)現(xiàn)異常,則認為該未知程序是惡意程序,將該程序標志下來后,對運行環(huán)境進行回滾操作以恢復到原來的狀態(tài),這樣,無論病毒或者惡意程序如何運行,都無法對實際系統(tǒng)造成損害和威脅[1]。在沙箱運行過程中,用戶希望沙箱所占用的額外開銷盡可能地小,這樣用戶將感受不到沙箱的存在。
早期的一些沙箱機制并不存在于Linux 系統(tǒng)中,比如Janus和Mapbox都是出現(xiàn)在Solaris系統(tǒng)上,它們都為Linux 上的沙箱機制提供了一些可借鑒的思路[2]。
Janus是最早基于系統(tǒng)調用插入的沙箱機制之一,當調用要檢查的系統(tǒng)時,Janus將跟蹤進程置于休眠狀態(tài)并檢查其配置文件(也可以稱為安全策略),以決定是否允許當前系統(tǒng)調用。Janus 和本文實現(xiàn)的工具之間存在根本性差異,它在Solaris 操作系統(tǒng)中使用proc接口實現(xiàn),因為ptrace系統(tǒng)調用易受競爭條件的影響,并且在使用ptrace時中止系統(tǒng)調用很麻煩;另外,對于所有進程只有一個安全配置文件,用戶僅能建立一個全局安全策略;Janus不會解析相關路徑并相應地檢查系統(tǒng)調用,而是中止所有試圖使用相對路徑訪問資源的系統(tǒng)調用[3]。
Bluebox使用系統(tǒng)調用插入來捕獲系統(tǒng)調用,通過使用ptrace接口強制執(zhí)行以前指定的安全規(guī)則。它不允許用戶通過圖形界面交互生成安全策略,使用預先設置的靜態(tài)安全策略,這樣用戶就不能恢復由不良靜態(tài)策略所造成的結果[4]。
Mapbox是一個基于系統(tǒng)調用插入的工具,它在指定和執(zhí)行安全規(guī)則方面的工作方式截然不同。它是為Solaris操作系統(tǒng)實現(xiàn)的,它利用Solaris操作系統(tǒng)的系統(tǒng)調用攔截接口(proc)來跟蹤和操作系統(tǒng)調用[5]。Mapbox不是為不同的流程提供策略文件,而是對許多應用程序的行為進行分類,并將類似的應用程序行為分組在一起,以便根據(jù)它們的預期功能對每類應用程序實施安全規(guī)則。當計劃使用Mapbox 運行程序時,用戶配置策略文件并為目標程序分配一個或多個行為類,這些行為類指定目標程序可以訪問哪些系統(tǒng)資源[6]。例如,目標應用程序在Mapbox 中標記了reader,則意味著它只能讀取指定的某些文件,并不能執(zhí)行任何寫入操作或網(wǎng)絡操作。
SELinux是Linux中強制訪問控制安全模塊,它與Linux 內核集成,如Ubuntu 或Red Hat Enterprise。SELinux主要作用就是最大限度地減小系統(tǒng)中服務進程可訪問的資源(最小權限原則),如果用戶不希望在任何時候運行SELinux,那么每次想要運行沙箱應用程序時,在系統(tǒng)啟用和禁用SELinux 都會很麻煩。此外,對于臨時系統(tǒng)用戶配置ACL策略通常很困難。它不允許以交互方式生成安全策略,不能為用戶提供跟蹤應用程序活動或詳細日志記錄以進行執(zhí)行后的分析[7]。
Seccomp機制用于限制應用程序可使用系統(tǒng)調用,增加系統(tǒng)的安全性。啟用了Seccomp模式,則目標進程將在其功能非常有限的安全狀態(tài)下運行。Seccomp是一種可擴展的工具,可以白名單形式過濾系統(tǒng)調用,性能上也較好[8]。
用戶直接在操作系統(tǒng)運行未知程序是一個相當危險的操作,存在系統(tǒng)資源惡意被消耗的風險,考慮惡意程序在運行過程中的特點,沙箱主要功能設計如圖1所示。
圖1 沙箱主要功能設計
作為一款安全工具,沙箱應該具有以下特性:異常行為和(或)系統(tǒng)入侵檢測、富有表現(xiàn)力的安全策略、交互式安全策略生成、易用性、用于執(zhí)行后分析的日志記錄功能。
沙箱要實現(xiàn)的功能:
(1)限制未知程序的運行時間。
(2)限制未知程序的運行內存。
(3)及時了解程序的運行狀態(tài)。
(4)阻止未知程序運行時出現(xiàn)危險操作。
程序運行時間分為用戶可感知的程序運行時間和程序所實際占用的CPU 時間。之所以存在兩種不同的時間是因為用戶使用的操作系統(tǒng)大多數(shù)是分時多任務操作系統(tǒng),盡管目前大多數(shù)系統(tǒng)都是多核心CPU,但目前只考慮單核心CPU這種簡單的情況,大多情況下這種操作系統(tǒng)內的進程并不是一下就運行完成的,可能存在被進程調度的情況,因為任意時刻只可能存在一個正在運行的進程,其他進程就需要等待,所以一個進程的實際運行時間可能會大于該進程占用CPU運行的時間。在限制程序的運行時間時需要清楚限制的是程序運行的實際時間還是程序運行所占用的CPU時間。
給沙箱運行的程序設置一個較寬松的運行時間,以確保程序可正常運行又不讓惡意程序有占用較多的系統(tǒng)資源的機會。
進程實際運行所占用的物理內存包含進程使用系統(tǒng)提供的動態(tài)鏈接庫部分的內存,把所有的進程實際占用的物理內存加起來可能會超過機器的實際物理內存。在對內存進行限制的時候,可根據(jù)自身系統(tǒng)情況考慮一個限制沙箱內程序使用的內存值,確保程序能夠正常運行又不至于消耗過多的系統(tǒng)資源。
沙箱需要能監(jiān)控其中運行的未知程序的行為,對未知程序進程狀態(tài)進行跟蹤,需要了解進程到底是運行結束成功返回還是由于資源限制而導致進程提前結束,或者是進程要調用某個沙箱限制了的系統(tǒng)調用而被提前結束,這些行為都應該由沙箱監(jiān)控,這就要對進程和資源進行監(jiān)控,并且記錄進程結束時候的返回值。
沙箱中進程的資源限制可以通過對進程的CPU占用時間和進程內存占用的限制來實現(xiàn),而安全性限制需通過限制系統(tǒng)調用來進行。一些危險、常見可執(zhí)行系統(tǒng)命令函數(shù)如remove、system 等以及網(wǎng)絡通信操作相關函數(shù)都需進行限制,否則有可能導致系統(tǒng)的關鍵信息泄露,這些都可以通過使用Seccomp 限制相關的系統(tǒng)調用來實現(xiàn)。
沙箱接受通過命令行傳入未知來源的程序路徑作為參數(shù),并在加載指定的安全策略之后,開始嘗試運行該未知來源的程序。沙箱主要工作流程如圖2 所示。
圖2 沙箱工作流程圖
沙箱安全機制是沙箱最重要的功能,通過過濾系統(tǒng)調用來實現(xiàn)。系統(tǒng)調用是操作系統(tǒng)實現(xiàn)并提供給用戶來讓用戶能夠對底層硬件實現(xiàn)控制的一種編程接口[9]。當一個進程要調用系統(tǒng)的時候,操作系統(tǒng)會把相關參數(shù)放到CPU的寄存器中,比如系統(tǒng)調用號存在EAX寄存器中,EBX、ECX 和EDX 再分別存放一些其他的參數(shù),調用軟中斷(int 0x80),讓CPU切換到內核態(tài)并開始執(zhí)行對應的內核函數(shù)。
3.2.1 限制系統(tǒng)調用
Seccomp調用之后會作用于整個父進程和fork出來的子進程,只有在加載Seccomp的策略之后,沙箱才開始fork父進程執(zhí)行未知程序。實現(xiàn)本沙箱時采用的是在加載Seccomp策略之后執(zhí)行execve函數(shù)去執(zhí)行未知程序,這個順序也是Seccomp的安全策略所要求的。因為后面執(zhí)行程序需要使用到execve 這個系統(tǒng)調用,所以Seccomp也不能完全限制了execve 系統(tǒng)調用,本沙箱選擇對execve 系統(tǒng)調用進行參數(shù)的過濾,以此來限制execve[10]。
3.2.2 加載Seccomp
Seccomp是一種侵入式的加載策略,如果程序已經執(zhí)行結束之后再加載Seccomp 策略毫無意義,所以應該在execve之前加載Seccomp。由于Seccomp 采用白名單加載策略,如果execve 在Seccomp 之后的話就需要把Seccomp也加入系統(tǒng)調用的白名單里面,但是execve是一個很危險的系統(tǒng)調用,如果不加以限制那這很明顯是一個“繞過”[11]。Seccomp 可對系統(tǒng)調用的參數(shù)進行限制,通過對execve 系統(tǒng)調用的傳入?yún)?shù)進行一定的限制,只能執(zhí)行沙箱所限制的文件路徑的文件。如圖3 所示,在加載Seccomp 策略的函數(shù)Seccomp_rule_add,第2 個參數(shù)不滿足策略的進程直接被kill掉;第3 個參數(shù)過濾的系統(tǒng)調用是execve;第4個參數(shù)需要過濾幾個參數(shù),“1”表示只過濾1 個參數(shù);后面的參數(shù)則是需要過濾的參數(shù),如果第4 個參數(shù)為“1”,則表示有1 個需要過濾的參數(shù),圖3 中是execve系統(tǒng)調用的第1 個參數(shù)被過濾。
圖3 限制execve系統(tǒng)調用參數(shù)流程圖
3.2.3 白名單機制
完成了加載Seccomp 時機的設計,要設計加載Seccomp時需要考慮哪些系統(tǒng)調用。對一些常見程序用strace 命令進行分析,得出如表1 所示的系統(tǒng)調用的白名單[12]。
表1 系統(tǒng)調用白名單
除了execve系統(tǒng)調用需要過濾參數(shù),write系統(tǒng)調用也要進行參數(shù)的過濾。write系統(tǒng)調用中有一個參數(shù)是用來表示寫入的文件描述符,該參數(shù)為“0”“1”和“2”的時候,分別表示stdin、stdout 和stderr,大于3 表示某個已打開文件的文件描述符的值。之所以要限制write系統(tǒng)調用,是因為沙箱需要防止沙箱中的進程任意寫文件,該操作是危險的。如圖4 所示,和前面類似,這里限制了write系統(tǒng)調用的第1 個參數(shù)要小于等于2,即限制文件描述只能使用標準的輸入(stdin)和輸出(stdout)。
圖4 限制write系統(tǒng)調用參數(shù)流程圖
3.2.4 權限控制機制
Linux訪問控制權限分為3 組,分別為user、group和others。user是對文件所有者設定的權限;group 是對文件所屬組下面用戶設定的權限;others 是對既不是文件所有者也不是文件所屬組下面的用戶設定的權限。其中root用戶的權限是最高的,其他用戶的權限是可以劃分的。Linux下一切皆文件,所以進程同樣也是有權限劃分的,每個用戶都有一個UID 的值,文件組也有一個GID的值,一個運行中的進程在運行時會有UID和GID的值來標識,進程中也可以調用setuid和setgid函數(shù)分別來改變當前進程的UID 和GID 值,不過調用這兩個函數(shù)首先需要有root用戶的權限。如圖5 所示,沙箱采用了NOBODY 用戶的GID 和UID,這是權限非常低的用戶,采用這個用戶來運行沙箱進程,可以進一步避免在沙箱中運行未知程序帶來的危害。
圖5 設置進程UID和GID流程圖
在Ubuntu18.04 對沙箱進行安全和性能兩方面的測試:安全測試主要包含2 個程序,一個正常的安全程序和一個存在惡意系統(tǒng)調用的程序,分別運行在操作系統(tǒng)和沙箱中進行對比;性能測試選擇一個特殊的測試程序,即一個存在大量系統(tǒng)調用的程序,分別運行在本沙箱、其他沙箱和直接運行在操作系統(tǒng)中進行時間的對比。
對安全性的測試,用一個正常的測試程序和一個包含惡意代碼的程序分別在操作系統(tǒng)上直接運行和通過沙箱運行來進行對比。
將正常測試程序直接運行在操作系統(tǒng)和沙箱,正常程序在操作系統(tǒng)環(huán)境和沙箱環(huán)境中均能正常的運行。正常程序直接在操作系統(tǒng)中運行效果如圖6所示。
圖6 正常測試程序直接運行
在沙箱環(huán)境中運行效果如圖7 所示,說明沙箱對操作系統(tǒng)運行正常程序進行了較好的模擬。
圖7 正常測試程序在沙箱中運行
將包含惡意代碼的程序在操作系統(tǒng)中運行,可以發(fā)現(xiàn)該惡意程序代碼運行成功,并獲取機器的shell,運行效果如圖8 所示。
圖8 包含惡意代碼的程序直接運行
將包含惡意代碼的程序運行在沙箱之中,可見,惡意程序被檢測出來,隨后進程停止運行,運行效果如圖9 所示,沙箱環(huán)境達到了發(fā)現(xiàn)惡意程序并中止進程的效果。
圖9 包含惡意代碼的程序在沙箱中運行
通過對比運行可以發(fā)現(xiàn),沙箱可以阻止惡意程序的執(zhí)行,并不影響正常程序的運行,保護系統(tǒng)正常運行不受影響。
對性能測試,選擇使用一個存在大量系統(tǒng)調用的程序分別運行在本沙箱、一個使用ptrace 實現(xiàn)的沙箱和直接運行在操作系統(tǒng)上,對比運行時間。時間獲取采用wait3()函數(shù)獲取子進程運行時間,分別對3 個測試進行多次子進程運行來測試大量系統(tǒng)調用的程序的運行時間。進程運行時間見表2,可見,使用ptrace 實現(xiàn)的沙箱在存在大量系統(tǒng)調用的時候進程運行時間會較長,而本沙箱在系統(tǒng)調用量較大的時候程序的執(zhí)行效率比不使用沙箱時略低。
表2 各種沙箱實現(xiàn)的性能對比
基于多種安全機制實現(xiàn)一個安全、輕量級的應用程序沙箱,以幫助Linux 系統(tǒng)用戶能夠安全使用應用程序。通過仔細研究Linux 內核提供的不同安全機制,選擇使用Linux 的Seccomp 接口,使一個進程能夠操作并完全控制另一個進程,結合多種安全機制實現(xiàn)一個沙箱系統(tǒng),該系統(tǒng)根據(jù)定義的安全策略去檢測未知程序運行時是否存在危險行為,檢測到危險行為的進程將被終止,正常的進程就仿佛運行在操作系統(tǒng),可以正常運行結束且效率不會受到較大影響。