SELinux資安強固技術在Embedded System上的應用

工業技術研究院 資訊與通訊研究所 王禹軒、張柏駿、趙翊廷

 

隨著Linux成為嵌入式系統的霸主,如何使存取控制防護技術在資安控管強度與便利使用的權衡下達成共識的資安防禦解決方案,來解決與物聯網/嵌入式系統設備相關的資安議題,是個值得探討的題目。

應用程式白名單(Application Whitelisting)只允許已知的合法應用程式在系統上執行,適用在固定功能的電腦設備,例如車載系統、自動化工廠機台等。這些設備過去普遍用黑名單技術進行資安保護,不過由於惡意軟體(Malware)數目快速增加,已使得黑名單防不勝防,於是反過來利用白名單阻止未知程式執行。相較之下,白名單限制範圍更大,它確保系統中受信任的軟體才能執行,即使惡意程式在周圍環伺也無法作怪。

白名單與SELinux技術簡介

惡意程式慣用的入侵手法是利用軟體弱點進行攻擊,如在電子郵件中提供連結,點擊執行後塞進一小段程式碼(Shell Code),再透過這個小程式植入惡意軟體伺機執行,一旦開了此門就有如邀請壞人入住家裡,財產隨時受威脅。惡意程式可在下載時啟動偵測或在源頭處把關,即在入口處攔下,或者執行軟體弱點掃描也可避免漏洞發生。但就算有千百種防禦手法,仍然難免疏漏,更不要說惡意軟體也時時更新,天羅地網仍無法全面抵擋入侵。應用程式白名單的存在就是最終防線,無論惡意程式經由什麼媒介、什麼手段侵入,在它被啟動時即遭系統阻擋,使惡意攻擊無法得逞。惡意軟體有如偷渡客,白名單就是檢查哨,安全清單則是過關的基準,讓合法軟體照常執行又提防到惡意攻擊,是白名單機制的主要目標。

SELinux在Linux系統上早已是廣為人知的存取控制機制,但也知名於令人卻步的學習門檻,因此系統管理員傾向使用社群所維護的開源Policy,也就是所謂Reference Policy,此Policy提供普遍系統詳細的存取控制規則,系統管理員以此為基礎並於其中調整至符合自身需求,但調整方法可能大都使用audit2allow來消除受阻擋訊息,或是使用chcon來調整subject/object標籤名稱。此種trial-and-error的方式可能會導致Policy開啟了不必要的權限,因為缺乏人員檢視,而且也受限於檢視人員對於SELinux以及系統的全面了解。由於Policy體系架構的設計非常可靠與完整,透過Reference Policy搭配SELinux完善的攔檢機制,並在Android這全世界最多的嵌入式裝置所體現出的資安防禦成效,團隊因應業界廠商對於GPL開源規範的考量,從2019年開始全面改用SELinux搭配自製Policy來實現應用程式白名單的防禦概念,並於Ubuntu 18.04LTS、樹梅派四、Nvidia Jetson Xavier等證明此設計方式所產出之應用程式白名單之有效性與維護之便利性。再者透過相關場域維運過程證明此方案之穩定與可靠。面對透過此解決方案進行的資安強固成果,對不懷好意的入侵者而言,有如戴上緊箍咒一般,處處難以施展、處處碰壁的情況下,難以發揮其所常,達到最佳防護成效。

採用SELinux與自製Policy所實現之應用程式白名單產品,不僅克服開放原始碼環境下的種種限制,從交付到規模化部署,再到後續更新與維護,以及整合資安戰情室的流程,皆大量採用開放原始碼相關專案之整合,一方面大大降低開發團隊之人力成本,一方面也為各式客戶的客製化需求降低其進入門檻及整合負擔。在商業上面臨工廠不停機、少維護以及長時間運轉的 高要求下,目前台灣僅有此方案能夠以最快速的方式進行整合以及導入,並同時兼顧產品的穩定與可靠,極大化降低客戶在導入時所面臨的種種技術困難。

後續為了讓打算採用SELinux為基礎的解決方案操作人員以及相關有興趣之讀者能夠深入了解,接下來會開始進行一系列解說,說明SELinux +自製Policy的奧妙之處,最後再以嵌入式裝置上之Ubuntu系統進行實際案例介紹。

SELinux基礎解說

起源

早在接觸到SELinux之前,就有聽過這是一門入門很難的存取控制(Access Control)機制,差不多在去年的這個時候跟公司夥伴們讀了一篇50幾頁的論文加上官方手冊SELinux Notebook,才終於抓到一點感覺,話不多說,就讓我先來說說什麼是存取控制,以及在Linux上的情況。

存取控制

存取控制的概念存在於日常生活中的每一刻,例如法律規範人民能做什麼、進公司需要有ID卡或是進家門使用卡扣感應等等,這些存取控制簡單由存取主體(Subject)、資源(Object)、存取行為(Access)組成。在資訊安全(Information Security)的領域中,存取控制是進行風險管理(Risk Management)的其中一個部分,目的在於確保資訊存取的機密性(Confidentiality)、完整性(Integrity)、可用性(Availability)不受非法侵害,這3種性質簡稱為CIA triad。

 圖1 CIA triad in Information System (From https://en.wikipedia.org/wiki/Information_security)
圖1 CIA triad in Information System (From https://en.wikipedia.org/wiki/Information_security)

要完成上述的事情勢必得存在一套機制,當存取資訊時會基於管理者所制定的政策(Policy)規範,來看存取主體(Subject)是否有權限存取受保護的資訊,此處的存取主體也包括電腦軟體。存取控制最困難的地方莫過於如何制定符合需求的政策,不會將權限設定的過於嚴格或是寬鬆,當然唯有充分了解使用情景和需求才有辦法做到,比如說,我們可以透過評估資訊或是資產的敏感度和價值,並針對評估的結果來設定存取控制的強度。

存取控制模型

介紹存取控制機制之前,我們先來看看DAC(Discretionary Access Control)自主式存取控制和MAC(Mandatory Access Control)委任式存取控制,這2個是常常被拿出來說明的存取控制模型,不同的模型代表不同存取控制方法,根據論文的定義DAC和MAC分別為:
DAC:(authorization-based) policies control access based on the identity of the requestor and on access rules stating what requestors are (or are not) allowed to do.
MAC:policies control access based on mandated regulations determined by a central authority.

簡單來說,DAC是根據存取主體的「身分」來判斷權限,譬如進公司時會用ID卡來識別身分,而MAC是根據中央政策規範每個存取主體的「行為」,譬如中央政策規範明訂某A只能負責影印文件,因此某A不論用何種身分進入公司都只能影印文件,此處存取主體的「行為」跟「身分」是分離的。分離身分與行為的好處在於壞蛋無法透過冒充身分來做壞事,因為不管冒充何種身分也會被中央政策規範的行為限制住。

存取控制機制

在Linux環境中,DAC的實作機制由uid、euid、gid、egid、suid、sguid、fsuid等組成,這些東西被稱為程序(Process)的身分驗證資訊(credentials),也就代表此程序的身分,此身分是當使用者登入系統後所給予,前面有提到DAC這種沒有把身分跟存取主體(也就是程序)分開的模式有可能會遭受惡意程式的荼毒,例如管理員執行了嵌入惡意程式的計算機程式,此惡意程序即相當於擁有了管理員的身分。

如果以MAC的角度來看,首先我們明訂政策說明存取主體與資源之間的關係,限定計算機程序只能做計算,其他行為例如存取管理員加目錄機密資料等等都不能做,則當管理員執行了嵌入惡意程式的計算機程式時,惡意程序也無法做壞事。

坊間存在着許多實作MAC模型的機制,建立於Linux安全模組(Linux Security Modules)之上,例如SELinux(Security-Enhanced Linux)、Smack(Simplified Mandatory Access Control Kernel)、Apparmor等等。
Smack: 於2008年首次發布,在Linux 2.6.25被納入其中,標榜易於使用,目前主要活躍於Automotive Grade Linux(AGL)社群,詳細Smack介紹以及遇到的問題可以看2019 Opensource Summit上的投影片[9],簡單來說問題為Root權限依舊無敵,且在Kernel中有預設規則,當預設規則通過時就不會去檢查自己寫的規則。
Apparmor: 於1998年首次發布,在Linux 2.6.36被納入其中,目前活躍於Ubuntu、OpenSUSE社群,其特色為要幫應用程式寫一套規範,內容描述應用程式可存取資源,檢測皆基於路徑,旨在作為原本Linux DAC的延伸。
SELinux: 於2000年首次發布,在Linux 2.6.0被納入其中,主要開發者為NSA(美國國家安全局)和Redhat,目前活躍於Redhat、Fedora、CentOS、Android社群,實作許多存取控制模型(UBAC、RBAC、Type Enforcement、MLS、MCS)。

表1 3種機制的差別

三者差異可由我們自製的表格看出,SELinux和Smack需要檔案系統支援擴展文件屬性(Extended Attribute),而Apparmor則是以路徑為主,另外可以看到SELinux的檢查點最多,代表檢查的細緻程度較高,SELinux和Apparmor的比較可以參考wiki,最後基於SELinux活躍的社群、保護程度(檢查點多且可受檢查的權限比較多)和對於存取控制模型的支援,也因此我們在其中選擇了SELinux。

啟動SELinux
Security-Enhanced Linux(SELinux)早在2003年時被納入Linux Kernel 2.6,也就是說,此版本後你可以從Kernel設定檔中開啟SELinux的安全模組功能,SELinux的安全模組建立在Linux安全模組框架(Linux Security Modules)上,此框架也支援其他安全模組,例如AppArmor、Smack、TOMOYO Linux等等。
從Kernel設定檔中開啟SELinux的安全模組功能就代表開啟了SELinux防護嗎?很可惜並不是! 使用者空間(Userspace)中存在著一些幫手,SELinux-aware Applications,在系統建置時期,也就是開發階段,SELinux-aware程式依照我們預先設定的SELinux設定檔(SELinux Configuration Files)來將系統資源標上標籤(Label),系統運行時,init或systemd之類的init system,會將SELinux政策二進位檔(SELinux Policy Binary)透過讀寫SELinux Filesystem(selinuxfs)釋出的界面載入Kernel之中,最後根據設定檔中要開啟的SELinux模式(SELinux Mode)來運行,至此,我們才能說SELinux防護已啟動。

補充說明,在SELinux世界中存取主體(Subject)和資源(Object)會被標上標籤(Label),而SELinux政策二進位檔中的內容就是在描述存取主體標籤和資源標籤之間的存取關係,我們這邊先統稱SELinux政策代表存取控制規則的集合。

圖2來自官方手冊,The SELinux Notebook 4th Edition,展示了整個SELinux的系統架構,我們接下來會就核心空間、使用者空間、SELinux政策與SELinux設定檔,分享開啟SELinux防護所需的要件,了解內部運作後,對於使用以及除錯上一定會有所幫助。

 圖2 SELinux 架構(From The SELinux Notebook 4th Edition)
圖2 SELinux 架構(From The SELinux Notebook 4th Edition)
核心空間(Kernel Space):
 圖3 SELinux核心空間(From The SELinux Notebook 4th Edition)
圖3 SELinux核心空間(From The SELinux Notebook 4th Edition)

前面有提到SELinux的安全模組建立在Linux安全模組框架(Linux Security Modules)上,何謂Linux安全模組框架呢?起初的設計理念即是為了支援多種安全模組,以達到小幅度改動核心且實行更進一步的存取控制功能,例如委任式存取控制(MAC)。 Linux安全模組框架在核心中提供許多的插入點(LSM Hooks),這些插入點應存在於核心中有安全疑慮之處,當程式流程執行到此插入點時,即會跳轉到載入的安全模組(e.g. SELinux)中進行檢查。

以使用者開啟檔案為例,當使用者開啟檔案時,會透過系統呼叫進入核心使用核心服務(Linux Kernel Services),如圖3,執行過程中遇到插入點就會先跳轉到對應的SELinux核心服務(SELinux Kernel Services)中進行檢查,檢查過程中會去查詢是否此存取行為(Action)符合預先載入的SELinux政策規範,檢查完後會回到跳轉來的地方繼續執行。這邊要重點提到,在SELinux核心服務中進行檢查時,會根據設定來選擇是否要將檢查結果紀錄成稽核訊息(Audit Message)並透過Audit Services記錄在Audit Log中,因此,並不是所有的檢查都會被記錄成訊息哦!

從圖3上方可以看到selinuxfs檔案系統,負責使用者空間中的程式與核心中SELinux模組的溝通,程式可以透過讀寫selinuxfs檔案系統釋出的介面,來與SELinux模組交換資訊,例如獲取當前SELinux狀態、載入政策等等。

使用者空間(User Space):
 圖4 SELinux使用者空間(From The SELinux Notebook 4th Edition)
圖4 SELinux使用者空間(From The SELinux Notebook 4th Edition)

如果SELinux只開啟了核心部分的功能,並無法發揮它的功力,必須配合使用者空間中所謂SELinux-aware Application一起運作。 什麼是SELinux-aware Application呢?簡單來說就是知道SELinux的存在並與之互動的程式,打個比方就是能感知到幽靈的人我們就稱他為「幽靈-aware」。 根據感知的程度我們提出了一個分類,如圖5。

 圖5 SELinux-aware程度 (From https://hankwangbighead.blogspot.com/2020/04/selinuxpart2-selinux.html)
圖5 SELinux-aware程度 (From https://hankwangbighead.blogspot.com/2020/04/selinuxpart2-selinux.html)

圖5中,最低的感知程度即為「不知道」SELinux的存在,例如rm。緊接著是「知道」SELinux,但不是必須的程度,例如使用ps或是ls我們可以知道程序或是系統資源被標上什麼標籤(Label),但沒有這些功能也不影響SELinux的運作。

有些程式會透過讀寫selinuxfs中的介面去跟核心中的SELinux模組交換資訊,舉例來說getenforce程式會讀取selinuxfs底下的enforce檔案,即可獲得當前SELinux是以什麼模式(e.g. permissive mode)運行,此種會存取selinuxfs介面但並不需要特殊存取權限(e.g. setenforce權限,所謂的特殊權限是我們在分類時,自己認為會影響系統運行的權限)的程式歸為一個程度。

最高程度的SELinux-aware Application運行會涉及到特殊權限,也就是會一定程度上影響系統的運行,例如我們可以透過setenforce工具(需要setenforce權限)動態改變SELinux目前的運行模式,此種SELinux-aware Application中經典的例子為開機流程中init system和使用者登入。

 圖6 Linux 開機流程 (From https://hankwangbighead.blogspot.com/2020/04/selinuxpart2-selinux.html)
圖6 Linux 開機流程 (From https://hankwangbighead.blogspot.com/2020/04/selinuxpart2-selinux.html)

開機過程中,當核心載入且初始化完成後,執行流程來到使用者空間中,此時init system開始運行,根據使用情境的不同,init system可能為SysV-style init、OpenRC、Systemd等等,不管是哪一種都必須讓SELinux政策在所有程式跑起來前載入核心中,因此如圖5,init system會將政策載入且重新執行自己來讓自己被納入SELinux的規範中(會有一對應的init政策)。 接著init system開啟服務且為使用者登入做準備,這邊以Getty和Login為例,系統要求使用者輸入使用者名稱和密碼,進行使用者認證後會去讀取SELinux設定檔,以查詢此Linux使用者所對應的SELinux使用者名稱,再經由此SELinux使用者名稱找出該使用者後續程序(e.g. bash)應該用什麼標籤(Label)來運行。

標上標籤(Label)
當使用者登入後會去存取系統資源,此時如何為系統資源標上標籤(Label)也是很重要的一件事情,在系統建置時期,透過使用setfiles等相關的工具,依據SELinux的設定檔(e.g. file_contexts)來進行標上標籤的動作。

由前面的敘述我們來複習一個重要的概念,管理員必須知道他想怎麼保護系統資源,因此管理員必須了解系統運作,且經過風險評估來知曉資源的重要程度,以在系統建置時期幫資源標上適合的標籤,也透過調整SELinux設定檔來讓使用者登入時運行在最適合的標籤,使程序主體(Subject)運行在最小權限(Least Privilege)中。

應用程式白名單特色

經過存取控制背景知識的介紹,我們可以知道要將系統存取控制的政策寫好是非常具有挑戰性的一件事情,但要如何將未知或不可掌控的資安因素壓到最低呢?

正確的流程應該是威脅分析、對策、政策規劃、撰寫資安政策、人/機器執行,但在實際執行流程上為資安問題?例如勒索病毒、找對策、如何導入、安裝/限制、人/機器執行,這樣的做法最大的問題,在於你的解決方案是否已能應對包含你所不知道的威脅,見招拆招的策略高度不敷使用,防範未然、超前部屬才是上策。

但如果照官方SELinux政策語法的複雜度則需要非常高的學習門檻,無法每個人都分析程式碼的資源存取行為並撰寫SELinux政策,因此我們希望可以做到容易跨作業系統版本、資安防禦強度夠高、簡單操作、執行系統更新等特點的存取控制方法。

為此我們需要降低複雜度,放寬管控粗細度,降階到允許/阻擋程式執行層級資安政策。
以下列出我們應用程式白名單之優勢:

•政策跨平台,不需因平台不同而有過多調整
•與官方SELinux政策相比,便利性高,只需針對情況區分特例
*會產生與執行檔案的程式
*執行腳本的程式
•好用,學習曲線低
*不修改任何SELinux程式碼
•支援全系統程式
*應用程式白名單內容:Application, Script, Kernel Module, Library
•支援白名單更新
*透過apt套件管理程式安裝新的應用程式時,apt會自動將新的應用程式加入白名單。

應用於嵌入式Ubuntu實例

本文的最後附上從頭開始在Ubuntu上開啟應用程式白名單的步驟,直接執行後並重新開機即可讓Ubuntu開啟SELinux且運行在permissive mode,如果想運行在enforcing mode則必須要自行設定政策的內容哦!

如果需要開啟應用程式白名單,則可以使用如下連結中的指令來將應用程式白名單部署於機器上:
https://launchpad.net/~itri-icl-fteam/+archive/ubuntu/selinuxapplicationwhitelist Installation:
•sudo add-apt-repository ppa:itri-icl-fteam/selinuxapplicationwhitelist
•sudo apt-get update
•sudo apt install selinuxpack-libsepol selinuxpack-libselinux selinuxpack-libsemanage selinuxpack-checkpolicy selinuxpack-dbus selinuxpack-gui selinuxpack-mcstrans selinuxpack-policycoreutils selinuxpack-python selinuxpack-sandbox selinuxpack-secilc selinuxpack-semodule-utils selinux-app-whitelist-policy selinux-configuration
•sudo install_selinux.sh

SELinux政策(SELinux Policy)與SELinux設定檔(SELinux Configuration Files)
不管是在系統建置時期抑或是SELinux運行時期,SELinux提供了許許多多的設定檔來供我們便利地調整其功能,分為通用設定檔(Global Configuration Files)和政策設定檔(Policy Configuration Files),以使存取控制的結果符合我們心中的樣貌,例如/etc/selinux/config這個通用設定檔中就描述了SELinux將以什麼模式運行以及想要使用的政策目錄名稱,而相關的政策設定檔都會放在/etc/selinux/政策目錄名稱之下。

基本上格式由「檔案路徑」、「檔案類型」、「標籤」所組成,檔案路徑可以包含正規表示式(Regular Expression)。setfiles運行時會將2個檔案合併後分為包含以及不包含正規表示式的路徑,一開始會從「不包含正規表示式的路徑」找起,找到後會直接使用並不會繼續往後找,因此通常在除錯時得小心是否因為此原因而無法標上預期的標籤。

除了這些與政策相關的基本設定檔外,最重要的就是SELinux政策二進位檔,管理者需構思與撰寫SELinux政策原始檔(SELinux Policy Source),並將其轉換為SELinux政策二進位檔,此政策二進位檔一般存放於/etc/selinux/政策目錄名稱/policy/中,可以透過selinuxfs釋出的介面載入核心之中,SELinux政策二進位檔由SELinux核心模組進行解析並不依賴於任何平台,但會依賴於核心的版本,根據核心版本不同能支援的政策語法也不同,我們可以透過sestatus工具,來看看核心最高支援的政策版本。

最後一行即為核心最高支援的政策版本,至於該如何撰寫以及如何產生自己的SELinux政策呢?在這邊我們使用官方提供的Reference Policy,此政策旨在提供一般來說系統上最通用的存取控制規範,每個distro會修改Reference Policy使其符合自身的需求。

以下附上白名單於Ubuntu上之實際攻擊防護情景。首先看一下開啟白名單的Ubuntu狀態:

 圖7 白名單狀態
圖7 白名單狀態

並且實際執行攻擊防護情景:
1.建立新腳本來模擬誤下載之惡意程式:

 圖8 新建腳本
圖8 新建腳本

2.新檔案並不存在於白名單中:

 圖9 新建腳本不在白名單中
圖9 新建腳本不在白名單中

3.執行此不存在於白名單中的腳本,會遭遇白名單阻擋:

 圖10 白名單阻擋執行
圖10 白名單阻擋執行

甚至是使用管理員權限執行

 圖11 白名單阻擋Root執行
圖11 白名單阻擋Root執行

為確保整體防護效果之可靠穩定,後續團隊更研發出完整之功能測試,確保所有可能的執行行為皆被徹底阻擋。以下為測試與驗證結果。

 圖12 測試沒通過的結果與發現的問題清單
圖12 測試沒通過的結果與發現的問題清單
 圖13 測試通過的結果
圖13 測試通過的結果

結語

我們花了幾個禮拜的時間在Ubuntu 18.04上建制WhiteList Policy,將世界一分為二,白名單內與外,好與壞,能做任何事與不能做任何事,Policy精簡到包含宣告只有10幾行規則,運行時被建立的新檔案預設被標籤為白名單外。一切的努力都是為了讓存取控制資安防護技術變得更加便利好用,被廣大群眾所接受,但使用者也必須注意,防護強度需要針對自身的需求來做調整,如果需要更加強力的防護則必須越趨近於使用Least Privilege強度的資安解決方案。

參考文獻

[1] http://www.reuters.com/article/us-uber-tech-volvo-otto-idUSKCN10T1TR
[2] https://www.nytimes.com/2017/05/14/technology/lyft-waymo-self-driving-cars.html
[3] https://electrek.co/2017/04/29/elon-musk-tesla-plan-level-5-full-autonomous-driving/ [4]https://blogs.nvidia.com/blog/2017/07/05/baidus-project-apollo-takes-flight-bringing-autonomous-cars-closer-to-reality/
[5] https://www.ihs.com/country-industry-forecasting.html?ID=10659115737
[6] http://fortune.com/2016/12/19/blackberry-autonomous-vehicle-research-center/
[7] http://blog.trendmicro.com/is-your-car-connected-or-protected/
[8] Samarati, P., & Vimercati, S.D. (2000). Access Control: Policies, Models, and Mechanisms. FOSAD.
[9] SMACK-based Application Whitelisting on AGL – Che-Hao Liu & Chuan-Yu Cho, Industrial Technology Research Institute, Taiwan, OpenSource Summit 2019

文章轉載自工業技術研究院電腦與通訊季刊

推薦課程: