上次提到了如何針對程式定義 AppArmor 的限制策略,並且透過工具協助進行策略的放行。那今天則是要來看看這些策略到底可以限制哪些資源,以及相關的編寫定義,最後試著把它套用到容器上面。
AppArmor 策略編寫可以參考 Profile Components and Syntax、What is Apparmor and how to add a security layer with it in Docker? 以及AppArmor security profiles for Docker。
我們這邊先定義一個最基本的框架,留給之後docker的容器載入使用,並且加入註解如下。
#include <tunables/global>
# No template variables specified
# flags 參考 https://documentation.suse.com/sles/15-SP1/html/SLES-all/cha-apparmor-profiles.html#sec-apparmor-profiles-flags
profile my-docker flags=(attach_disconnected,mediate_deleted) {
# ---- 1: include -------
# 檔案位置在 /etc/apparmor.d 底下
#include <abstractions/base>
# ---- 2: capability ----
# ---- 3: network -------
# ---- 4: rlimit --------
# ---- 5: file ----------
}
sudo mkdir -p /etc/apparmor.d/containers/ ;
sudo mv my-docker /etc/apparmor.d/containers/ ;
sudo apparmor_parser -r -W /etc/apparmor.d/containers/my-docker ;
# 這邊會顯示有一個 profiles 叫做 my-docker
sudo aa-status ;
# 此時會發現所有的檔案都無法讀寫
docker run --rm -it --security-opt "apparmor=my-docker" aeifkz/my-ubuntu:v1.0 bash ;
# 會發現能力上的不足
apt update ;
#include <tunables/global>
# No template variables specified
profile my-docker flags=(attach_disconnected,mediate_deleted) {
# ---- 1: include -------
#include <abstractions/base>
# ---- 2: capability ----
# ---- 3: network -------
# ---- 4: rlimit --------
# ---- 5: file ----------
#開放所有檔案的存取
file ,
}
sudo apparmor_parser -r -W /etc/apparmor.d/containers/my-docker ;
# 現在有檔案的讀取權限
docker run --rm -it --security-opt "apparmor=my-docker" aeifkz/my-ubuntu:v1.0 bash ;
# 但依然發現能力上的不足
apt update ;
# 透過 capsh 來看一下目前的 CAP 狀態,觀察 Current: 這個欄位
capsh --print ;
#include <tunables/global>
# No template variables specified
profile my-docker flags=(attach_disconnected,mediate_deleted) {
# ---- 1: include -------
#include <abstractions/base>
# ---- 2: capability ----
capability,
# ---- 3: network -------
network,
# ---- 4: rlimit --------
# ---- 5: file ----------
#開放所有檔案的存取
file ,
}
sudo apparmor_parser -r -W /etc/apparmor.d/containers/my-docker ;
# 現在有檔案的讀取權限
docker run --rm -it --security-opt "apparmor=my-docker" aeifkz/my-ubuntu:v1.0 bash ;
# 有沒有很敢動,終於有勇氣繼續惹
apt update ;
#include <tunables/global>
# No template variables specified
profile my-docker flags=(attach_disconnected,mediate_deleted) {
# ---- 1: include -------
#include <abstractions/base>
# ---- 2: capability ----
capability,
# ---- 3: network -------
network,
# ---- 4: rlimit --------
# ---- 5: file ----------
#開放所有檔案的存取
file ,
# 假設我們禁止 /tmp、/tools 資料夾的讀取及寫入
deny /tmp/** rw ,
deny /tools/** rw ,
# 假設我們禁止用 cat 讀取檔案
deny /usr/bin/cat mrwklx ,
}
sudo apparmor_parser -r -W /etc/apparmor.d/containers/my-docker ;
docker run --rm -it --security-opt "apparmor=my-docker" aeifkz/my-ubuntu:v1.0 bash ;
# 此時會發現所有檔案都可以讀寫,除了 /tmp 底下之外
echo aaa > aaa ;
# 測試 cat 指令及特性
cat aaa ; # 出現 Permission denied,試圖改資料夾名稱也沒救
# 對兩個資料夾進行寫入測試
touch /tmp/test ;
touch /tools/test ;
# 試著更名繞過
mv /tmp /tmp123 ;
mv /tools /tools_123 ;
# 在對資料夾做新增檔案試試
touch /tmp123/test ;
# 還原資料夾名稱
mv /tmp123 /tmp ;
touch /tmp/new_test ;
透過上面的範例會發現當對空的資料夾進行禁止條件讀取跟寫入的時候可以被更名給繞過,這部分我也不知道原因,就只是剛好有測到而已,不過實務要限制一個空的資料夾的情境應該不會太多,就當作一個奇特的特性就好了(雖然說這個特性害我花了不少時間Debug)。
至於要繞過限制 cat 的部分就比較特別一點,需要利用到shebang,可以參考如何繞過 AppArmor。
echo '#!/bin/cat' > read_file.sh ;
chmod +x read_file.sh ;
./read_file.sh 檔案名稱 ;
至於想知道 docker 套用了甚麼設定的話,可以參考這篇 Where is docker's apparmor profile? 以及這篇 Apparmor in Docker 還有 AppArmor security profiles for Docker 以及 moby/contrib/apparmor。
docker-default profile Summary:
最後我們一樣來探討 AppArmor 實質上提供了甚麼防護呢? 這部分列舉攻擊篇的手法來進行驗證。
攻擊手法 | AppArmor 預設能否阻擋? |
---|---|
privileged + host pid | N |
--cap-add=ALL + host pid | Y (作業8) |
privileged | N |
(CVE-2022-0492) unshare + cgroup 特權逃逸手法 | N |
安裝 linux_module | N |
docker.sock 掛載 | N |
從上表各位會覺得好像預設能阻擋的攻擊手法並不多,這是因為 apparmor 的設定檔案還是以黑名單為主,所以名單的設定會相對嚴謹。而且比較直覺可以限制的部分通常會是檔案系統上的讀寫限制,這部分在應對逃逸手法上就顯的相對乏力。但如果是預防網頁竄改這樣的攻擊,應該就會相對有利一些。
但 AppArmor 的缺點在於很難建立出一個完整通用的預設白名單出來,因為除了 capability、network、file 之外,還有其他類型的資源開放例如 mount、pivot_root、ptrace、signal 等,再加上無法引入 docker-default 進行疊加的情況下,要做出白名單的確有些難度。
作業8 : 我們都知道開啟特權容器會關閉 Seccomp、Apparmor 等相關機制,造成無法測試掛載 host pid 的逃逸手法,但假如給予今天給予容器所有的能力並掛載 host pid,到底是否能夠順利逃逸呢? 假如不行的話,驗證一下是不是 Apparmor 搞的鬼。
今日總結 :