iT邦幫忙

2023 iThome 鐵人賽

0

Yes

  • SELinux 也是實現了強制存取控制 MAC (mandatory access control) 的訪問控制安全策略機制。但相對於 AppArmor 來說學習門檻真的高蠻多的,這邊就只能就我目前初學的心得做說明,並且用 SELinux + Docker 的方式作為切入點。

  • 在 SELinux 的世界中沒有所謂的 root 使用者的概念,取而代之的只有所謂的"安全本文(security contexts)",而安全本文可以標記程序、檔案類型的資源。透過常用指令帶上 Z 這個參數就可以看到所屬的安全文本。

    #確認 SELinux 有啟動
    sestatus ; 
    
    # 直接進容器觀察看看
    docker run -it --rm aeifkz/my-ubuntu:v1.0 bash ;
    
    # 看看目前容器內執行程序所帶的 security contexts
    # system_u:system_r:spc_t:s0
    ps Z ;
    
    # 看看目前容器內檔案所帶的 security contexts
    # system_u:object_r:container_share_t:s0
    ls -Z ;
    
    exit ;
    
  • 那接下來要針對這個 security contexts 做說明。這部分可以參考 第三章、SELinux 初探,格式為[SELinux用戶別:角色:類型]。而現行主要的限制是針對 "類型" 這個欄位進行限制,SELinux 主要的限制方式就是針對這些欄位去定義可以進行的動作權限。但也因為如此複雜度會比 AppArmor 來的高一些。
    https://ithelp.ithome.com.tw/upload/images/20231010/20148308QVJ8FykYKt.jpg

  • 這樣看起來 SELinux 是不是蠻簡單的,只要搞清楚這些 security contexts (為了不要講這麼多字,我後面都會用 label(標籤) 稱呼它們) 的定義方式以及對應關係就好了。但事情會遠比我們想像的更複雜,這個等到最後面再來說明。但待會先從不受標籤限制的容器操作開始測試起,這邊先建立一個普通容器,然後掛載硬碟裝置並且對宿主機進行檔案寫入。

    # 建立一般容器,但是掛載根目錄
    docker run -it --rm -v /:/mnt aeifkz/my-ubuntu:v1.0 bash ; 
    
    # 觀察一下跟剛剛有甚麼差別,應該是沒有才對
    ps Z ;
    
    chroot /mnt ;
    echo "I am root" > /root/I_am_root ;
    
    # 離開 chroot 狀態
    exit ;    
    
  • 這邊我要開始思考一件事情,為什麼特權容器可以對宿主機的 /root 進行寫入? 這件事情在 DAC 的存取模式下在正常不過,因為身分是 root 而且 /root 是擁有者可讀、可寫、可執行。但現在我們要開始用 MAC 的想法進行分析,究竟當下的程序的標籤是甚麼、對象的標籤是甚麼以及究竟這兩個標籤能不能互相讀取。

    # 在宿主機確認 SELinux 相關工具都有裝好
    sudo yum install setools-console attr  -y ;
    sudo yum install setroubleshoot-server -y ;
    
    # 確認一下 /root 的資料夾標籤下檔案的標籤
    # system_u:object_r:admin_home_t:s0
    sudo ls -Z /root/ ;
    
    # 透過 sesearch 指令去搜尋允許的規則
    sesearch -s spc_t -t admin_home_t --allow -c file ;
    
  • 這個標籤的開放格式可以參考 SELinux/Tutorials/How SELinux controls file and directory accesses 裡面的內容,其中有提到如下。

    allow auditd_t auditd_log_t:file { write }; 
    
    Well, this is exactly what SELinux does:
        1. if the process runs within the auditd_t domain (and thus has a security context with auditd_t in its third position)
        2. and if the target has the type auditd_log_t set,
        3. and the target is a file
        4. then the permission write is granted   
    
  • 所以依照剛剛得到唯一正常的格式如下,感覺我們應該是找錯了對吧?

    allow files_unconfined_type file_type : file { ioctl read write create ...略 } ;
    
  • 這是我當遇到的瓶頸,也是我覺得 SELinux 門檻高的原因,找不到一條實際的規則去對應到存取的部分。撞牆撞了很久偶然看到這篇 SELinux type attributes provide this grouping functionality 瞬間豁然開朗。原來 SELinux 為了設定方便,它有支援群組的功能,也就是可以把一群標籤定義成一個群組A,把另一群標籤訂為群組B,然後就可以定義群組A 跟群組B 的存取關係。

    # -a 找尋屬性名稱,後面接要查詢的屬性
    # 所以發現剛剛那條規則的確有定義到我們的存取行為
    seinfo -afiles_unconfined_type -x | grep spc_t ;
    
    # 實測下來這個 file_type 的標籤涵蓋了所有檔案類的標籤
    seinfo -afile_type -x |  grep admin_home_t ;
    
  • 回到容器安全上面,到目前為止我們都沒有讓真正的 SELinux 標籤套用到 docker 身上,因為 spc_t 這個標籤感覺權限挺大的。接著來設定 docker 套用 SELinux 設定,步驟如下 :

    1. 新增 /etc/docker/daemon.json 檔案內容如下 :
      {
          "selinux-enabled": true
      }
      
    2. 重啟 docker 服務並且確認是否有套用 selinux
      sudo systemctl restart docker ;
      docker info | grep Security -A3 ;
      
    3. 再建立一樣的普通容器,然後掛載硬碟裝置並且對宿主機進行檔案寫入。
      # 建立一般容器,但是掛載根目錄
      docker run -it --rm -v /:/mnt aeifkz/my-ubuntu:v1.0 bash ; 
      
      # 觀察一下跟剛剛有甚麼差別
      # system_u:system_r:container_t:s0:c818,c852
      ps Z ;
      
      chroot /mnt ;
      
      # 試著寫入 /root 結果失敗
      echo "I am root" > /root/I_am_root ;
      
      # 離開直到回到宿主機
      exit ;
      
      # 沒看到甚麼寫入相關權限,估計是沒辦法做寫入的
      sesearch -s container_t -t admin_home_t --allow -c file ;  
      
      # 找一下 container_t 可以寫入哪種標籤的檔案
      sesearch -s container_t --allow -c file ;  
      
      # 暫時將這個檔案的標籤改成 container_file_t
      sudo chcon -t container_file_t /root/I_am_root ;
      
      # 建立一般容器,但是掛載根目錄
      docker run -it --rm -v /:/mnt aeifkz/my-ubuntu:v1.0 bash ; 
      
      chroot /mnt ;
      
      # 試著寫入 /root ,現在就會成功惹
      echo "I am root" > /root/I_am_root ;
      
      # 離開直到回到宿主機
      exit ;
      
  • 那假如今天真的需要把宿主機的資料夾掛載進來的話要怎麼用呢? 參考 docker selinux-enabled作用可以知道掛載目錄時加上 Z 跟 z 則會調整掛載目錄的標籤內容,使用 Z 則是會在標籤中加上 category,使用 z 則不會加入,這部分決定了 docker 容器內是否可以共享那個資料夾。當然也不是所以的資料夾都可以進行掛載,這部分還是有限制存在的,因為它背後的原理也是幫忙修改掛載目錄的標籤,但在 SELinux 的世界標籤也步是想改就能改的。

        # 建立一般容器,但是掛載根目錄並加上 z,會整個被拒絕
        docker run -it --rm -v /:/mnt:z aeifkz/my-ubuntu:v1.0 bash ;
    
        # 重新建立一個資料夾進行掛載
        mkdir ~/selinux_test ;
        ls -Z ~/ ;
    
        # 改掛載剛剛建立的資料夾,則可以掛載成功
        docker run -it --rm -v ~/selinux_test:/mnt:z aeifkz/my-ubuntu:v1.0 bash ;
    
        # 離開直到回到宿主機
        exit ;
    
        # 會發現該資料夾的標籤被改寫,也就是我們剛剛上個階段在做的事情
        ls -Z ~/ ;
    
  • 最後我們一樣來探討 selinux 實質上提供了甚麼防護呢? 這部分列舉攻擊篇的手法來進行驗證。

攻擊手法 selinux 預設能否阻擋?
privileged + host pid N
--cap-add=ALL + host pid N (作業9)
privileged N
(CVE-2022-0492) unshare + 特權逃逸手法 NA(不適用)
安裝 linux_module Y
docker.sock 掛載 Y
  • 作業9 : 跟當初驗證 Apparmor 機制一樣,但假如給予今天給予容器所有的能力並掛載 host pid,到底是否能夠順利逃逸呢? 假如可以的話,驗證一下為何 SELinux 無法防守住。/images/emoticon/emoticon33.gif

  • 本日總結 :

    • 本日回顧 :
      • SELinux 是一個相當複雜的防禦機制,這邊也只是大概說明它內部的標籤機制以及如何套用到容器防護上面。但還有很多我不知道也沒去研究的東西,像是 setseboolQuick start to write a custom SELinux policy 等等,還有標籤修改的權限機制是怎麼運行的我都還不知道,只能說水真的很深。/images/emoticon/emoticon06.gif
    • 次日預告 :
      • SELinux 的部分就到這邊惹,接下來就開始講比較簡單的防禦機制部分,如何使用 Non-Root User 啟動容器,這部分就相對簡單一些。

上一篇
Day32 - 完賽心得 (含說明大型翻車現場)
下一篇
Day 33 - 作業 9 解答 - 測試 cap-add ALL 以及 host pid 的逃逸手法 (SELinux)
系列文
怕痛的我把 Docker、K8s 攻擊、防禦、偵測力點滿就對了63
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言