Linux Cgroups漏洞可實現容器逃逸

語言: CN / TW / HK

研究人員在Linux kernel中發現一個許可權提升漏洞——CVE-2022-0492,該漏洞存在於Linux kernel 特徵control groups(cgroups)中,漏洞CVSS評分7.0分。攻擊者利用該漏洞可以實現容器逃逸,在容器主機上執行任意命令。

Cgroups是Linux的一個特徵,允許程序進行分層分組,以限制和監控CPU、記憶體、硬碟I/O和網路等資源的使用。Linux支援2種cgroup架構,v1和v2。CVE-2022-0492漏洞影響的是應用最廣泛的cgroup v1。

CVE-2022-0492漏洞根源分析

cgroups v1有一個特徵——release_agent檔案,該檔案允許管理員配置release agent程式,通過寫入目標release agent路徑到release_agent檔案,如下所示:

$ echo /bin/my-release-agent > /sys/fs/cgroup/memory/release_agent

release_agent檔案只可在root cgroup目錄下可見。每個子組(child group)可以通過寫入notify_on_release檔案來重新配置為觸發或不觸發release agent。

$ echo 1 > /sys/fs/cgroup/memory/a_child_cgroup/notify_on_release

程序終止後,kernel會檢查其cgroups是否啟用了notify_on_release,如果啟用了就派生出配置的release_agent二進位制檔案。release agent會以最高的許可權執行。配置release agent是被認為是一個特權操作,允許其決定哪個二進位制檔案可以以完全root許可權來執行。

CVE-2022-0492 漏洞產生的根源是因為沒有進行驗證。Linux並不會檢查設定release_agent 檔案的程序是否有管理許可權。

漏洞利用

因為Linux將release_agent 檔案的所有者設定為root,只有root才可以寫入。因此,該漏洞只允許root程序提升許可權。

並不是每個容器都可以利用CVE-2022-0492 漏洞來實現逃逸,只有具有特定許可權的才可以執行。Cgroup mounts掛載在容器內只讀,所以release_agent 檔案無法寫入。想要利用該漏洞的惡意容器必須要掛載到另一個可寫的cgroupfs。

圖 Cgroupfs掛載在容器內是隻讀的(ro)

AppArmor和SELinux 都可以預防掛載,這表示執行的容器是受保護的。容器掛載cgroupfs的方式有2種:濫用使用者名稱空間或CAP_SYS_ADMIN能力。

預設情況下,容器是沒有CAP_SYS_ADMIM能力的,也無法在初始的使用者名稱空間內掛載cgroupfs。但是通過unshare()系統呼叫,容器就可以建立具有CAP_SYS_ADMIN能力的新的使用者和cgroup 名稱空間,並可以掛載cgroupfs。

圖 容器建立新的具有CAP_SYS_ADMIN能力的使用者名稱空間

也不是每一個容器都可以建立新的使用者名稱空間的,背後的主機必須有啟用非特權的使用者名稱空間。比如,最新的Ubuntu版本就預設啟用了。因為Seccomp 會攔截unshare() 系統呼叫,只有沒有執行Seccomp的容器才能建立新的使用者名稱空間。下圖中的容器就沒有執行Seccomp、AppArmor或SELinux:

圖 容器掛載記憶體cgroup到新使用者和cgroup名稱空間

如上圖所示,容器成功掛載到了記憶體cgroup,但release_agent 檔案並不包含在掛載的目錄中。

release_agent 檔案只有root cgroup才可見。為使release_agent檔案可對cgroup mount可見,容器必須在子系統的root cgroup下執行。

為利用該漏洞,需要將惡意release agent 寫入release_agent 檔案。

圖 設定release agent的root容器

圖 非root容器無法設定release agent

逃逸的最後一步是呼叫配置的release_agent,這一步並不需要任何許可權。

圖 通過使用者名稱空間利用CVE-2022-0492實現容器逃逸

完整技術細節參見: https://unit42.paloaltonetworks.com/cve-2022-0492-cgroups/